diff --git a/.github/actions/spelling/expect.txt b/.github/actions/spelling/expect.txt index dbf81dd8..6142f860 100644 --- a/.github/actions/spelling/expect.txt +++ b/.github/actions/spelling/expect.txt @@ -3,6 +3,7 @@ AAFFBB aarch abe addrpair +advapi almalinux ATL ATLMFC @@ -40,6 +41,7 @@ collectguestlogs commandline comspec consoleloggerparameters +covrec CPlat cplusplus cpptools @@ -87,7 +89,9 @@ etest etestoutputs etestsharedstorage EToken +etw EUID +EVENTLOG evt exampledatadiskname exampleosdiskname @@ -157,7 +161,7 @@ logdir Loggerhas logon Lrs -Lsa +lsa ltsc luid macikgo @@ -218,6 +222,7 @@ RDFE redhat Redist refcnt +registereventsourcew registrykey relativeurl resf @@ -324,8 +329,10 @@ wdk wdksetup Werror westus +wevtapi WFP winapi +winbase windowsazureguestagent winget winmgmts diff --git a/Cargo.lock b/Cargo.lock index 906565d5..80e2d820 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,7 +4,7 @@ version = 4 [[package]] name = "ProxyAgentExt" -version = "1.0.31" +version = "1.0.32" dependencies = [ "clap", "ctor", @@ -63,6 +63,21 @@ version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f" +[[package]] +name = "android-tzdata" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + [[package]] name = "anstream" version = "0.6.15" @@ -99,7 +114,7 @@ version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6d36fc52c7f6c869915e99412912f22093507da8d9e942ceaf66fe4b7c14422a" dependencies = [ - "windows-sys 0.52.0", + "windows-sys", ] [[package]] @@ -109,7 +124,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5bf74e1b6e971609db8ca7a9ce79fd5768ab6ae46441c572e46cf596f59e57f8" dependencies = [ "anstyle", - "windows-sys 0.52.0", + "windows-sys", ] [[package]] @@ -157,7 +172,7 @@ dependencies = [ [[package]] name = "azure-proxy-agent" -version = "1.0.31" +version = "1.0.32" dependencies = [ "aya", "bitflags", @@ -192,7 +207,7 @@ dependencies = [ "winapi", "windows-acl", "windows-service", - "windows-sys 0.42.0", + "windows-sys", "winres", ] @@ -217,6 +232,12 @@ version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" +[[package]] +name = "bumpalo" +version = "3.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793db76d6187cd04dff33004d8e6c9cc4e05cd330500379d2394209271b4aeee" + [[package]] name = "byteorder" version = "1.5.0" @@ -229,6 +250,15 @@ version = "1.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8318a53db07bb3f8dca91a600466bdb3f2eaadeedfdbcf02e1accbad9271ba50" +[[package]] +name = "cc" +version = "1.2.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d487aa071b5f64da6f19a3e848e3578944b726ee5a4854b82172f02aa876bfdc" +dependencies = [ + "shlex", +] + [[package]] name = "cfg-if" version = "1.0.0" @@ -241,6 +271,20 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" +[[package]] +name = "chrono" +version = "0.4.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c469d952047f47f91b68d1cba3f10d63c11d73e4636f24f08daf0278abf01c4d" +dependencies = [ + "android-tzdata", + "iana-time-zone", + "js-sys", + "num-traits", + "wasm-bindgen", + "windows-link", +] + [[package]] name = "clap" version = "4.5.18" @@ -594,6 +638,30 @@ dependencies = [ "tokio", ] +[[package]] +name = "iana-time-zone" +version = "0.1.63" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0c919e5debc312ad217002b8048a17b7d83f80703865bbfcfebb0458b0b27d8" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "log", + "wasm-bindgen", + "windows-core 0.61.2", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + [[package]] name = "indexmap" version = "2.7.1" @@ -625,6 +693,16 @@ version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" +[[package]] +name = "js-sys" +version = "0.3.77" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" +dependencies = [ + "once_cell", + "wasm-bindgen", +] + [[package]] name = "libc" version = "0.2.171" @@ -680,7 +758,7 @@ dependencies = [ "hermit-abi", "libc", "wasi", - "windows-sys 0.52.0", + "windows-sys", ] [[package]] @@ -746,7 +824,7 @@ checksum = "ae99c7fa6dd38c7cafe1ec085e804f8f555a2f8659b0dbe03f1f9963a9b51092" dependencies = [ "log", "serde", - "windows-sys 0.52.0", + "windows-sys", ] [[package]] @@ -787,7 +865,7 @@ dependencies = [ [[package]] name = "proxy_agent_setup" -version = "1.0.31" +version = "1.0.32" dependencies = [ "clap", "proxy_agent_shared", @@ -799,8 +877,10 @@ dependencies = [ [[package]] name = "proxy_agent_shared" -version = "1.0.31" +version = "1.0.32" dependencies = [ + "backtrace", + "chrono", "concurrent-queue", "ctor", "log", @@ -808,6 +888,7 @@ dependencies = [ "os_info", "regex", "serde", + "serde-xml-rs", "serde_derive", "serde_json", "thiserror", @@ -815,7 +896,7 @@ dependencies = [ "time", "tokio", "windows-service", - "windows-sys 0.42.0", + "windows-sys", "winreg", ] @@ -922,6 +1003,12 @@ dependencies = [ "semver", ] +[[package]] +name = "rustversion" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a0d197bd2c9dc6e53b84da9556a69ba4cdfab8619eb41a8bd1cc2027a0f6b1d" + [[package]] name = "ryu" version = "1.0.18" @@ -945,9 +1032,9 @@ dependencies = [ [[package]] name = "serde-xml-rs" -version = "0.6.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb3aa78ecda1ebc9ec9847d5d3aba7d618823446a049ba2491940506da6e2782" +checksum = "53630160a98edebde0123eb4dfd0fce6adff091b2305db3154a9e920206eb510" dependencies = [ "log", "serde", @@ -978,6 +1065,12 @@ dependencies = [ "serde", ] +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + [[package]] name = "slab" version = "0.4.9" @@ -1000,7 +1093,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" dependencies = [ "libc", - "windows-sys 0.52.0", + "windows-sys", ] [[package]] @@ -1120,7 +1213,7 @@ dependencies = [ "pin-project-lite", "socket2", "tokio-macros", - "windows-sys 0.52.0", + "windows-sys", ] [[package]] @@ -1294,6 +1387,64 @@ version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +[[package]] +name = "wasm-bindgen" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" +dependencies = [ + "bumpalo", + "log", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" +dependencies = [ + "unicode-ident", +] + [[package]] name = "widestring" version = "0.4.3" @@ -1334,7 +1485,7 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e48a53791691ab099e5e2ad123536d0fff50652600abaf43bbf952894110d0be" dependencies = [ - "windows-core", + "windows-core 0.52.0", "windows-targets", ] @@ -1359,6 +1510,56 @@ dependencies = [ "windows-targets", ] +[[package]] +name = "windows-core" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3" +dependencies = [ + "windows-implement", + "windows-interface", + "windows-link", + "windows-result", + "windows-strings", +] + +[[package]] +name = "windows-implement" +version = "0.60.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "windows-interface" +version = "0.59.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "windows-link" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" + +[[package]] +name = "windows-result" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6" +dependencies = [ + "windows-link", +] + [[package]] name = "windows-service" version = "0.7.0" @@ -1367,22 +1568,16 @@ checksum = "d24d6bcc7f734a4091ecf8d7a64c5f7d7066f45585c1861eba06449909609c8a" dependencies = [ "bitflags", "widestring 1.1.0", - "windows-sys 0.52.0", + "windows-sys", ] [[package]] -name = "windows-sys" -version = "0.42.0" +name = "windows-strings" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" +checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57" dependencies = [ - "windows_aarch64_gnullvm 0.42.2", - "windows_aarch64_msvc 0.42.2", - "windows_i686_gnu 0.42.2", - "windows_i686_msvc 0.42.2", - "windows_x86_64_gnu 0.42.2", - "windows_x86_64_gnullvm 0.42.2", - "windows_x86_64_msvc 0.42.2", + "windows-link", ] [[package]] @@ -1400,46 +1595,28 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ - "windows_aarch64_gnullvm 0.52.6", - "windows_aarch64_msvc 0.52.6", - "windows_i686_gnu 0.52.6", + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", "windows_i686_gnullvm", - "windows_i686_msvc 0.52.6", - "windows_x86_64_gnu 0.52.6", - "windows_x86_64_gnullvm 0.52.6", - "windows_x86_64_msvc 0.52.6", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", ] -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" - [[package]] name = "windows_aarch64_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" -[[package]] -name = "windows_aarch64_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" - [[package]] name = "windows_aarch64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" -[[package]] -name = "windows_i686_gnu" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" - [[package]] name = "windows_i686_gnu" version = "0.52.6" @@ -1452,48 +1629,24 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" -[[package]] -name = "windows_i686_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" - [[package]] name = "windows_i686_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" -[[package]] -name = "windows_x86_64_gnu" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" - [[package]] name = "windows_x86_64_gnu" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" - [[package]] name = "windows_x86_64_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" -[[package]] -name = "windows_x86_64_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" - [[package]] name = "windows_x86_64_msvc" version = "0.52.6" diff --git a/cargo-clippy.cmd b/cargo-clippy.cmd new file mode 100644 index 00000000..d5a88cac --- /dev/null +++ b/cargo-clippy.cmd @@ -0,0 +1,24 @@ +REM Copyright (c) Microsoft Corporation +REM SPDX-License-Identifier: MIT + +@echo off + +REM This script is used to set the default toolchain for the current directory and run cargo clippy and cargo fmt. + +echo ======= rustup default stable +echo rustup update stable +rustup update stable +echo rustup override unset +rustup override unset + +echo ======= cargo fmt and clippy +echo call rustup component add rustfmt clippy +call rustup component add rustfmt clippy +echo call cargo fmt --all +cargo fmt --all +echo call cargo clippy -- -D warnings +cargo clippy -- -D warnings +if %ERRORLEVEL% NEQ 0 ( + echo cargo clippy failed with exit-code: %errorlevel% + exit /b %errorlevel% +) diff --git a/cargo-clippy.sh b/cargo-clippy.sh new file mode 100755 index 00000000..a4fed8c3 --- /dev/null +++ b/cargo-clippy.sh @@ -0,0 +1,26 @@ +#!/bin/bash + +# Copyright (c) Microsoft Corporation +# SPDX-License-Identifier: MIT + +# Prints then runs the command based on: https://stackoverflow.com/questions/31656645/how-do-i-echo-directly-on-standard-output-inside-a-shell-function +runthis(){ + echo "$@" + ## Run the command and redirect its error output + "$@" >&2 +} + +# This script is used to set the default toolchain for the current directory and run cargo clippy and cargo fmt. +rustup update stable +rustup override unset + +echo "======= cargo fmt & clippy" +runthis rustup component add rustfmt clippy +runthis cargo fmt --all +runthis cargo clippy -- -D warnings +error_code=$? +if [ $error_code -ne 0 ] +then + echo "cargo clippy with exit-code: $error_code" + exit $error_code +fi \ No newline at end of file diff --git a/e2etest/GuestProxyAgentTest/Resources/GuestProxyAgentLoadedModulesBaseline.txt b/e2etest/GuestProxyAgentTest/Resources/GuestProxyAgentLoadedModulesBaseline.txt index 32d1b5d5..0b7e8fc0 100644 --- a/e2etest/GuestProxyAgentTest/Resources/GuestProxyAgentLoadedModulesBaseline.txt +++ b/e2etest/GuestProxyAgentTest/Resources/GuestProxyAgentLoadedModulesBaseline.txt @@ -34,4 +34,9 @@ SAMLIB.dll WLDAP32.dll crypt32.dll msasn1.dll -version.dll \ No newline at end of file +version.dll +combase.dll +oleaut32.dll +msvcp_win.dll +symsrv.dll +shlwapi.dll \ No newline at end of file diff --git a/proxy_agent/Cargo.toml b/proxy_agent/Cargo.toml index 112f32fd..e0585635 100644 --- a/proxy_agent/Cargo.toml +++ b/proxy_agent/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "azure-proxy-agent" -version = "1.0.31" # always 3-number version +version = "1.0.32" # always 3-number version edition = "2021" build = "build.rs" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html @@ -12,11 +12,11 @@ once_cell = "1.17.0" # use Lazy serde = "1.0.152" serde_derive = "1.0.152" serde_json = "1.0.91" # json Deserializer -serde-xml-rs = "0.6.0" # xml Deserializer +serde-xml-rs = "0.8.1" # xml Deserializer with xml attribute bitflags = "2.6.0" # support bitflag enum hmac-sha256 = "1.1.6" # use HMAC using the SHA-256 hash function hex = "0.4.3" # hex encode -regex = "1.11" # match process name in cmdline +regex = "1.11" # match process name in cmdline tokio = { version = "1", features = ["rt", "rt-multi-thread", "time", "net", "macros", "sync"] } tokio-util = "0.7.11" http = "1.1.0" @@ -62,8 +62,10 @@ winres = "0.1.12" # Rust Windows resource helper to add file version static_vcruntime = "2.0.0" # Statically link the VCRuntime when using the MSVC toolchain [target.'cfg(windows)'.dependencies.windows-sys] -version = "0.42.0" +version = "0.52.0" features = [ + "Wdk_Foundation", + "Wdk_System_Threading", "Win32_Foundation", "Win32_Networking_WinSock", "Win32_System_IO", @@ -76,7 +78,7 @@ features = [ "Win32_System_ProcessStatus", "Win32_System_Kernel", "Win32_Security_Cryptography", - "Win32_System_Memory", + "Win32_System_Memory" ] [features] diff --git a/proxy_agent/config/GuestProxyAgent.linux.json b/proxy_agent/config/GuestProxyAgent.linux.json index 32c35ae9..74fce03f 100644 --- a/proxy_agent/config/GuestProxyAgent.linux.json +++ b/proxy_agent/config/GuestProxyAgent.linux.json @@ -7,5 +7,7 @@ "hostGAPluginSupport": 1, "ebpfProgramName": "ebpf_cgroup.o", "cgroupRoot": "/sys/fs/cgroup", - "fileLogLevel": "Info" + "fileLogLevel": "Info", + "fileLogLevelForEvents": "Info", + "fileLogLevelForSystemEvents": "Info" } \ No newline at end of file diff --git a/proxy_agent/config/GuestProxyAgent.windows.json b/proxy_agent/config/GuestProxyAgent.windows.json index caa47c27..c1ea059c 100644 --- a/proxy_agent/config/GuestProxyAgent.windows.json +++ b/proxy_agent/config/GuestProxyAgent.windows.json @@ -6,5 +6,7 @@ "pollKeyStatusIntervalInSeconds": 15, "hostGAPluginSupport": 1, "ebpfProgramName": "redirect.bpf.sys", - "fileLogLevel": "Info" + "fileLogLevel": "Info", + "fileLogLevelForEvents": "Info", + "fileLogLevelForSystemEvents": "Info" } \ No newline at end of file diff --git a/proxy_agent/src/acl/linux_acl.rs b/proxy_agent/src/acl/linux_acl.rs index d49440f3..d588c3d9 100644 --- a/proxy_agent/src/acl/linux_acl.rs +++ b/proxy_agent/src/acl/linux_acl.rs @@ -10,19 +10,16 @@ use std::path::PathBuf; pub fn acl_directory(dir_to_acl: PathBuf) -> Result<()> { let dir_str = misc_helpers::path_to_string(&dir_to_acl); logger::write(format!( - "acl_directory: start to set root-only permission to folder {}.", - dir_str + "acl_directory: start to set root-only permission to folder {dir_str}." )); match chown(&dir_to_acl, Some(Uid::from_raw(0)), Some(Gid::from_raw(0))) { Ok(_) => logger::write(format!( - "acl_directory: successfully set root-only permission to folder {}.", - dir_str + "acl_directory: successfully set root-only permission to folder {dir_str}." )), Err(e) => { logger::write(format!( - "acl_directory: failed to set root-only permission to folder {}. Error: {:?}", - dir_str, e + "acl_directory: failed to set root-only permission to folder {dir_str}. Error: {e:?}" )); } } @@ -31,13 +28,11 @@ pub fn acl_directory(dir_to_acl: PathBuf) -> Result<()> { let permissions = fs::Permissions::from_mode(0o700); match fs::set_permissions(dir_to_acl, permissions) { Ok(_) => logger::write(format!( - "acl_directory: successfully set root-only permission to folder {}.", - dir_str + "acl_directory: successfully set root-only permission to folder {dir_str}." )), Err(e) => { logger::write(format!( - "acl_directory: failed to set root-only permission to folder {}. Error: {:?}", - dir_str, e + "acl_directory: failed to set root-only permission to folder {dir_str}. Error: {e:?}" )); } } diff --git a/proxy_agent/src/acl/windows_acl.rs b/proxy_agent/src/acl/windows_acl.rs index 532a2893..eb63a896 100644 --- a/proxy_agent/src/acl/windows_acl.rs +++ b/proxy_agent/src/acl/windows_acl.rs @@ -31,16 +31,14 @@ pub fn acl_directory(dir_to_acl: PathBuf) -> Result<()> { .map_err(|e| Error::Acl(AclErrorType::Sid(BUILDIN_ADMIN_SID.to_string()), e))?; logger::write(format!( - "acl_directory: removing all the remaining access rules for folder {}.", - dir_str + "acl_directory: removing all the remaining access rules for folder {dir_str}." )); match acl.all() { Ok(entries) => { logger::write(format!( - "acl_directory: get '{}' access rules for folder {}.", - entries.len(), - dir_str + "acl_directory: get '{len}' access rules for folder {dir_str}.", + len = entries.len() )); for entry in entries { match entry.sid { @@ -55,12 +53,11 @@ pub fn acl_directory(dir_to_acl: PathBuf) -> Result<()> { None, // remove all, including inherited permissions ) { Ok(r) => { - logger::write(format!("acl_directory: removed '{}' entry.", r)); + logger::write(format!("acl_directory: removed '{r}' entry.")); } Err(e) => { logger::write_warning(format!( - "acl_directory: remove_entry failed with error '{}' entry.", - e + "acl_directory: remove_entry failed with error '{e}' entry.", )); } } @@ -77,8 +74,7 @@ pub fn acl_directory(dir_to_acl: PathBuf) -> Result<()> { } logger::write(format!( - "acl_directory: Adding new access rules for the target directory {}.", - dir_str + "acl_directory: Adding new access rules for the target directory {dir_str}." )); let flags = (CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE) as u8; let mask = FULL_CONTROL; @@ -90,8 +86,7 @@ pub fn acl_directory(dir_to_acl: PathBuf) -> Result<()> { ) { Ok(r) => { logger::write(format!( - "acl_directory: Adding new access rules for sid {} with result {}.", - LOCAL_SYSTEM_SID, r + "acl_directory: Adding new access rules for sid {LOCAL_SYSTEM_SID} with result {r}.", )); } Err(e) => { @@ -109,8 +104,7 @@ pub fn acl_directory(dir_to_acl: PathBuf) -> Result<()> { ) { Ok(r) => { logger::write(format!( - "acl_directory: Adding new access rules for sid {} with result {}.", - BUILDIN_ADMIN_SID, r + "acl_directory: Adding new access rules for sid {BUILDIN_ADMIN_SID} with result {r}." )); } Err(e) => { diff --git a/proxy_agent/src/common/config.rs b/proxy_agent/src/common/config.rs index b5a52200..cf2df59b 100644 --- a/proxy_agent/src/common/config.rs +++ b/proxy_agent/src/common/config.rs @@ -70,6 +70,14 @@ pub fn get_file_log_level() -> LoggerLevel { SYSTEM_CONFIG.get_file_log_level() } +pub fn get_file_log_level_for_events() -> Option { + SYSTEM_CONFIG.get_file_log_level_for_events() +} + +pub fn get_file_log_level_for_system_events() -> Option { + SYSTEM_CONFIG.get_file_log_level_for_system_events() +} + #[derive(Serialize, Deserialize)] #[allow(non_snake_case)] pub struct Config { @@ -89,6 +97,10 @@ pub struct Config { #[serde(skip_serializing_if = "Option::is_none")] #[cfg(not(windows))] cgroupRoot: Option, + #[serde(skip_serializing_if = "Option::is_none")] + fileLogLevelForEvents: Option, + #[serde(skip_serializing_if = "Option::is_none")] + fileLogLevelForSystemEvents: Option, } impl Default for Config { @@ -179,6 +191,22 @@ impl Config { None => PathBuf::from(constants::CGROUP_ROOT), } } + + pub fn get_file_log_level_for_events(&self) -> Option { + if let Some(file_log_level) = &self.fileLogLevelForEvents { + let log_level = LoggerLevel::from_str(file_log_level).unwrap_or(LoggerLevel::Info); + return Some(log_level); + } + None + } + + pub fn get_file_log_level_for_system_events(&self) -> Option { + if let Some(file_log_level) = &self.fileLogLevelForSystemEvents { + let log_level = LoggerLevel::from_str(file_log_level).unwrap_or(LoggerLevel::Info); + return Some(log_level); + } + None + } } #[cfg(test)] @@ -260,6 +288,18 @@ mod tests { ); } + assert_eq!( + proxy_agent_shared::logger::LoggerLevel::Info, + config.get_file_log_level_for_events().unwrap(), + "get_file_log_level_for_events mismatch" + ); + + assert_eq!( + proxy_agent_shared::logger::LoggerLevel::Info, + config.get_file_log_level_for_system_events().unwrap(), + "get_file_log_level_for_system_events mismatch" + ); + // clean up _ = fs::remove_dir_all(&temp_test_path); } @@ -275,7 +315,9 @@ mod tests { "wireServerSupport": 2, "hostGAPluginSupport": 1, "imdsSupport": 1, - "ebpfProgramName": "ebpfProgramName" + "ebpfProgramName": "ebpfProgramName", + "fileLogLevelForEvents": "Info", + "fileLogLevelForSystemEvents": "Info" }"# } else { r#"{ @@ -287,7 +329,9 @@ mod tests { "wireServerSupport": 2, "hostGAPluginSupport": 1, "imdsSupport": 1, - "ebpfProgramName": "ebpfProgramName" + "ebpfProgramName": "ebpfProgramName", + "fileLogLevelForEvents": "Info", + "fileLogLevelForSystemEvents": "Info" }"# }; diff --git a/proxy_agent/src/common/constants.rs b/proxy_agent/src/common/constants.rs index 230f6aa3..19824849 100644 --- a/proxy_agent/src/common/constants.rs +++ b/proxy_agent/src/common/constants.rs @@ -7,6 +7,7 @@ pub const GA_PLUGIN_PORT: u16 = 32526u16; pub const IMDS_IP: &str = "169.254.169.254"; pub const IMDS_PORT: u16 = 80u16; +pub const WINDOWS_AZURE: &str = "Windows Azure"; pub const PROXY_AGENT_SERVICE_NAME: &str = "GuestProxyAgent"; pub const PROXY_AGENT_IP: &str = "127.0.0.1"; pub const PROXY_AGENT_PORT: u16 = 3080; diff --git a/proxy_agent/src/common/helpers.rs b/proxy_agent/src/common/helpers.rs index c945e9ea..112c957a 100644 --- a/proxy_agent/src/common/helpers.rs +++ b/proxy_agent/src/common/helpers.rs @@ -18,7 +18,7 @@ static CURRENT_SYS_INFO: Lazy<(u64, usize)> = Lazy::new(|| { let ram_in_mb = match windows::get_memory_in_mb() { Ok(ram) => ram, Err(e) => { - logger::write_error(format!("get_memory_in_mb failed: {}", e)); + logger::write_error(format!("get_memory_in_mb failed: {e}")); 0 } }; diff --git a/proxy_agent/src/common/hyper_client.rs b/proxy_agent/src/common/hyper_client.rs index 9eea2cbc..bc52c375 100644 --- a/proxy_agent/src/common/hyper_client.rs +++ b/proxy_agent/src/common/hyper_client.rs @@ -166,8 +166,7 @@ where Err(e) => Err(Error::Hyper( HyperErrorType::Deserialize( format!( - "Failed to xml deserialize response body with content_type {} from: {} with error {}", - content_type, body_string, e + "Failed to xml deserialize response body with content_type {content_type} from: {body_string} with error {e}" ) ), )), @@ -178,8 +177,7 @@ where Err(e) => Err(Error::Hyper( HyperErrorType::Deserialize( format!( - "Failed to json deserialize response body with {} from: {} with error {}", - content_type, body_string, e + "Failed to json deserialize response body with {content_type} from: {body_string} with error {e}" ) ), )), @@ -246,8 +244,7 @@ pub fn build_request( match request_builder.body(boxed_body) { Ok(r) => Ok(r), Err(e) => Err(Error::Hyper(HyperErrorType::RequestBuilder(format!( - "Failed to build request body: {}", - e + "Failed to build request body: {e}" )))), } } @@ -268,7 +265,7 @@ where let mut sender = build_http_sender(host, port, log_fun).await?; sender.send_request(request).await.map_err(|e| { Error::Hyper(HyperErrorType::Custom( - format!("Failed to send request to {}", full_url), + format!("Failed to send request to {full_url}"), e, )) }) @@ -285,12 +282,12 @@ where B::Error: Into>, F: FnMut(String) + Send + 'static, { - let addr = format!("{}:{}", host, port); + let addr = format!("{host}:{port}"); let stream = match TcpStream::connect(addr.to_string()).await { Ok(tcp_stream) => tcp_stream, Err(e) => { return Err(Error::Io( - format!("Failed to open TCP connection to {}", addr), + format!("Failed to open TCP connection to {addr}"), e, )) } @@ -301,13 +298,13 @@ where .await .map_err(|e| { Error::Hyper(HyperErrorType::Custom( - format!("Failed to establish connection to {}", addr), + format!("Failed to establish connection to {addr}"), e, )) })?; tokio::task::spawn(async move { if let Err(err) = conn.await { - log_fun(format!("Connection failed: {:?}", err)); + log_fun(format!("Connection failed: {err:?}")); } }); @@ -428,7 +425,7 @@ fn get_path_and_canonicalized_parameters(url: &Uri) -> (String, String) { pairs.insert( // add the query parameter value for sorting, // just in case of duplicate keys by value lexicographically in ascending order. - format!("{}{}", key, value), + format!("{key}{value}"), (key.to_lowercase(), value.to_string()), ); } diff --git a/proxy_agent/src/common/logger.rs b/proxy_agent/src/common/logger.rs index 155b8bb0..a3e06819 100644 --- a/proxy_agent/src/common/logger.rs +++ b/proxy_agent/src/common/logger.rs @@ -1,11 +1,12 @@ // Copyright (c) Microsoft Corporation // SPDX-License-Identifier: MIT -use crate::common::cli; use proxy_agent_shared::{ logger::{logger_manager, LoggerLevel}, - misc_helpers, + telemetry::event_logger, }; +use super::config; + pub const AGENT_LOGGER_KEY: &str = "Agent_Logger"; pub fn write(message: String) { @@ -25,22 +26,21 @@ pub fn write_error(message: String) { } fn log(log_level: LoggerLevel, message: String) { - if log_level != LoggerLevel::Trace { - write_console_log(message.to_string()); - }; - logger_manager::log(AGENT_LOGGER_KEY.to_string(), log_level, message); -} - -pub fn write_console_log(message: String) { - if cli::CLI.is_console_mode() { - println!( - "{} {}", - misc_helpers::get_date_time_string_with_milliseconds(), - message - ); - } else { - println!("{}", message); + if let Some(log_for_event) = config::get_file_log_level_for_events() { + if log_for_event >= log_level { + // write to event + let (module_name, caller_name) = + proxy_agent_shared::logger::get_caller_info("proxy_agent::common::logger"); + event_logger::write_event_only( + log_level, + message.to_string(), + &caller_name, + &module_name, + ); + } } + + logger_manager::log(AGENT_LOGGER_KEY.to_string(), log_level, message); } #[cfg(not(windows))] @@ -64,11 +64,11 @@ pub fn write_serial_console_log(message: String) { { Ok(mut serial_console) => { if serial_console.write_all(message.as_bytes()).is_err() { - eprintln!("Failed to write to serial console: {}", message); + eprintln!("Failed to write to serial console: {message}"); } } Err(e) => { - eprintln!("Failed to open serial console: {}", e); + eprintln!("Failed to open serial console: {e}"); } } } diff --git a/proxy_agent/src/common/windows.rs b/proxy_agent/src/common/windows.rs index a6f34c9e..5513695e 100644 --- a/proxy_agent/src/common/windows.rs +++ b/proxy_agent/src/common/windows.rs @@ -12,7 +12,7 @@ use windows_sys::Win32::Security::Cryptography::{ // msasn1.dll (ASN.1 library) is also used by crypt32.dll CryptProtectData, CryptUnprotectData, - CRYPTOAPI_BLOB, + CRYPT_INTEGER_BLOB, }; use windows_sys::Win32::System::SystemInformation::{ GetSystemInfo, // kernel32.dll @@ -46,11 +46,11 @@ pub fn get_memory_in_mb() -> Result { pub fn store_key_data(encrypted_file_path: &Path, key_data: String) -> Result<()> { let data = key_data.as_bytes(); - let data_in = CRYPTOAPI_BLOB { + let data_in = CRYPT_INTEGER_BLOB { cbData: data.len() as u32, pbData: data.as_ptr() as *mut u8, }; - let mut data_out = CRYPTOAPI_BLOB { + let mut data_out = CRYPT_INTEGER_BLOB { cbData: 0, pbData: std::ptr::null_mut(), }; @@ -73,7 +73,9 @@ pub fn store_key_data(encrypted_file_path: &Path, key_data: String) -> Result<() let encrypted_data = unsafe { std::slice::from_raw_parts(data_out.pbData, data_out.cbData as usize).to_vec() }; - unsafe { windows_sys::Win32::System::Memory::LocalFree(data_out.pbData as isize) }; + unsafe { + windows_sys::Win32::Foundation::LocalFree(data_out.pbData as *mut ::core::ffi::c_void) + }; std::fs::write(encrypted_file_path, encrypted_data).map_err(|e| { Error::Io( format!( @@ -97,11 +99,11 @@ pub fn fetch_key_data(encrypted_file_path: &Path) -> Result { e, ) })?; - let data_in = CRYPTOAPI_BLOB { + let data_in = CRYPT_INTEGER_BLOB { cbData: encrypted_data.len() as u32, pbData: encrypted_data.as_ptr() as *mut u8, }; - let mut data_out = CRYPTOAPI_BLOB { + let mut data_out = CRYPT_INTEGER_BLOB { cbData: 0, pbData: std::ptr::null_mut(), }; @@ -125,7 +127,9 @@ pub fn fetch_key_data(encrypted_file_path: &Path) -> Result { let decrypted_data = unsafe { std::slice::from_raw_parts(data_out.pbData as *const u8, data_out.cbData as usize).to_vec() }; - unsafe { windows_sys::Win32::System::Memory::LocalFree(data_out.pbData as isize) }; + unsafe { + windows_sys::Win32::Foundation::LocalFree(data_out.pbData as *mut ::core::ffi::c_void) + }; let key_data = String::from_utf8_lossy(&decrypted_data).to_string(); Ok(key_data) diff --git a/proxy_agent/src/host_clients/goal_state.rs b/proxy_agent/src/host_clients/goal_state.rs index d1e6a179..69c3b7e2 100644 --- a/proxy_agent/src/host_clients/goal_state.rs +++ b/proxy_agent/src/host_clients/goal_state.rs @@ -89,15 +89,20 @@ pub struct SharedConfig { #[derive(Deserialize, Serialize, PartialEq)] #[allow(non_snake_case)] struct DeploymentField { + #[serde(rename = "@name")] name: String, + #[serde(rename = "@guid")] guid: String, + #[serde(rename = "@incarnation")] incarnation: String, } #[derive(Deserialize, Serialize, PartialEq)] #[allow(non_snake_case)] struct RoleField { + #[serde(rename = "@guid")] guid: String, + #[serde(rename = "@name")] name: String, } @@ -110,7 +115,9 @@ struct InstancesField { #[derive(Deserialize, Serialize, PartialEq)] #[allow(non_snake_case)] struct SharedConfigInstance { + #[serde(rename = "@id")] id: String, + #[serde(rename = "@address")] address: String, } diff --git a/proxy_agent/src/host_clients/wire_server_client.rs b/proxy_agent/src/host_clients/wire_server_client.rs index 252b1a7f..ced98348 100644 --- a/proxy_agent/src/host_clients/wire_server_client.rs +++ b/proxy_agent/src/host_clients/wire_server_client.rs @@ -82,7 +82,7 @@ impl WireServerClient { Err(e) => { return Err(Error::WireServer( WireServerErrorType::Telemetry, - format!("Failed to send request {}", e), + format!("Failed to send request {e}"), )) } }; @@ -91,10 +91,7 @@ impl WireServerClient { if !status.is_success() { return Err(Error::WireServer( WireServerErrorType::Telemetry, - format!( - "Failed to get response from {}, status code: {}", - url, status - ), + format!("Failed to get response from {url}, status code: {status}"), )); } diff --git a/proxy_agent/src/key_keeper.rs b/proxy_agent/src/key_keeper.rs index 11d939df..81e5b177 100644 --- a/proxy_agent/src/key_keeper.rs +++ b/proxy_agent/src/key_keeper.rs @@ -175,7 +175,7 @@ impl KeyKeeper { let notify = match self.key_keeper_shared_state.get_notify().await { Ok(notify) => notify, Err(e) => { - logger::write_error(format!("Failed to get notify: {}", e)); + logger::write_error(format!("Failed to get notify: {e}")); return; } }; @@ -187,8 +187,7 @@ impl KeyKeeper { .await { logger::write_error(format!( - "Failed to set key_keeper module state to 'Running' with error: {} ", - e + "Failed to set key_keeper module state to 'Running' with error: {e} " )); } @@ -205,8 +204,7 @@ impl KeyKeeper { Ok(state) => state, Err(e) => { logger::write_warning(format!( - "Failed to get current secure channel state: {}", - e + "Failed to get current secure channel state: {e}" )); UNKNOWN_STATE.to_string() } @@ -229,10 +227,10 @@ impl KeyKeeper { // this is to handle quicker response to the secure channel state change during VM provisioning. _ = notify.notified() => { if current_state == DISABLE_STATE || current_state == UNKNOWN_STATE { - logger::write_warning(format!("poll_secure_channel_status task notified and secure channel state is '{}', reset states and start poll status now.", current_state)); + logger::write_warning(format!("poll_secure_channel_status task notified and secure channel state is '{current_state}', reset states and start poll status now.")); provision::key_latch_ready_state_reset(self.provision_shared_state.clone()).await; if let Err(e) = self.key_keeper_shared_state.update_current_secure_channel_state(UNKNOWN_STATE.to_string()).await{ - logger::write_warning(format!("Failed to update secure channel state to 'Unknown': {}", e)); + logger::write_warning(format!("Failed to update secure channel state to 'Unknown': {e}")); } if start.elapsed().as_millis() > PROVISION_TIMEUP_IN_MILLISECONDS { @@ -253,7 +251,7 @@ impl KeyKeeper { let continue_sleep = sleep.as_millis() - slept_time_in_millisec; if continue_sleep > 0 { let continue_sleep = Duration::from_millis(continue_sleep as u64); - let message = format!("poll_secure_channel_status task notified but secure channel state is '{}', continue with sleep wait for {:?}.", current_state, continue_sleep); + let message = format!("poll_secure_channel_status task notified but secure channel state is '{current_state}', continue with sleep wait for {continue_sleep:?}."); logger::write_warning(message); tokio::time::sleep(continue_sleep).await; } @@ -292,12 +290,12 @@ impl KeyKeeper { let status = match key::get_status(&self.base_url).await { Ok(s) => s, Err(e) => { - self.update_status_message(format!("Failed to get key status - {}", e), true) + self.update_status_message(format!("Failed to get key status - {e}"), true) .await; continue; } }; - self.update_status_message(format!("Got key status successfully: {}.", status), true) + self.update_status_message(format!("Got key status successfully: {status}."), true) .await; let mut access_control_rules_changed = false; @@ -313,21 +311,20 @@ impl KeyKeeper { Ok((updated, old_wire_server_rule_id)) => { if updated { logger::write_warning(format!( - "Wireserver rule id changed from '{}' to '{}'.", - old_wire_server_rule_id, wireserver_rule_id + "Wireserver rule id changed from '{old_wire_server_rule_id}' to '{wireserver_rule_id}'." )); if let Err(e) = self .key_keeper_shared_state .set_wireserver_rules(status.get_wireserver_rules()) .await { - logger::write_error(format!("Failed to set wireserver rules: {}", e)); + logger::write_error(format!("Failed to set wireserver rules: {e}")); } access_control_rules_changed = true; } } Err(e) => { - logger::write_warning(format!("Failed to update wireserver rule id: {}", e)); + logger::write_warning(format!("Failed to update wireserver rule id: {e}")); } } @@ -339,21 +336,20 @@ impl KeyKeeper { Ok((updated, old_imds_rule_id)) => { if updated { logger::write_warning(format!( - "IMDS rule id changed from '{}' to '{}'.", - old_imds_rule_id, imds_rule_id + "IMDS rule id changed from '{old_imds_rule_id}' to '{imds_rule_id}'." )); if let Err(e) = self .key_keeper_shared_state .set_imds_rules(status.get_imds_rules()) .await { - logger::write_error(format!("Failed to set imds rules: {}", e)); + logger::write_error(format!("Failed to set imds rules: {e}")); } access_control_rules_changed = true; } } Err(e) => { - logger::write_warning(format!("Failed to update imds rule id: {}", e)); + logger::write_warning(format!("Failed to update imds rule id: {e}")); } } @@ -365,21 +361,20 @@ impl KeyKeeper { Ok((updated, old_hostga_rule_id)) => { if updated { logger::write_warning(format!( - "HostGA rule id changed from '{}' to '{}'.", - old_hostga_rule_id, hostga_rule_id + "HostGA rule id changed from '{old_hostga_rule_id}' to '{hostga_rule_id}'." )); if let Err(e) = self .key_keeper_shared_state .set_hostga_rules(status.get_hostga_rules()) .await { - logger::write_error(format!("Failed to set HostGA rules: {}", e)); + logger::write_error(format!("Failed to set HostGA rules: {e}")); } access_control_rules_changed = true; } } Err(e) => { - logger::write_warning(format!("Failed to update HostGA rule id: {}", e)); + logger::write_warning(format!("Failed to update HostGA rule id: {e}")); } } @@ -416,7 +411,7 @@ impl KeyKeeper { if let Err(e) = self.key_keeper_shared_state.update_key(key.clone()).await { - logger::write_warning(format!("Failed to update key: {}", e)); + logger::write_warning(format!("Failed to update key: {e}")); } let message = helpers::write_startup_event( @@ -440,7 +435,7 @@ impl KeyKeeper { Err(e) => { event_logger::write_event( LoggerLevel::Info, - format!("Failed to fetch local key details with error: {:?}. Will try acquire the key details from Server.", e), + format!("Failed to fetch local key details with error: {e:?}. Will try acquire the key details from Server."), "poll_secure_channel_status", "key_keeper", logger::AGENT_LOGGER_KEY, @@ -458,7 +453,7 @@ impl KeyKeeper { Ok(k) => k, Err(e) => { self.update_status_message( - format!("Failed to acquire key details: {:?}", e), + format!("Failed to acquire key details: {e:?}"), true, ) .await; @@ -471,11 +466,11 @@ impl KeyKeeper { match Self::store_key(&self.key_dir, &key) { Ok(()) => { logger::write_information(format!( - "Successfully acquired the key '{}' details from server and saved locally.", guid)); + "Successfully acquired the key '{guid}' details from server and saved locally.")); } Err(e) => { self.update_status_message( - format!("Failed to save key details to file: {:?}", e), + format!("Failed to save key details to file: {e:?}"), true, ) .await; @@ -487,8 +482,7 @@ impl KeyKeeper { if let Err(e) = Self::check_key(&self.key_dir, &key) { self.update_status_message( format!( - "Failed to check the key '{}' details saved locally: {:?}.", - guid, e + "Failed to check the key '{guid}' details saved locally: {e:?}." ), true, ) @@ -501,7 +495,7 @@ impl KeyKeeper { if let Err(e) = self.key_keeper_shared_state.update_key(key.clone()).await { - logger::write_warning(format!("Failed to update key: {}", e)); + logger::write_warning(format!("Failed to update key: {e}")); } let message = helpers::write_startup_event( @@ -521,7 +515,7 @@ impl KeyKeeper { .await; } Err(e) => { - logger::write_warning(format!("Failed to attest the key: {:?}", e)); + logger::write_warning(format!("Failed to attest the key: {e:?}")); continue; } } @@ -567,7 +561,7 @@ impl KeyKeeper { // clear key in memory for disabled state if let Err(e) = self.key_keeper_shared_state.clear_key().await { - logger::write_warning(format!("Failed to clear key: {}", e)); + logger::write_warning(format!("Failed to clear key: {e}")); } provision::key_latched( self.cancellation_token.clone(), @@ -581,7 +575,7 @@ impl KeyKeeper { } } Err(e) => { - logger::write_warning(format!("Failed to update secure channel state: {}", e)); + logger::write_warning(format!("Failed to update secure channel state: {e}")); } } } @@ -600,7 +594,7 @@ impl KeyKeeper { } } Err(e) => { - logger::write_warning(format!("Failed to set module status message: {}", e)); + logger::write_warning(format!("Failed to set module status message: {e}")); } } } @@ -616,8 +610,7 @@ impl KeyKeeper { &key_file, serde_json::to_string(&key).map_err(|e| { Error::Key(KeyErrorType::StoreLocalKey(format!( - "serialize key error: {:?} ", - e + "serialize key error: {e:?} " ))) })?, ) @@ -690,8 +683,7 @@ impl KeyKeeper { serde_json::from_str::(&key_data).map_err(|e| { Error::Key(crate::common::error::KeyErrorType::FetchLocalKey(format!( - "Parse key data with error: {}", - e + "Parse key data with error: {e}" ))) }) } @@ -704,8 +696,7 @@ impl KeyKeeper { #[cfg(windows)] { logger::write_information(format!( - "Failed to fetch .encrypted file with error: {}. Fallback to fetch .key file for windows platform.", - _e + "Failed to fetch .encrypted file with error: {_e}. Fallback to fetch .key file for windows platform." )); } @@ -760,8 +751,7 @@ impl KeyKeeper { .await { logger::write_warning(format!( - "Failed to set key_keeper module state to 'Stopped' with error: {} ", - e + "Failed to set key_keeper module state to 'Stopped' with error: {e} " )); } } diff --git a/proxy_agent/src/key_keeper/key.rs b/proxy_agent/src/key_keeper/key.rs index 9adcd118..bf8ba5ac 100644 --- a/proxy_agent/src/key_keeper/key.rs +++ b/proxy_agent/src/key_keeper/key.rs @@ -419,8 +419,7 @@ impl KeyStatus { && key_delivery_method != constants::KEY_DELIVERY_METHOD_VTPM { validate_message.push_str(&format!( - "keyDeliveryMethod '{}' is invalid; ", - key_delivery_method + "keyDeliveryMethod '{key_delivery_method}' is invalid; " )); } @@ -444,7 +443,7 @@ impl KeyStatus { && state != super::MUST_SIG_WIRESERVER_IMDS { validate_message - .push_str(&format!("secureChannelState '{}' is invalid; ", state)); + .push_str(&format!("secureChannelState '{state}' is invalid; ")); validate_result = false; } } @@ -528,7 +527,7 @@ impl KeyStatus { None => return super::DISABLE_STATE.to_string(), } - format!("{} - {} - {}", wireserver, imds, hostga) + format!("{wireserver} - {imds} - {hostga}") } else { super::DISABLE_STATE.to_string() } @@ -720,7 +719,7 @@ const KEY_URL: &str = "/secure-channel/key"; pub async fn get_status(base_url: &Uri) -> Result { let (host, port) = hyper_client::host_port_from_uri(base_url)?; - let url = format!("http://{}:{}{}", host, port, STATUS_URL); + let url = format!("http://{host}:{port}{STATUS_URL}"); let url: Uri = url.parse().map_err(|e| { Error::Key(KeyErrorType::ParseKeyUrl( base_url.to_string(), @@ -739,7 +738,7 @@ pub async fn get_status(base_url: &Uri) -> Result { pub async fn acquire_key(base_url: &Uri) -> Result { let (host, port) = hyper_client::host_port_from_uri(base_url)?; - let url = format!("http://{}:{}{}", host, port, KEY_URL); + let url = format!("http://{host}:{port}{KEY_URL}"); let url: Uri = url.parse().map_err(|e| { Error::Key(KeyErrorType::ParseKeyUrl( base_url.to_string(), diff --git a/proxy_agent/src/main.rs b/proxy_agent/src/main.rs index 63ae8657..74940119 100644 --- a/proxy_agent/src/main.rs +++ b/proxy_agent/src/main.rs @@ -97,7 +97,7 @@ async fn main() { match service_dispatcher::start(constants::PROXY_AGENT_SERVICE_NAME, ffi_service_main) { Ok(_) => {} Err(e) => { - logger::write_error(format!("Error in starting the service dispatcher: {}", e)); + logger::write_error(format!("Error in starting the service dispatcher: {e}")); } } } @@ -121,7 +121,7 @@ fn proxy_agent_windows_service_main(_args: Vec) { .expect("You must provide the Tokio runtime handle before this function is called"); handle.block_on(async { if let Err(e) = windows::run_service().await { - logger::write_error(format!("Error in running the service: {}", e)); + logger::write_error(format!("Error in running the service: {e}")); } }); } diff --git a/proxy_agent/src/provision.rs b/proxy_agent/src/provision.rs index 806fa0ad..bec9c783 100644 --- a/proxy_agent/src/provision.rs +++ b/proxy_agent/src/provision.rs @@ -596,10 +596,7 @@ pub mod provision_query { let state = match self.get_current_provision_status(first_loop).await { Ok(state) => state, Err(e) => { - println!( - "Failed to query the current provision state with error: {}.", - e - ); + println!("Failed to query the current provision state with error: {e}."); ProvisionState::new(false, String::new()) } }; diff --git a/proxy_agent/src/proxy.rs b/proxy_agent/src/proxy.rs index 31de00a9..19be4655 100644 --- a/proxy_agent/src/proxy.rs +++ b/proxy_agent/src/proxy.rs @@ -91,7 +91,7 @@ async fn get_user( } else { let user = User::from_logon_id(logon_id)?; if let Err(e) = proxy_server_shared_state.add_user(user.clone()).await { - println!("Failed to add user: {} to cache", e); + println!("Failed to add user: {e} to cache"); } Ok(user) } @@ -166,7 +166,7 @@ impl Process { #[cfg(windows)] { let handler = windows::get_process_handler(pid).unwrap_or_else(|e| { - println!("Failed to get process handler: {}", e); + println!("Failed to get process handler: {e}"); 0 }); let base_info = windows::query_basic_process_info(handler); @@ -178,7 +178,7 @@ impl Process { Err(e) => { process_full_path = PathBuf::default(); cmd = UNDEFINED.to_string(); - println!("Failed to query basic process info: {}", e); + println!("Failed to query basic process info: {e}"); } } } diff --git a/proxy_agent/src/proxy/authorization_rules.rs b/proxy_agent/src/proxy/authorization_rules.rs index 6d4805b6..27ef84fa 100644 --- a/proxy_agent/src/proxy/authorization_rules.rs +++ b/proxy_agent/src/proxy/authorization_rules.rs @@ -52,7 +52,7 @@ impl std::str::FromStr for AuthorizationMode { "disabled" => Ok(AuthorizationMode::Disabled), "audit" => Ok(AuthorizationMode::Audit), "enforce" => Ok(AuthorizationMode::Enforce), - _ => Err(format!("Invalid AuthorizationMode: {}", s)), + _ => Err(format!("Invalid AuthorizationMode: {s}")), } } } @@ -84,7 +84,7 @@ impl ComputedAuthorizationItem { Ok(mode) => mode, Err(err) => { // This should not happen, log the error and set the mode to disabled - logger::write_error(format!("Failed to parse authorization mode: {}", err)); + logger::write_error(format!("Failed to parse authorization mode: {err}")); AuthorizationMode::Disabled } }; @@ -184,7 +184,7 @@ impl ComputedAuthorizationItem { any_privilege_matched = true; logger.write( LoggerLevel::Trace, - format!("Request matched privilege '{}'.", privilege_name), + format!("Request matched privilege '{privilege_name}'."), ); if let Some(assignments) = self.privilegeAssignments.get(privilege_name) { @@ -195,8 +195,7 @@ impl ComputedAuthorizationItem { logger.write( LoggerLevel::Trace, format!( - "Request matched privilege '{}' and identity '{}'.", - privilege_name, identity_name + "Request matched privilege '{privilege_name}' and identity '{identity_name}'." ), ); return true; @@ -206,23 +205,21 @@ impl ComputedAuthorizationItem { logger.write( LoggerLevel::Trace, format!( - "Request matched privilege '{}' but no identity matched.", - privilege_name + "Request matched privilege '{privilege_name}' but no identity matched." ), ); } else { logger.write( LoggerLevel::Trace, format!( - "Request matched privilege '{}' but no identity assigned.", - privilege_name + "Request matched privilege '{privilege_name}' but no identity assigned." ), ); } } else { logger.write( LoggerLevel::Trace, - format!("Request does not match privilege '{}'.", privilege_name), + format!("Request does not match privilege '{privilege_name}'."), ); } } diff --git a/proxy_agent/src/proxy/proxy_authorizer.rs b/proxy_agent/src/proxy/proxy_authorizer.rs index 8e113616..cbe575f7 100644 --- a/proxy_agent/src/proxy/proxy_authorizer.rs +++ b/proxy_agent/src/proxy/proxy_authorizer.rs @@ -66,7 +66,7 @@ impl Authorizer for WireServer { } else { if rules.mode == AuthorizationMode::Audit { logger.write( - LoggerLevel::Info, format!("WireServer request {} denied in audit mode, continue forward the request", request_url)); + LoggerLevel::Info, format!("WireServer request {request_url} denied in audit mode, continue forward the request")); return AuthorizeResult::OkWithAudit; } return AuthorizeResult::Forbidden; @@ -104,8 +104,7 @@ impl Authorizer for Imds { logger.write( LoggerLevel::Info, format!( - "IMDS request {} denied in audit mode, continue forward the request", - request_url + "IMDS request {request_url} denied in audit mode, continue forward the request" ), ); return AuthorizeResult::OkWithAudit; @@ -143,7 +142,7 @@ impl Authorizer for GAPlugin { } else { if rules.mode == AuthorizationMode::Audit { logger.write( - LoggerLevel::Info, format!("HostGAPlugin request {} denied in audit mode, continue forward the request", request_url)); + LoggerLevel::Info, format!("HostGAPlugin request {request_url} denied in audit mode, continue forward the request")); return AuthorizeResult::OkWithAudit; } return AuthorizeResult::Forbidden; diff --git a/proxy_agent/src/proxy/proxy_connection.rs b/proxy_agent/src/proxy/proxy_connection.rs index 0b034a69..b4200251 100644 --- a/proxy_agent/src/proxy/proxy_connection.rs +++ b/proxy_agent/src/proxy/proxy_connection.rs @@ -4,8 +4,8 @@ //! This module contains the connection context struct for the proxy listener, and write proxy processing logs to local file. use crate::common::error::{Error, HyperErrorType}; -use crate::common::hyper_client; use crate::common::result::Result; +use crate::common::{config, hyper_client}; use crate::proxy::Claims; use crate::redirector::{self, AuditEntry}; use crate::shared_state::proxy_server_wrapper::ProxyServerSharedState; @@ -39,7 +39,7 @@ impl Client { let full_url = req.uri().to_string(); self.sender.send_request(req).await.map_err(|e| { Error::Hyper(HyperErrorType::Custom( - format!("Failed to send request to {}", full_url), + format!("Failed to send request to {full_url}"), e, )) }) @@ -91,7 +91,7 @@ impl TcpConnectionContext { Err(e) => { logger.write( LoggerLevel::Error, - format!("Failed to get claims from audit entry: {}", e), + format!("Failed to get claims from audit entry: {e}"), ); // return None for claims None @@ -154,22 +154,20 @@ impl TcpConnectionContext { logger.write( LoggerLevel::Trace, format!( - "Found audit entry with client_source_port '{}' successfully", - client_source_port + "Found audit entry with client_source_port '{client_source_port}' successfully" ), ); match redirector::remove_audit(client_source_port, redirector_shared_state).await { Ok(_) => logger.write( LoggerLevel::Trace, format!( - "Removed audit entry with client_source_port '{}' successfully", - client_source_port + "Removed audit entry with client_source_port '{client_source_port}' successfully" ), ), Err(e) => { logger.write( LoggerLevel::Warn, - format!("Failed to remove audit entry: {}", e), + format!("Failed to remove audit entry: {e}"), ); } } @@ -178,8 +176,7 @@ impl TcpConnectionContext { } Err(e) => { let message = format!( - "Failed to find audit entry with client_source_port '{}' with error: {}", - client_source_port, e + "Failed to find audit entry with client_source_port '{client_source_port}' with error: {e}" ); logger.write(LoggerLevel::Warn, message.clone()); @@ -206,7 +203,7 @@ impl TcpConnectionContext { Err(e) => { logger.write( LoggerLevel::Warn, - format!("Failed to get lookup_audit_from_stream with error: {}", e), + format!("Failed to get lookup_audit_from_stream with error: {e}"), ); Err(Error::FindAuditEntryError(message)) } @@ -290,15 +287,41 @@ impl ConnectionLogger { } pub fn write(&mut self, logger_level: LoggerLevel, message: String) { - if logger_level > logger_manager::get_logger_level() { + let message = format!( + "{}[{}] - {}", + self.http_connection_id, self.tcp_connection_id, message + ); + + // write to system log for connection logger explicitly, + // as the connection logger only writes to file when the connection is dropped and, + // connection logger file log does not write to system log implicitly. + logger_manager::write_system_log(logger_level, message.to_string()); + + if let Some(log_for_event) = crate::common::config::get_file_log_level_for_events() { + if log_for_event >= logger_level { + // write to event + let (module_name, caller_name) = proxy_agent_shared::logger::get_caller_info( + "proxy_agent::proxy::proxy_connection", + ); + proxy_agent_shared::telemetry::event_logger::write_event_only( + logger_level, + message.to_string(), + &caller_name, + &module_name, + ); + } + } + + if logger_level > logger_manager::get_max_logger_level() + || config::get_logs_dir() == std::path::PathBuf::from("") + { + // If the logger level is higher than the max logger level or logs directory is not set, skip logging return; } self.queue.push(format!( - "{}{}[{}] - {}", + "{}{}", logger::get_log_header(logger_level), - self.http_connection_id, - self.tcp_connection_id, message )); } diff --git a/proxy_agent/src/proxy/proxy_server.rs b/proxy_agent/src/proxy/proxy_server.rs index 0f765aaf..8a4e4214 100644 --- a/proxy_agent/src/proxy/proxy_server.rs +++ b/proxy_agent/src/proxy/proxy_server.rs @@ -111,10 +111,7 @@ impl ProxyServer { } _ => { // other error, return it - return Err(Error::Io( - format!("Failed to bind TcpListener '{}'", addr), - e, - )); + return Err(Error::Io(format!("Failed to bind TcpListener '{addr}'"), e)); } }, } @@ -123,7 +120,7 @@ impl ProxyServer { // one more effort try bind to the addr TcpListener::bind(addr) .await - .map_err(|e| Error::Io(format!("Failed to bind TcpListener '{}'", addr), e)) + .map_err(|e| Error::Io(format!("Failed to bind TcpListener '{addr}'"), e)) } pub async fn start(&self) { @@ -145,14 +142,14 @@ impl ProxyServer { .set_module_status_message(message.to_string(), AgentStatusModule::ProxyServer) .await { - logger::write_warning(format!("Failed to set module status message: {}", e)); + logger::write_warning(format!("Failed to set module status message: {e}")); } if let Err(e) = self .agent_status_shared_state .set_module_state(ModuleState::STOPPED, AgentStatusModule::ProxyServer) .await { - logger::write_warning(format!("Failed to set module state: {}", e)); + logger::write_warning(format!("Failed to set module state: {e}")); } // send this critical error to event logger @@ -179,14 +176,14 @@ impl ProxyServer { .set_module_status_message(message.to_string(), AgentStatusModule::ProxyServer) .await { - logger::write_warning(format!("Failed to set module status message: {}", e)); + logger::write_warning(format!("Failed to set module status message: {e}")); } if let Err(e) = self .agent_status_shared_state .set_module_state(ModuleState::RUNNING, AgentStatusModule::ProxyServer) .await { - logger::write_warning(format!("Failed to set module state: {}", e)); + logger::write_warning(format!("Failed to set module state: {e}")); } provision::listener_started( self.cancellation_token.clone(), @@ -213,7 +210,7 @@ impl ProxyServer { self.handle_new_tcp_connection(stream, client_addr).await; }, Err(e) => { - logger::write_error(format!("Failed to accept connection: {}", e)); + logger::write_error(format!("Failed to accept connection: {e}")); } } } @@ -235,7 +232,7 @@ impl ProxyServer { Err(e) => { ConnectionLogger::new(0, 0).write( LoggerLevel::Error, - format!("Failed to increase tcp connection count: {}", e), + format!("Failed to increase tcp connection count: {e}"), ); return; } @@ -243,7 +240,7 @@ impl ProxyServer { let mut tcp_connection_logger = ConnectionLogger::new(tcp_connection_id, 0); tcp_connection_logger.write( LoggerLevel::Trace, - format!("Accepted new tcp connection [{}].", tcp_connection_id), + format!("Accepted new tcp connection [{tcp_connection_id}]."), ); tokio::spawn({ @@ -255,7 +252,7 @@ impl ProxyServer { Err(e) => { tcp_connection_logger.write( LoggerLevel::Error, - format!("Failed to set stream read timeout: {}", e), + format!("Failed to set stream read timeout: {e}"), ); return; } @@ -312,7 +309,7 @@ impl ProxyServer { { tcp_connection_logger.write( LoggerLevel::Warn, - format!("ProxyListener serve_connection error: {}", e), + format!("ProxyListener serve_connection error: {e}"), ); } } @@ -342,7 +339,7 @@ impl ProxyServer { if let Err(e) = std_stream.set_read_timeout(Some(std::time::Duration::from_secs(10))) { connection_logger.write( LoggerLevel::Warn, - format!("Failed to set read timeout: {}", e), + format!("Failed to set read timeout: {e}"), ); } @@ -376,9 +373,9 @@ impl ProxyServer { Err(e) => { tcp_connection_context.log( LoggerLevel::Error, - format!("Failed to increase connection count: {}", e), + format!("Failed to increase connection count: {e}"), ); - return Ok(Self::empty_response(StatusCode::INTERNAL_SERVER_ERROR)); + return Ok(Self::closed_response(StatusCode::INTERNAL_SERVER_ERROR)); } }; @@ -408,7 +405,7 @@ impl ProxyServer { "Traversal characters found in the request, return NOT_FOUND!".to_string(), ) .await; - return Ok(Self::empty_response(StatusCode::NOT_FOUND)); + return Ok(Self::closed_response(StatusCode::NOT_FOUND)); } if http_connection_context.url == provision::provision_query::PROVISION_URL_PATH { @@ -430,7 +427,7 @@ impl ProxyServer { "No remote destination_ip found in the request, return!".to_string(), ) .await; - return Ok(Self::empty_response(StatusCode::MISDIRECTED_REQUEST)); + return Ok(Self::closed_response(StatusCode::MISDIRECTED_REQUEST)); } }; let port = tcp_connection_context.destination_port; @@ -444,7 +441,7 @@ impl ProxyServer { "No claims found in the request, return!".to_string(), ) .await; - return Ok(Self::empty_response(StatusCode::MISDIRECTED_REQUEST)); + return Ok(Self::closed_response(StatusCode::MISDIRECTED_REQUEST)); } }; http_connection_context.log(LoggerLevel::Trace, format!("Use lookup value:{ip}:{port}.")); @@ -455,10 +452,10 @@ impl ProxyServer { &mut http_connection_context, StatusCode::MISDIRECTED_REQUEST, false, - format!("Failed to get claims json string: {}", e), + format!("Failed to get claims json string: {e}"), ) .await; - return Ok(Self::empty_response(StatusCode::MISDIRECTED_REQUEST)); + return Ok(Self::closed_response(StatusCode::MISDIRECTED_REQUEST)); } }; http_connection_context.log(LoggerLevel::Trace, claim_details.to_string()); @@ -477,10 +474,10 @@ impl ProxyServer { &mut http_connection_context, StatusCode::INTERNAL_SERVER_ERROR, false, - format!("Failed to get access control rules: {}", e), + format!("Failed to get access control rules: {e}"), ) .await; - return Ok(Self::empty_response(StatusCode::INTERNAL_SERVER_ERROR)); + return Ok(Self::closed_response(StatusCode::INTERNAL_SERVER_ERROR)); } }; let result = proxy_authorizer::authorize( @@ -505,10 +502,10 @@ impl ProxyServer { &mut http_connection_context, StatusCode::FORBIDDEN, false, - format!("Block unauthorized request: {}", claim_details), + format!("Block unauthorized request: {claim_details}"), ) .await; - return Ok(Self::empty_response(StatusCode::FORBIDDEN)); + return Ok(Self::closed_response(StatusCode::FORBIDDEN)); } } @@ -528,12 +525,9 @@ impl ProxyServer { Err(e) => { http_connection_context.log( LoggerLevel::Error, - format!( - "Failed to add claims header: {} with error: {}", - host_claims, e - ), + format!("Failed to add claims header: {host_claims} with error: {e}"), ); - return Ok(Self::empty_response(StatusCode::BAD_GATEWAY)); + return Ok(Self::closed_response(StatusCode::BAD_GATEWAY)); } }, ); @@ -544,9 +538,9 @@ impl ProxyServer { Err(e) => { http_connection_context.log( LoggerLevel::Error, - format!("Failed to add date header with error: {}", e), + format!("Failed to add date header with error: {e}"), ); - return Ok(Self::empty_response(StatusCode::BAD_GATEWAY)); + return Ok(Self::closed_response(StatusCode::BAD_GATEWAY)); } }, ); @@ -571,9 +565,9 @@ impl ProxyServer { Err(e) => { http_connection_context.log( LoggerLevel::Error, - format!("Failed to convert request: {}", e), + format!("Failed to convert request: {e}"), ); - return Ok(Self::empty_response(StatusCode::BAD_REQUEST)); + return Ok(Self::closed_response(StatusCode::BAD_REQUEST)); } }; let proxy_response = http_connection_context.send_request(request).await; @@ -606,7 +600,7 @@ impl ProxyServer { LoggerLevel::Warn, "No MetaData header found in the request.".to_string(), ); - return Ok(Self::empty_response(StatusCode::BAD_REQUEST)); + return Ok(Self::closed_response(StatusCode::BAD_REQUEST)); } // Get the query time_tick let query_time_tick = match request.headers().get(constants::TIME_TICK_HEADER) { @@ -624,7 +618,7 @@ impl ProxyServer { Err(e) => { logger.write( LoggerLevel::Warn, - format!("Failed to parse time_tick header: {}", e), + format!("Failed to parse time_tick header: {e}"), ); 0 } @@ -652,7 +646,7 @@ impl ProxyServer { if let Err(e) = self.key_keeper_shared_state.notify().await { logger.write( LoggerLevel::Warn, - format!("Failed to notify key_keeper: {}", e), + format!("Failed to notify key_keeper: {e}"), ); } } @@ -663,7 +657,7 @@ impl ProxyServer { ); match serde_json::to_string(&provision_state) { Ok(json) => { - logger.write(LoggerLevel::Info, format!("Provision state: {}", json)); + logger.write(LoggerLevel::Info, format!("Provision state: {json}")); let mut response = Response::new(hyper_client::full_body(json.as_bytes().to_vec())); response.headers_mut().insert( hyper::header::CONTENT_TYPE, @@ -672,7 +666,7 @@ impl ProxyServer { Ok(response) } Err(e) => { - let error = format!("Failed to get provision state: {}", e); + let error = format!("Failed to get provision state: {e}"); logger.write(LoggerLevel::Warn, error.to_string()); let mut response = Response::new(hyper_client::full_body(error.as_bytes().to_vec())); @@ -698,10 +692,10 @@ impl ProxyServer { &mut http_connection_context, http_status_code, false, - format!("Failed to send request to host: {}", e), + format!("Failed to send request to host: {e}"), ) .await; - return Ok(Self::empty_response(http_status_code)); + return Ok(Self::closed_response(http_status_code)); } }; @@ -713,7 +707,7 @@ impl ProxyServer { Err(e) => { logger.write( LoggerLevel::Error, - format!("Failed to get frame data: {:?}", e), + format!("Failed to get frame data: {e:?}"), ); Bytes::new() } @@ -794,7 +788,6 @@ impl ProxyServer { errorDetails: error_details, }; if let Ok(json) = serde_json::to_string(&summary) { - logger::write_console_log(json.to_string()); event_logger::write_event( LoggerLevel::Info, json, @@ -811,7 +804,7 @@ impl ProxyServer { { http_connection_context.log( LoggerLevel::Warn, - format!("Failed to add failed connection summary: {}", e), + format!("Failed to add failed connection summary: {e}"), ); } } else if let Err(e) = self @@ -821,7 +814,7 @@ impl ProxyServer { { http_connection_context.log( LoggerLevel::Warn, - format!("Failed to add connection summary: {}", e), + format!("Failed to add connection summary: {e}"), ); } } @@ -835,6 +828,17 @@ impl ProxyServer { response } + fn closed_response(status_code: StatusCode) -> Response> { + let mut response = Self::empty_response(status_code); + + // Add the Connection: close header to close the tcp connection + response + .headers_mut() + .insert(hyper::header::CONNECTION, HeaderValue::from_static("close")); + + response + } + async fn handle_request_with_signature( &self, mut http_connection_context: HttpConnectionContext, @@ -846,9 +850,9 @@ impl ProxyServer { Err(e) => { http_connection_context.log( LoggerLevel::Error, - format!("Failed to receive the request body: {}", e), + format!("Failed to receive the request body: {e}"), ); - return Ok(Self::empty_response(StatusCode::BAD_REQUEST)); + return Ok(Self::closed_response(StatusCode::BAD_REQUEST)); } }; @@ -891,24 +895,23 @@ impl ProxyServer { http_connection_context.log( LoggerLevel::Error, format!( - "Failed to add authorization header: {} with error: {}", - authorization_value, e + "Failed to add authorization header: {authorization_value} with error: {e}" ), ); - return Ok(Self::empty_response(StatusCode::BAD_GATEWAY)); + return Ok(Self::closed_response(StatusCode::BAD_GATEWAY)); } }, ); http_connection_context.log( LoggerLevel::Trace, - format!("Added authorization header {}", authorization_value), + format!("Added authorization header {authorization_value}"), ) } Err(e) => { http_connection_context.log( LoggerLevel::Error, - format!("compute_signature failed with error: {}", e), + format!("compute_signature failed with error: {e}"), ); } } @@ -973,15 +976,29 @@ mod tests { .unwrap_or(None), ) .unwrap(); - let response = hyper_client::send_request(host, port, request, logger::write_warning) + let mut sender = hyper_client::build_http_sender(host, port, logger::write_warning) .await .unwrap(); + let response = sender.send_request(request).await.unwrap(); assert_eq!( http::StatusCode::MISDIRECTED_REQUEST, response.status(), "response.status must be MISDIRECTED_REQUEST." ); + // verify the connection is closed + response.headers().get("connection").map(|v| { + assert_eq!( + v.to_str().unwrap(), + "close", + "response.headers.connection must be close." + ); + }); + assert!( + sender.is_closed(), + "sender must be closed after the request." + ); + // test with traversal characters let url: hyper::Uri = format!("http://{}:{}/test/../", host, port) .parse() diff --git a/proxy_agent/src/proxy/windows.rs b/proxy_agent/src/proxy/windows.rs index fe96ed9e..74085f59 100644 --- a/proxy_agent/src/proxy/windows.rs +++ b/proxy_agent/src/proxy/windows.rs @@ -11,18 +11,23 @@ use once_cell::sync::Lazy; use std::mem::MaybeUninit; use std::ptr::null_mut; use std::{collections::HashMap, ffi::OsString, os::windows::ffi::OsStringExt, path::PathBuf}; +use windows_sys::Wdk::System::Threading::{ + NtQueryInformationProcess, // ntdll.dll + PROCESSINFOCLASS, +}; use windows_sys::Win32::Foundation::{BOOL, HANDLE, LUID, NTSTATUS, UNICODE_STRING}; use windows_sys::Win32::Security::Authentication::Identity; -use windows_sys::Win32::Security::Authentication::Identity::SECURITY_LOGON_SESSION_DATA; +use windows_sys::Win32::Security::Authentication::Identity::{ + LSA_UNICODE_STRING, SECURITY_LOGON_SESSION_DATA, +}; use windows_sys::Win32::System::ProcessStatus::{ K32GetModuleBaseNameW, // kernel32.dll K32GetModuleFileNameExW, // kernel32.dll }; +use windows_sys::Win32::System::Threading::PROCESS_BASIC_INFORMATION; use windows_sys::Win32::System::Threading::{ - NtQueryInformationProcess, // ntdll.dll - OpenProcess, //kernel32.dll + OpenProcess, //kernel32.dll }; -use windows_sys::Win32::System::Threading::{PROCESSINFOCLASS, PROCESS_BASIC_INFORMATION}; const LG_INCLUDE_INDIRECT: u32 = 1u32; const MAX_PREFERRED_LENGTH: u32 = 4294967295u32; @@ -36,8 +41,8 @@ fn load_netapi32_dll() -> Library { match unsafe { Library::new(dll_name) } { Ok(lib) => lib, Err(e) => { - logger::write_error(format!("Loading {} failed with error: {}.", dll_name, e)); - panic!("Loading {} failed with error: {}", dll_name, e); + logger::write_error(format!("Loading {dll_name} failed with error: {e}.")); + panic!("Loading {dll_name} failed with error: {e}"); } } } @@ -110,7 +115,7 @@ pub fn get_user(logon_id: u64) -> Result<(String, Vec)> { if status != 0 { let e = std::io::Error::from_raw_os_error(status as i32); return Err(Error::WindowsApi( - WindowsApiErrorType::LsaGetLogonSessionData(format!("failed with os error: {}", e)), + WindowsApiErrorType::LsaGetLogonSessionData(format!("failed with os error: {e}")), )); } @@ -122,8 +127,7 @@ pub fn get_user(logon_id: u64) -> Result<(String, Vec)> { // but finding that SECURITY_LOGON_SESSION_DATA->UserName.Length is 0, // it typically means that the logon session exists but does not have an associated username. logger::write_warning(format!( - "LsaGetLogonSessionData with login'{}' success, but user name is empty.", - logon_id + "LsaGetLogonSessionData with logon id '{logon_id}' success, but user name is empty." )); // return OK with UNDEFINED user name and empty groups return Ok((super::UNDEFINED.to_string(), Vec::new())); @@ -166,8 +170,7 @@ pub fn get_user(logon_id: u64) -> Result<(String, Vec)> { } else { let e = std::io::Error::from_raw_os_error(status as i32); logger::write_warning(format!( - "NetUserGetLocalGroups '{}' failed ({}) with os error: {}", - domain_user_name, status, e + "NetUserGetLocalGroups '{domain_user_name}' failed ({status}) with os error: {e}" )); } @@ -179,7 +182,7 @@ pub fn get_user(logon_id: u64) -> Result<(String, Vec)> { Ok((user_name, user_groups)) } -fn from_unicode_string(unicode_string: &UNICODE_STRING) -> String { +fn from_unicode_string(unicode_string: &LSA_UNICODE_STRING) -> String { let mut v = vec![0u16; unicode_string.Length as usize]; unsafe { std::ptr::copy_nonoverlapping( @@ -291,7 +294,7 @@ pub fn get_process_cmd(handler: isize) -> Result { std::io::Error::from_raw_os_error(status), ))); } - println!("return_length: {}", return_length); + println!("return_length: {return_length}"); let buf_len = (return_length as usize) / 2; let mut buffer: Vec = vec![0; buf_len + 1]; @@ -305,7 +308,7 @@ pub fn get_process_cmd(handler: isize) -> Result { &mut return_length as *mut _, ); if status < 0 { - eprintln!("NtQueryInformationProcess failed with status: {}", status); + eprintln!("NtQueryInformationProcess failed with status: {status}"); return Err(Error::WindowsApi(WindowsApiErrorType::WindowsOsError( std::io::Error::from_raw_os_error(status), ))); diff --git a/proxy_agent/src/proxy_agent_status.rs b/proxy_agent/src/proxy_agent_status.rs index 6496b308..777c1620 100644 --- a/proxy_agent/src/proxy_agent_status.rs +++ b/proxy_agent/src/proxy_agent_status.rs @@ -92,7 +92,7 @@ impl ProxyAgentStatusTask { .set_module_status_message(status_message, AgentStatusModule::ProxyAgentStatus) .await { - logger::write_error(format!("Error updating agent status message: {}", e)); + logger::write_error(format!("Error updating agent status message: {e}")); } } @@ -104,7 +104,7 @@ impl ProxyAgentStatusTask { { Ok(message) => message, Err(e) => { - let message = format!("Error getting agent status message: {}", e); + let message = format!("Error getting agent status message: {e}"); logger::write_error(message.clone()); message } @@ -131,7 +131,7 @@ impl ProxyAgentStatusTask { if status_report_time.elapsed() >= status_report_duration { let status = match serde_json::to_string(&aggregate_status.proxyAgentStatus) { Ok(status) => status, - Err(e) => format!("Error serializing proxy agent status: {}", e), + Err(e) => format!("Error serializing proxy agent status: {e}"), }; event_logger::write_event( LoggerLevel::Info, @@ -152,7 +152,7 @@ impl ProxyAgentStatusTask { .to_string(), ); if let Err(e) = self.agent_status_shared_state.clear_all_summary().await { - logger::write_error(format!("Error clearing the connection summary map and failed authenticate summary map: {}", e)); + logger::write_error(format!("Error clearing the connection summary map and failed authenticate summary map: {e}")); } start_time = Instant::now(); } @@ -249,7 +249,7 @@ impl ProxyAgentStatusTask { { Ok(count) => count, Err(e) => { - logger::write_error(format!("Error getting connection count: {}", e)); + logger::write_error(format!("Error getting connection count: {e}")); 0 } }, @@ -267,7 +267,7 @@ impl ProxyAgentStatusTask { { Ok(summary) => summary, Err(e) => { - logger::write_error(format!("Error getting connection summary: {}", e)); + logger::write_error(format!("Error getting connection summary: {e}")); vec![] } }, @@ -278,7 +278,7 @@ impl ProxyAgentStatusTask { { Ok(summary) => summary, Err(e) => { - logger::write_error(format!("Error getting failed connection summary: {}", e)); + logger::write_error(format!("Error getting failed connection summary: {e}")); vec![] } }, @@ -289,8 +289,7 @@ impl ProxyAgentStatusTask { let full_file_path = self.status_dir.join("status.json"); if let Err(e) = misc_helpers::json_write_to_file(&status, &full_file_path) { self.update_agent_status_message(format!( - "Error writing aggregate status to status file: {}", - e + "Error writing aggregate status to status file: {e}" )) .await; } else { diff --git a/proxy_agent/src/redirector.rs b/proxy_agent/src/redirector.rs index 6b71fa47..07a33433 100644 --- a/proxy_agent/src/redirector.rs +++ b/proxy_agent/src/redirector.rs @@ -138,8 +138,7 @@ impl Redirector { .await { logger::write_error(format!( - "Failed to set error status '{}' for redirector: {}", - message, e + "Failed to set error status '{message}' for redirector: {e}" )); } @@ -299,8 +298,7 @@ impl Redirector { .await { logger::write_error(format!( - "Failed to set error status '{}' for redirector: {}", - message, e + "Failed to set error status '{message}' for redirector: {e}" )); } } @@ -339,7 +337,7 @@ pub fn ip_to_string(ip: u32) -> String { pub fn string_to_ip(ip_str: &str) -> u32 { let ip_str_seg: Vec<&str> = ip_str.split('.').collect(); if ip_str_seg.len() != 4 { - logger::write_warning(format!("string_to_ip:: ip_str {} is invalid", ip_str)); + logger::write_warning(format!("string_to_ip:: ip_str {ip_str} is invalid")); return 0; } @@ -353,8 +351,7 @@ pub fn string_to_ip(ip_str: &str) -> u32 { } Err(e) => { logger::write_warning(format!( - "string_to_ip:: error parsing ip segment {} with error: {}", - ip_str, e + "string_to_ip:: error parsing ip segment {ip_str} with error: {e}" )); return 0; } diff --git a/proxy_agent/src/redirector/linux.rs b/proxy_agent/src/redirector/linux.rs index 6676ba39..f973428e 100644 --- a/proxy_agent/src/redirector/linux.rs +++ b/proxy_agent/src/redirector/linux.rs @@ -66,11 +66,11 @@ impl BpfObject { let key = sock_addr_skip_process_entry::from_pid(pid); let value = sock_addr_skip_process_entry::from_pid(pid); match skip_process_map.insert(key.to_array(), value.to_array(), 0) { - Ok(_) => logger::write(format!("skip_process_map updated with {}", pid)), + Ok(_) => logger::write(format!("skip_process_map updated with {pid}")), Err(err) => { return Err(Error::Bpf(BpfErrorType::UpdateBpfMapHashMap( skip_process_map_name.to_string(), - format!("insert pid: {}", pid), + format!("insert pid: {pid}"), err.to_string(), ))); } @@ -156,8 +156,7 @@ impl BpfObject { match program.attach(cgroup, CgroupAttachMode::Single) { Ok(link_id) => { logger::write(format!( - "connect4 program attached with id {:?}.", - link_id + "connect4 program attached with id {link_id:?}." )); } Err(err) => { @@ -211,8 +210,7 @@ impl BpfObject { match program.attach("tcp_connect", 0) { Ok(link_id) => { logger::write(format!( - "tcp_v4_connect program attached with id {:?}.", - link_id + "tcp_v4_connect program attached with id {link_id:?}." )); } Err(err) => { @@ -340,8 +338,7 @@ impl BpfObject { } Err(err) => { logger::write(format!( - "Failed to load HashMap 'policy_map' with error: {}", - err + "Failed to load HashMap 'policy_map' with error: {err}" )); } }, @@ -360,7 +357,7 @@ impl BpfObject { audit_map.remove(&key.to_array()).map_err(|err| { Error::Bpf(BpfErrorType::MapDeleteElem( source_port.to_string(), - format!("Error: {}", err), + format!("Error: {err}"), )) })?; } @@ -402,7 +399,7 @@ impl super::Redirector { Err(e) => { event_logger::write_event( LoggerLevel::Warn, - format!("Failed to get the cgroup2 mount path {}, fallback to use the cgroup2 path from config file.", e), + format!("Failed to get the cgroup2 mount path {e}, fallback to use the cgroup2 path from config file."), "start", "redirector/linux", logger::AGENT_LOGGER_KEY, @@ -411,7 +408,7 @@ impl super::Redirector { } }; if let Err(e) = bpf_object.attach_cgroup_program(cgroup2_path) { - let message = format!("Failed to attach cgroup program for redirection. {}", e); + let message = format!("Failed to attach cgroup program for redirection. {e}"); event_logger::write_event( LoggerLevel::Warn, message.to_string(), diff --git a/proxy_agent/src/redirector/windows.rs b/proxy_agent/src/redirector/windows.rs index 7daf8092..cf23a3b8 100644 --- a/proxy_agent/src/redirector/windows.rs +++ b/proxy_agent/src/redirector/windows.rs @@ -122,8 +122,7 @@ pub fn get_audit_from_redirect_context(raw_socket_id: usize) -> Result Result bool { if let Err(e) = EBPF_API.set(ebpf_api) { event_logger::write_event( LoggerLevel::Error, - format!("{}", e), + format!("{e}"), "try_load_ebpf_api", "redirector", logger::AGENT_LOGGER_KEY, @@ -61,7 +61,7 @@ fn init_ebpf_lib() -> Option { if let Err(e) = EBPF_API_VERSION.set(v) { event_logger::write_event( LoggerLevel::Error, - format!("{}", e), + format!("{e}"), "EBPF_API_VERSION.set", "redirector", logger::AGENT_LOGGER_KEY, @@ -71,7 +71,7 @@ fn init_ebpf_lib() -> Option { Err(e) => { event_logger::write_event( LoggerLevel::Warn, - format!("{}", e), + format!("{e}"), "get_file_product_version", "redirector", logger::AGENT_LOGGER_KEY, @@ -85,7 +85,7 @@ fn init_ebpf_lib() -> Option { Err(e) => { event_logger::write_event( LoggerLevel::Warn, - format!("{}", e), + format!("{e}"), "load_ebpf_api", "redirector", logger::AGENT_LOGGER_KEY, @@ -101,7 +101,7 @@ fn init_ebpf_lib() -> Option { Err(e) => { event_logger::write_event( LoggerLevel::Warn, - format!("{}", e), + format!("{e}"), "load_ebpf_api", "redirector", logger::AGENT_LOGGER_KEY, diff --git a/proxy_agent/src/redirector/windows/bpf_prog.rs b/proxy_agent/src/redirector/windows/bpf_prog.rs index 27b6c8f8..71e51968 100644 --- a/proxy_agent/src/redirector/windows/bpf_prog.rs +++ b/proxy_agent/src/redirector/windows/bpf_prog.rs @@ -60,10 +60,7 @@ impl BpfObject { let error_code = libbpf_get_error()?; return Err(Error::Bpf(BpfErrorType::OpenBpfObject( bpf_file_path.display().to_string(), - format!( - "bpf_object__open return null pointer with error code '{}'", - error_code - ), + format!("bpf_object__open return null pointer with error code '{error_code}'",), ))); } @@ -84,7 +81,7 @@ impl BpfObject { } else { return Err(Error::Bpf(BpfErrorType::LoadBpfObject( bpf_file_path.display().to_string(), - format!("bpf_object__load return with error code '{}'", result), + format!("bpf_object__load return with error code '{result}'"), ))); } @@ -109,7 +106,7 @@ impl BpfObject { let program_name = "authorize_connect4"; let connect4_program = match bpf_object__find_program_by_name(self.0, program_name) { Ok(p) => { - logger::write_information(format!("Found {} program.", program_name)); + logger::write_information(format!("Found {program_name} program.")); p } Err(e) => { @@ -141,7 +138,7 @@ impl BpfObject { if r != 0 { return Err(Error::Bpf(BpfErrorType::AttachBpfProgram( program_name.to_string(), - format!("ebpf_prog_attach return with error code '{}'", r), + format!("ebpf_prog_attach return with error code '{r}'"), ))); } logger::write_information( @@ -157,7 +154,7 @@ impl BpfObject { if r != 0 { return Err(Error::Bpf(BpfErrorType::AttachBpfProgram( program_name.to_string(), - format!("bpf_link_destroy return with error code '{}'", r), + format!("bpf_link_destroy return with error code '{r}'"), ))); } logger::write_information("Success destroyed link.".to_string()); @@ -165,7 +162,7 @@ impl BpfObject { Err(e) => { return Err(Error::Bpf(BpfErrorType::AttachBpfProgram( program_name.to_string(), - format!("bpf_link_destroy return with error '{}'", e), + format!("bpf_link_destroy return with error '{e}'"), ))); } } @@ -173,7 +170,7 @@ impl BpfObject { Err(e) => { return Err(Error::Bpf(BpfErrorType::AttachBpfProgram( program_name.to_string(), - format!("bpf_link_disconnect return with error '{}'", e), + format!("bpf_link_disconnect return with error '{e}'"), ))); } } @@ -181,7 +178,7 @@ impl BpfObject { Err(e) => { return Err(Error::Bpf(BpfErrorType::AttachBpfProgram( program_name.to_string(), - format!("ebpf_prog_attach return with error '{}'", e), + format!("ebpf_prog_attach return with error '{e}'"), ))); } } @@ -231,14 +228,14 @@ impl BpfObject { Error::Bpf(BpfErrorType::UpdateBpfMapHashMap( map_name.to_string(), endpoint_name.to_string(), - format!("bpf_map_update_elem returned error {}", e), + format!("bpf_map_update_elem returned error {e}"), )) })?; if result != 0 { return Err(Error::Bpf(BpfErrorType::UpdateBpfMapHashMap( map_name.to_string(), endpoint_name.to_string(), - format!("bpf_map_update_elem returned error code {}", result), + format!("bpf_map_update_elem returned error code {result}"), ))); } @@ -260,7 +257,7 @@ impl BpfObject { return; } if let Err(e) = bpf_object__close(self.0) { - logger::write_error(format!("bpf_object__close with error: {}", e)); + logger::write_error(format!("bpf_object__close with error: {e}")); } self.0 = std::ptr::null::().cast_mut(); @@ -297,14 +294,14 @@ impl BpfObject { .map_err(|e| { Error::Bpf(BpfErrorType::MapLookupElem( source_port.to_string(), - format!("Error: {}", e), + format!("Error: {e}"), )) })?; if result != 0 { return Err(Error::Bpf(BpfErrorType::MapLookupElem( source_port.to_string(), - format!("Result: {}", result), + format!("Result: {result}"), ))); } @@ -341,15 +338,15 @@ impl BpfObject { .map_err(|e| { Error::Bpf(BpfErrorType::UpdateBpfMapHashMap( map_name.to_string(), - format!("insert pid: {}", pid), - format!("bpf_map_update_elem returned error {}", e), + format!("insert pid: {pid}"), + format!("bpf_map_update_elem returned error {e}"), )) })?; if result != 0 { return Err(Error::Bpf(BpfErrorType::UpdateBpfMapHashMap( map_name.to_string(), - format!("insert pid: {}", pid), - format!("bpf_map_update_elem returned error code {}", result), + format!("insert pid: {pid}"), + format!("bpf_map_update_elem returned error code {result}"), ))); } @@ -374,14 +371,14 @@ impl BpfObject { bpf_map_delete_elem(map_fd, &key as *const destination_entry_t as *const c_void) .map_err(|e| { Error::Bpf(BpfErrorType::MapDeleteElem( - format!("dest_ipv4: {}, dest_port: {}", dest_ipv4, dest_port), - format!("Error: {}", e), + format!("dest_ipv4: {dest_ipv4}, dest_port: {dest_port}"), + format!("Error: {e}"), )) })?; if result != 0 { return Err(Error::Bpf(BpfErrorType::MapDeleteElem( - format!("dest_ipv4: {}, dest_port: {}", dest_ipv4, dest_port), - format!("Result: {}", result), + format!("dest_ipv4: {dest_ipv4}, dest_port: {dest_port}"), + format!("Result: {result}"), ))); } @@ -400,14 +397,14 @@ impl BpfObject { .map_err(|e| { Error::Bpf(BpfErrorType::MapDeleteElem( source_port.to_string(), - format!("Error: {}", e), + format!("Error: {e}"), )) })?; if result != 0 { return Err(Error::Bpf(BpfErrorType::MapDeleteElem( source_port.to_string(), - format!("Result: {}", result), + format!("Result: {result}"), ))); } diff --git a/proxy_agent/src/service.rs b/proxy_agent/src/service.rs index 65fec2e1..b091d153 100644 --- a/proxy_agent/src/service.rs +++ b/proxy_agent/src/service.rs @@ -27,11 +27,17 @@ use std::time::Duration; /// service::start_service(shared_state).await; /// ``` pub async fn start_service(shared_state: SharedState) { + if let Some(max_log_level) = config::get_file_log_level_for_system_events() { + logger_manager::set_system_logger( + max_log_level, + constants::WINDOWS_AZURE, + constants::PROXY_AGENT_SERVICE_NAME, + ); + } + let log_folder = config::get_logs_dir(); if log_folder == PathBuf::from("") { - logger::write_console_log( - "The log folder is not set, skip write to GPA managed file log.".to_string(), - ); + println!("The log folder is not set, skip write to GPA managed file log."); } else { setup_loggers(log_folder, config::get_file_log_level()); } @@ -78,8 +84,6 @@ pub async fn start_service(shared_state: SharedState) { } fn setup_loggers(log_folder: PathBuf, max_logger_level: LoggerLevel) { - logger_manager::set_logger_level(max_logger_level); - let agent_logger = RollingLogger::create_new( log_folder.clone(), "ProxyAgent.log".to_string(), @@ -98,7 +102,11 @@ fn setup_loggers(log_folder: PathBuf, max_logger_level: LoggerLevel) { ConnectionLogger::CONNECTION_LOGGER_KEY.to_string(), connection_logger, ); - logger_manager::set_loggers(loggers, logger::AGENT_LOGGER_KEY.to_string()); + logger_manager::set_loggers( + loggers, + logger::AGENT_LOGGER_KEY.to_string(), + max_logger_level, + ); } /// Start the service and wait until the service is stopped. diff --git a/proxy_agent/src/service/windows.rs b/proxy_agent/src/service/windows.rs index 1a44323b..d62170c3 100644 --- a/proxy_agent/src/service/windows.rs +++ b/proxy_agent/src/service/windows.rs @@ -40,8 +40,7 @@ pub async fn run_service() -> Result<()> { }; if let Err(e) = status_handle.set_service_status(stop_state) { logger::write_error(format!( - "Failed to set service status to Stopped: {}", - e + "Failed to set service status to Stopped: {e}" )); } } else { diff --git a/proxy_agent/src/shared_state/agent_status_wrapper.rs b/proxy_agent/src/shared_state/agent_status_wrapper.rs index bfffaab0..f540c4e5 100644 --- a/proxy_agent/src/shared_state/agent_status_wrapper.rs +++ b/proxy_agent/src/shared_state/agent_status_wrapper.rs @@ -207,7 +207,7 @@ impl AgentStatusSharedState { } } if response.send(updated).is_err() { - logger::write_warning(format!("Failed to send response to AgentStatusAction::SetStatusMessage for module {:?}", module)); + logger::write_warning(format!("Failed to send response to AgentStatusAction::SetStatusMessage for module {module:?}")); } } AgentStatusAction::GetStatusMessage { module, response } => { @@ -227,8 +227,7 @@ impl AgentStatusSharedState { }; if let Err(message) = response.send(message) { logger::write_warning(format!( - "Failed to send response to AgentStatusAction::GetStatusMessage for module '{:?}' with message '{:?}'", - module,message + "Failed to send response to AgentStatusAction::GetStatusMessage for module '{module:?}' with message '{message:?}'" )); } } @@ -258,7 +257,7 @@ impl AgentStatusSharedState { } } if let Err(state) = response.send(state) { - logger::write_warning(format!("Failed to send response to AgentStatusAction::SetState '{:?}' for module '{:?}'", state, module)); + logger::write_warning(format!("Failed to send response to AgentStatusAction::SetState '{state:?}' for module '{module:?}'")); } } AgentStatusAction::GetState { module, response } => { @@ -272,8 +271,7 @@ impl AgentStatusSharedState { }; if let Err(state) = response.send(state) { logger::write_warning(format!( - "Failed to send response to AgentStatusAction::GetState for module '{:?}' with state '{:?}'", - module,state + "Failed to send response to AgentStatusAction::GetState for module '{module:?}' with state '{state:?}'" )); } } @@ -342,8 +340,7 @@ impl AgentStatusSharedState { AgentStatusAction::GetConnectionCount { response } => { if let Err(count) = response.send(http_connection_count) { logger::write_warning(format!( - "Failed to send response to AgentStatusAction::GetConnectionCount with count '{:?}'", - count + "Failed to send response to AgentStatusAction::GetConnectionCount with count '{count:?}'" )); } } @@ -352,8 +349,7 @@ impl AgentStatusSharedState { http_connection_count = http_connection_count.overflowing_add(1).0; if let Err(count) = response.send(http_connection_count) { logger::write_warning(format!( - "Failed to send response to AgentStatusAction::IncreaseConnectionCount with count '{:?}'", - count + "Failed to send response to AgentStatusAction::IncreaseConnectionCount with count '{count:?}'" )); } } @@ -362,8 +358,7 @@ impl AgentStatusSharedState { tcp_connection_count = tcp_connection_count.overflowing_add(1).0; if let Err(count) = response.send(tcp_connection_count) { logger::write_warning(format!( - "Failed to send response to AgentStatusAction::IncreaseTcpConnectionCount with count '{:?}'", - count + "Failed to send response to AgentStatusAction::IncreaseTcpConnectionCount with count '{count:?}'" )); } } @@ -483,13 +478,13 @@ impl AgentStatusSharedState { .await .map_err(|e| { Error::SendError( - format!("AgentStatusAction::GetState ({:?})", module), + format!("AgentStatusAction::GetState ({module:?})"), e.to_string(), ) })?; response_rx .await - .map_err(|e| Error::RecvError(format!("AgentStatusAction::GetState ({:?})", module), e)) + .map_err(|e| Error::RecvError(format!("AgentStatusAction::GetState ({module:?})"), e)) } pub async fn set_module_state( @@ -507,13 +502,13 @@ impl AgentStatusSharedState { .await .map_err(|e| { Error::SendError( - format!("AgentStatusAction::SetState ({:?})", module), + format!("AgentStatusAction::SetState ({module:?})"), e.to_string(), ) })?; response_rx .await - .map_err(|e| Error::RecvError(format!("AgentStatusAction::SetState ({:?})", module), e)) + .map_err(|e| Error::RecvError(format!("AgentStatusAction::SetState ({module:?})"), e)) } pub async fn get_module_status_message(&self, module: AgentStatusModule) -> Result { @@ -526,13 +521,13 @@ impl AgentStatusSharedState { .await .map_err(|e| { Error::SendError( - format!("AgentStatusAction::GetStatusMessage ({:?})", module), + format!("AgentStatusAction::GetStatusMessage ({module:?})"), e.to_string(), ) })?; response_rx.await.map_err(|e| { Error::RecvError( - format!("AgentStatusAction::GetStatusMessage ({:?})", module), + format!("AgentStatusAction::GetStatusMessage ({module:?})"), e, ) }) @@ -560,13 +555,13 @@ impl AgentStatusSharedState { .await .map_err(|e| { Error::SendError( - format!("AgentStatusAction::SetStatusMessage ({:?})", module), + format!("AgentStatusAction::SetStatusMessage ({module:?})"), e.to_string(), ) })?; let update = response_rx.await.map_err(|e| { Error::RecvError( - format!("AgentStatusAction::SetStatusMessage ({:?})", module), + format!("AgentStatusAction::SetStatusMessage ({module:?})"), e, ) })?; @@ -577,7 +572,7 @@ impl AgentStatusSharedState { LoggerLevel::Warn, message, "set_module_status_message", - &format!("{:?}", module), + &format!("{module:?}"), logger::AGENT_LOGGER_KEY, ); } @@ -588,7 +583,7 @@ impl AgentStatusSharedState { let state = match self.get_module_state(module.clone()).await { Ok(state) => state, Err(e) => { - logger::write_warning(format!("Error getting module '{:?}' status: {}", module, e)); + logger::write_warning(format!("Error getting module '{module:?}' status: {e}")); ModuleState::UNKNOWN } }; @@ -596,8 +591,7 @@ impl AgentStatusSharedState { Ok(message) => message, Err(e) => { logger::write_warning(format!( - "Error getting module '{:?}' status message: {}", - module, e + "Error getting module '{module:?}' status message: {e}" )); super::UNKNOWN_STATUS_MESSAGE.to_string() } @@ -606,11 +600,10 @@ impl AgentStatusSharedState { event_logger::write_event( LoggerLevel::Warn, format!( - "Status message is too long, truncating to {} characters. Message: {}", - MAX_STATUS_MESSAGE_LENGTH, message + "Status message is too long, truncating to {MAX_STATUS_MESSAGE_LENGTH} characters. Message: {message}" ), "get_status", - &format!("{:?}", module), + &format!("{state:?}"), logger::AGENT_LOGGER_KEY, ); message = format!("{}...", &message[0..MAX_STATUS_MESSAGE_LENGTH]); diff --git a/proxy_agent/src/shared_state/key_keeper_wrapper.rs b/proxy_agent/src/shared_state/key_keeper_wrapper.rs index c7eed7e9..649b15e6 100644 --- a/proxy_agent/src/shared_state/key_keeper_wrapper.rs +++ b/proxy_agent/src/shared_state/key_keeper_wrapper.rs @@ -160,16 +160,14 @@ impl KeyKeeperSharedState { current_secure_channel_state = state.to_string(); if response.send(()).is_err() { logger::write_warning(format!( - "Failed to send response to KeyKeeperAction::SetSecureChannelState '{}' ", - state + "Failed to send response to KeyKeeperAction::SetSecureChannelState '{state}' " )); } } Some(KeyKeeperAction::GetSecureChannelState { response }) => { if let Err(state) = response.send(current_secure_channel_state.clone()) { logger::write_warning(format!( - "Failed to send response to KeyKeeperAction::GetSecureChannelState '{}'", - state + "Failed to send response to KeyKeeperAction::GetSecureChannelState '{state}'" )); } } @@ -177,16 +175,14 @@ impl KeyKeeperSharedState { wireserver_rule_id = rule_id.to_string(); if response.send(()).is_err() { logger::write_warning(format!( - "Failed to send response to KeyKeeperAction::SetWireServerRuleId '{}'", - rule_id + "Failed to send response to KeyKeeperAction::SetWireServerRuleId '{rule_id}'" )); } } Some(KeyKeeperAction::GetWireServerRuleId { response }) => { if let Err(rule_id) = response.send(wireserver_rule_id.clone()) { logger::write_warning(format!( - "Failed to send response to KeyKeeperAction::GetWireServerRuleId '{}'", - rule_id + "Failed to send response to KeyKeeperAction::GetWireServerRuleId '{rule_id}'" )); } } @@ -194,24 +190,21 @@ impl KeyKeeperSharedState { imds_rule_id = rule_id.to_string(); if response.send(()).is_err() { logger::write_warning(format!( - "Failed to send response to KeyKeeperAction::SetImdsRuleId '{}'", - rule_id + "Failed to send response to KeyKeeperAction::SetImdsRuleId '{rule_id}'" )); } } Some(KeyKeeperAction::GetImdsRuleId { response }) => { if let Err(rule_id) = response.send(imds_rule_id.clone()) { logger::write_warning(format!( - "Failed to send response to KeyKeeperAction::GetImdsRuleId '{}'", - rule_id + "Failed to send response to KeyKeeperAction::GetImdsRuleId '{rule_id}'" )); } } Some(KeyKeeperAction::GetHostGARuleId { response }) => { if let Err(rule_id) = response.send(hostga_rule_id.clone()) { logger::write_warning(format!( - "Failed to send response to KeyKeeperAction::GetHostGARuleId '{}'", - rule_id + "Failed to send response to KeyKeeperAction::GetHostGARuleId '{rule_id}'" )); } } @@ -219,8 +212,7 @@ impl KeyKeeperSharedState { hostga_rule_id = rule_id.to_string(); if response.send(()).is_err() { logger::write_warning(format!( - "Failed to send response to KeyKeeperAction::SetHostGARuleId '{}'", - rule_id + "Failed to send response to KeyKeeperAction::SetHostGARuleId '{rule_id}'" )); } } diff --git a/proxy_agent/src/shared_state/provision_wrapper.rs b/proxy_agent/src/shared_state/provision_wrapper.rs index e3cc1696..e9e92609 100644 --- a/proxy_agent/src/shared_state/provision_wrapper.rs +++ b/proxy_agent/src/shared_state/provision_wrapper.rs @@ -81,8 +81,7 @@ impl ProvisionSharedState { provision_state |= state; if let Err(new_state) = response.send(provision_state.clone()) { logger::write_warning(format!( - "Failed to send response to ProvisionAction::UpdateState with new state '{:?}'", - new_state + "Failed to send response to ProvisionAction::UpdateState with new state '{new_state:?}'" )); } } @@ -90,16 +89,14 @@ impl ProvisionSharedState { provision_state &= !state; if let Err(new_state) = response.send(provision_state.clone()) { logger::write_warning(format!( - "Failed to send response to ProvisionAction::ResetState with new state '{:?}'", - new_state + "Failed to send response to ProvisionAction::ResetState with new state '{new_state:?}'" )); } } ProvisionAction::GetState { response } => { if let Err(state) = response.send(provision_state.clone()) { logger::write_warning(format!( - "Failed to send response to ProvisionAction::GetState with state '{:?}'", - state + "Failed to send response to ProvisionAction::GetState with state '{state:?}'" )); } } @@ -114,8 +111,7 @@ impl ProvisionSharedState { response.send(provision_event_log_threads_initialized) { logger::write_warning(format!( - "Failed to send response to ProvisionAction::GetEventLogsThreadsInitialized with initialized '{:?}'", - initialized + "Failed to send response to ProvisionAction::GetEventLogsThreadsInitialized with initialized '{initialized:?}'" )); } } @@ -135,8 +131,7 @@ impl ProvisionSharedState { ProvisionAction::GetProvisionFinished { response } => { if let Err(finished) = response.send(provision_finished_time_tick) { logger::write_warning(format!( - "Failed to send response to ProvisionAction::GetProvisionFinished with finished '{:?}'", - finished + "Failed to send response to ProvisionAction::GetProvisionFinished with finished '{finished:?}'" )); } } diff --git a/proxy_agent/src/shared_state/proxy_server_wrapper.rs b/proxy_agent/src/shared_state/proxy_server_wrapper.rs index ce50c452..e9ef02a2 100644 --- a/proxy_agent/src/shared_state/proxy_server_wrapper.rs +++ b/proxy_agent/src/shared_state/proxy_server_wrapper.rs @@ -55,13 +55,13 @@ impl ProxyServerSharedState { let id = user.logon_id; users.insert(id, user); if response.send(()).is_err() { - logger::write_warning(format!("Failed to send response to ProxyServerAction::AddUser with id '{}'", id)); + logger::write_warning(format!("Failed to send response to ProxyServerAction::AddUser with id '{id}'")); } } ProxyServerAction::GetUser { user_id, response } => { let user = users.get(&user_id).cloned(); if response.send(user).is_err() { - logger::write_warning(format!("Failed to send response to ProxyServerAction::GetUser with id '{}'", user_id)); + logger::write_warning(format!("Failed to send response to ProxyServerAction::GetUser with id '{user_id}'")); } } #[cfg(test)] diff --git a/proxy_agent/src/shared_state/redirector_wrapper.rs b/proxy_agent/src/shared_state/redirector_wrapper.rs index 0f63d9b2..a1e9d2dd 100644 --- a/proxy_agent/src/shared_state/redirector_wrapper.rs +++ b/proxy_agent/src/shared_state/redirector_wrapper.rs @@ -61,16 +61,14 @@ impl RedirectorSharedState { local_port = new_local_port; if response.send(()).is_err() { logger::write_warning(format!( - "Failed to send response to RedirectorAction::SetLocalPort '{}'", - new_local_port + "Failed to send response to RedirectorAction::SetLocalPort '{new_local_port}'" )); } } RedirectorAction::GetLocalPort { response } => { if let Err(port) = response.send(local_port) { logger::write_warning(format!( - "Failed to send response to RedirectorAction::GetLocalPort '{}'", - port + "Failed to send response to RedirectorAction::GetLocalPort '{port}'" )); } } diff --git a/proxy_agent/src/shared_state/telemetry_wrapper.rs b/proxy_agent/src/shared_state/telemetry_wrapper.rs index c18211ac..f386de37 100644 --- a/proxy_agent/src/shared_state/telemetry_wrapper.rs +++ b/proxy_agent/src/shared_state/telemetry_wrapper.rs @@ -46,16 +46,14 @@ impl TelemetrySharedState { vm_meta_data = meta_data.clone(); if response.send(()).is_err() { logger::write_warning(format!( - "Failed to send response to TelemetryAction::SetVmMetaData '{:?}'", - meta_data, + "Failed to send response to TelemetryAction::SetVmMetaData '{meta_data:?}'" )); } } Some(TelemetryAction::GetVmMetaData { response }) => { if let Err(meta_data) = response.send(vm_meta_data.clone()) { logger::write_warning(format!( - "Failed to send response to TelemetryAction::GetVmMetaData '{:?}'", - meta_data, + "Failed to send response to TelemetryAction::GetVmMetaData '{meta_data:?}'" )); } } diff --git a/proxy_agent/src/telemetry/event_reader.rs b/proxy_agent/src/telemetry/event_reader.rs index 5d1dbc2d..06baadc7 100644 --- a/proxy_agent/src/telemetry/event_reader.rs +++ b/proxy_agent/src/telemetry/event_reader.rs @@ -171,7 +171,7 @@ impl EventReader { logger::write("success updated the vm metadata.".to_string()); } Err(e) => { - logger::write_warning(format!("Failed to read vm metadata with error {}.", e)); + logger::write_warning(format!("Failed to read vm metadata with error {e}.")); } } @@ -198,8 +198,7 @@ impl EventReader { .process_events_and_clean(files, wire_server_client, vm_meta_data) .await; let message = format!( - "Telemetry event reader sent {} events from {} files", - event_count, file_count + "Telemetry event reader sent {event_count} events from {file_count} files" ); logger::write(message); } @@ -248,7 +247,7 @@ impl EventReader { .set_vm_meta_data(Some(vm_meta_data.clone())) .await?; - logger::write(format!("Updated VM Metadata: {:?}", vm_meta_data)); + logger::write(format!("Updated VM Metadata: {vm_meta_data:?}")); Ok(()) } @@ -301,9 +300,8 @@ impl EventReader { match serde_json::to_string(&event) { Ok(json) => { logger::write_warning(format!( - "Event data too large. Not sending to wire-server. Event: {}.", - json - )); + "Event data too large. Not sending to wire-server. Event: {json}.", + )); } Err(_) => { logger::write_warning( @@ -345,8 +343,7 @@ impl EventReader { } Err(e) => { logger::write_warning(format!( - "Failed to send telemetry data to host with error: {}", - e + "Failed to send telemetry data to host with error: {e}" )); // wait 15 seconds and retry tokio::time::sleep(Duration::from_secs(15)).await; diff --git a/proxy_agent_extension/Cargo.toml b/proxy_agent_extension/Cargo.toml index ad73f22c..6995ba67 100644 --- a/proxy_agent_extension/Cargo.toml +++ b/proxy_agent_extension/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ProxyAgentExt" -version = "1.0.31" # always 3-number version +version = "1.0.32" # always 3-number version edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/proxy_agent_extension/src/common.rs b/proxy_agent_extension/src/common.rs index 1c9ef83f..fea6c0b5 100644 --- a/proxy_agent_extension/src/common.rs +++ b/proxy_agent_extension/src/common.rs @@ -61,7 +61,7 @@ pub fn report_heartbeat(heartbeat_file_path: PathBuf, heartbeat_obj: structs::He )); } Err(e) => { - logger::write(format!("Error in creating HeartBeat file: {:?}", e)); + logger::write(format!("Error in creating HeartBeat file: {e:?}")); } } } @@ -69,7 +69,7 @@ pub fn report_heartbeat(heartbeat_file_path: PathBuf, heartbeat_obj: structs::He pub fn get_file_path(status_folder: PathBuf, config_seq_no: &str, file_extension: &str) -> PathBuf { let mut file: PathBuf = status_folder; if let Err(e) = misc_helpers::try_create_folder(&file) { - logger::write(format!("Error in creating folder: {:?}", e)); + logger::write(format!("Error in creating folder: {e:?}")); } file.push(config_seq_no); file.set_extension(file_extension); @@ -107,10 +107,10 @@ pub fn report_status( // TODO: retry if write failed match fs::write(&status_file, root_status) { Ok(_) => { - logger::write(format!("Status file created: {:?}", status_file)); + logger::write(format!("Status file created: {status_file:?}")); } Err(e) => { - logger::write(format!("Error in creating status file: {:?}", e)); + logger::write(format!("Error in creating status file: {e:?}")); } } } @@ -128,12 +128,9 @@ pub fn update_current_seq_no(config_seq_no: &str, exe_path: &Path) -> Result { if seq_no != *config_seq_no { - logger::write(format!( - "updating seq no from {} to {}", - seq_no, config_seq_no - )); + logger::write(format!("updating seq no from {seq_no} to {config_seq_no}")); if let Err(e) = fs::write(¤t_seq_no_stored_file, config_seq_no) { - logger::write(format!("Error in writing seq no to file: {:?}", e)); + logger::write(format!("Error in writing seq no to file: {e:?}")); return Err(Error::Io(e)); } } else { @@ -148,7 +145,7 @@ pub fn update_current_seq_no(config_seq_no: &str, exe_path: &Path) -> Result String { let current_seq_no_stored_file: PathBuf = exe_path.join(constants::CURRENT_SEQ_NO_FILE); match fs::read_to_string(current_seq_no_stored_file) { Ok(seq_no) => { - logger::write(format!("Current seq no: {}", seq_no)); + logger::write(format!("Current seq no: {seq_no}")); seq_no } Err(e) => { - logger::write(format!("Error reading current seq no file: {:?}", e)); + logger::write(format!("Error reading current seq no file: {e:?}")); "".to_string() } } @@ -225,11 +222,28 @@ pub async fn start_event_logger() { logger::write("starting event logger".to_string()); tokio::spawn({ async move { - let interval: std::time::Duration = std::time::Duration::from_secs(60); + let interval = std::time::Duration::from_secs(60); let max_event_file_count: usize = 50; let exe_path = misc_helpers::get_current_exe_dir(); - let event_folder = - PathBuf::from(get_handler_environment(&exe_path).eventsFolder.to_string()); + // Get the events folder from the handler environment + let events_folder_str = match get_handler_environment(&exe_path).eventsFolder { + Some(folder) => folder, + None => { + logger::write( + "No events folder specified, skipping event logger start.".to_string(), + ); + return; + } + }; + let event_folder = PathBuf::from(events_folder_str.clone()); + // Check if the events folder exists + if !event_folder.exists() { + logger::write(format!( + "Events folder does not exist: {event_folder:?}. Skipping event logger start." + )); + return; + } + telemetry::event_logger::start(event_folder, interval, max_event_file_count, |_| { async { // do nothing @@ -337,10 +351,9 @@ mod tests { _ = fs::remove_dir_all(&temp_test_path); _ = misc_helpers::try_create_folder(&temp_test_path); - //Add HandlerEnvironment.json in the temp directory let handler_env_file = temp_test_path.to_path_buf().join("HandlerEnvironment.json"); - //Create raw handler environment json string + // Case 1: eventsFolder exists let json_handler_linux: &str = r#"[{ "version": 1.0, "handlerEnvironment": { @@ -352,22 +365,53 @@ mod tests { } }]"#; - //Deserialize handler environment json string let handler_env_obj: Vec = serde_json::from_str(json_handler_linux).unwrap(); + _ = misc_helpers::json_write_to_file(&handler_env_obj, &handler_env_file); + + let events_folder = temp_test_path.join("test_kusto"); + _ = misc_helpers::try_create_folder(&events_folder); + assert!(events_folder.exists(), "Events folder should exist"); - //Write the deserialized json object to HandlerEnvironment.json file + let handler_env = super::get_handler_environment(&temp_test_path); + assert_eq!(handler_env.eventsFolder, Some("test_kusto".to_string())); + + // Case 2: eventsFolder does NOT exist + _ = fs::remove_dir_all(&events_folder); + assert!(!events_folder.exists(), "Events folder should NOT exist"); + let handler_env = super::get_handler_environment(&temp_test_path); + assert_eq!(handler_env.eventsFolder, Some("test_kusto".to_string())); + + // Case 3: eventsFolder is not specified (None) + let json_handler_no_events: &str = r#"[{ + "version": 1.0, + "handlerEnvironment": { + "logFolder": "log", + "configFolder": "config", + "statusFolder": "status", + "heartbeatFile": "heartbeat.json" + } + }]"#; + let handler_env_obj: Vec = serde_json::from_str(json_handler_no_events).unwrap(); _ = misc_helpers::json_write_to_file(&handler_env_obj, &handler_env_file); + let handler_env = super::get_handler_environment(&temp_test_path); + assert_eq!(handler_env.eventsFolder, None); + // Case 4: eventsFolder is an empty string + let json_handler_empty_events: &str = r#"[{ + "version": 1.0, + "handlerEnvironment": { + "logFolder": "log", + "configFolder": "config", + "statusFolder": "status", + "heartbeatFile": "heartbeat.json", + "eventsFolder": "" + } + }]"#; + let handler_env_obj: Vec = + serde_json::from_str(json_handler_empty_events).unwrap(); + _ = misc_helpers::json_write_to_file(&handler_env_obj, &handler_env_file); let handler_env = super::get_handler_environment(&temp_test_path); - assert_eq!(handler_env.logFolder, "log".to_string()); - assert_eq!(handler_env.configFolder, "config".to_string()); - assert_eq!(handler_env.statusFolder, "status".to_string()); - assert_eq!(handler_env.heartbeatFile, "heartbeat.json".to_string()); - assert_eq!(handler_env.eventsFolder, "test_kusto".to_string()); - assert_eq!(handler_env.deploymentid, None); - assert_eq!(handler_env.rolename, None); - assert_eq!(handler_env.instance, None); - assert_eq!(handler_env.hostResolverAddress, None); + assert_eq!(handler_env.eventsFolder, Some("".to_string())); _ = fs::remove_dir_all(&temp_test_path); } diff --git a/proxy_agent_extension/src/constants.rs b/proxy_agent_extension/src/constants.rs index fbd9d1bc..b25f5e71 100644 --- a/proxy_agent_extension/src/constants.rs +++ b/proxy_agent_extension/src/constants.rs @@ -47,12 +47,12 @@ pub const WINDOWS_SUPPORTED_VERSIONS: &str = "10.0.17763"; pub const INVALID_FILE_VERSION: &str = "0.0.0.0"; pub const SERVICE_START_RETRY_COUNT: u32 = 5; pub const STATUS_CODE_OK: i32 = 0; +pub const STATUS_CODE_NOT_OK: i32 = 4; // Non zero exit codes pub const EXIT_CODE_HANDLER_ENV_ERR: i32 = 1; pub const EXIT_CODE_SERVICE_UPDATE_ERR: i32 = 2; pub const EXIT_CODE_SERVICE_INSTALL_ERR: i32 = 3; -pub const STATUS_CODE_NOT_OK: i32 = 4; pub const EXIT_CODE_SERVICE_UNINSTALL_ERR: i32 = 5; pub const EXIT_CODE_NOT_SUPPORTED_OS_VERSION: i32 = 6; pub const EXIT_CODE_SERVICE_START_ERR: i32 = 7; diff --git a/proxy_agent_extension/src/handler_main.rs b/proxy_agent_extension/src/handler_main.rs index afa375a1..57918166 100644 --- a/proxy_agent_extension/src/handler_main.rs +++ b/proxy_agent_extension/src/handler_main.rs @@ -58,7 +58,7 @@ pub async fn program_start(command: ExtensionCommand, config_seq_no: String) { fn check_windows_os_version(version: Version) -> bool { match version.build { Some(build) => { - logger::write(format!("OS build version: {}", build)); + logger::write(format!("OS build version: {build}")); build >= constants::MIN_SUPPORTED_OS_BUILD } None => false, @@ -144,12 +144,11 @@ fn get_update_tag_file() -> PathBuf { fn update_tag_file_exists() -> bool { let update_tag_file = get_update_tag_file(); if update_tag_file.exists() { - logger::write(format!("update tag file exists: {:?}", update_tag_file)); + logger::write(format!("update tag file exists: {update_tag_file:?}")); true } else { logger::write(format!( - "update tag file does not exist: {:?}", - update_tag_file + "update tag file does not exist: {update_tag_file:?}" )); false } @@ -165,12 +164,12 @@ fn get_exe_parent() -> PathBuf { Path::new("") } }; - logger::write(format!("exe parent: {:?}", exe_parent)); + logger::write(format!("exe parent: {exe_parent:?}")); exe_parent.to_path_buf() } async fn handle_command(command: ExtensionCommand, config_seq_no: String) { - logger::write(format!("entering handle command: {:?}", command)); + logger::write(format!("entering handle command: {command:?}")); let status_folder = HANDLER_ENVIRONMENT.statusFolder.to_string(); let status_folder_path: PathBuf = PathBuf::from(&status_folder); match command { @@ -200,28 +199,26 @@ fn uninstall_handler() { match str::from_utf8(&output.stdout) { Ok(output_string) => { logger::write(format!( - "uninstalling GuestProxyAgent, output: {}", - output_string + "uninstalling GuestProxyAgent, output: {output_string}" )); } Err(e) => { - logger::write(format!("error in uninstalling GuestProxyAgent: {:?}", e)); + logger::write(format!("error in uninstalling GuestProxyAgent: {e:?}")); } } match str::from_utf8(&output.stderr) { Ok(output_string) => { logger::write(format!( - "output stderr for uninstall GuestProxyAgent: {}", - output_string + "output stderr for uninstall GuestProxyAgent: {output_string}" )); } Err(e) => { - logger::write(format!("error in uninstalling GuestProxyAgent: {:?}", e)); + logger::write(format!("error in uninstalling GuestProxyAgent: {e:?}")); } } } Err(e) => { - logger::write(format!("error in uninstalling GuestProxyAgent: {:?}", e)); + logger::write(format!("error in uninstalling GuestProxyAgent: {e:?}")); } } } @@ -240,7 +237,7 @@ async fn enable_handler(status_folder: PathBuf, config_seq_no: String) { } } Err(e) => { - logger::write(format!("error in updating current seq no: {:?}", e)); + logger::write(format!("error in updating current seq no: {e:?}")); process::exit(constants::EXIT_CODE_WRITE_CURRENT_SEQ_NO_ERROR); } } @@ -273,13 +270,12 @@ async fn enable_handler(status_folder: PathBuf, config_seq_no: String) { Ok(child) => { let pid = child.id(); logger::write(format!( - "ProxyAgentExt started with pid: {}, do not start new one.", - pid + "ProxyAgentExt started with pid: {pid}, do not start new one." )); break; } Err(e) => { - logger::write(format!("error in starting ProxyAgentExt: {:?}", e)); + logger::write(format!("error in starting ProxyAgentExt: {e:?}")); } } } @@ -294,7 +290,7 @@ async fn enable_handler(status_folder: PathBuf, config_seq_no: String) { "update tag file removed: {:?}", update_tag_file.to_path_buf() )), - Err(e) => logger::write(format!("error in removing update tag file: {:?}", e)), + Err(e) => logger::write(format!("error in removing update tag file: {e:?}")), } } } @@ -312,7 +308,7 @@ fn get_linux_extension_long_running_process() -> Option { for p in system.processes_by_exact_name(constants::EXTENSION_PROCESS_NAME) { let cmd = p.cmd(); - logger::write(format!("cmd: {:?}", cmd)); + logger::write(format!("cmd: {cmd:?}")); if cmd.len() == 1 { logger::write(format!("ProxyAgentExt running with pid: {}", p.pid())); return Some(p.pid().as_u32() as i32); @@ -334,10 +330,10 @@ async fn disable_handler() { let p = NixPid::from_raw(pid); match kill(p, SIGKILL) { Ok(_) => { - logger::write(format!("ProxyAgentExt process with pid: {} killed", pid)); + logger::write(format!("ProxyAgentExt process with pid: {pid} killed")); } Err(e) => { - logger::write(format!("error in killing ProxyAgentExt process: {:?}", e)); + logger::write(format!("error in killing ProxyAgentExt process: {e:?}")); } } } @@ -357,14 +353,14 @@ fn reset_handler() { "update tag file removed: {:?}", update_tag_file.to_path_buf() )), - Err(e) => logger::write(format!("error in removing update tag file: {:?}", e)), + Err(e) => logger::write(format!("error in removing update tag file: {e:?}")), } match fs::remove_file(&seq_no_file) { Ok(_) => logger::write(format!( "seq no file removed: {:?}", seq_no_file.to_path_buf() )), - Err(e) => logger::write(format!("error in removing seq no file: {:?}", e)), + Err(e) => logger::write(format!("error in removing seq no file: {e:?}")), } } @@ -374,7 +370,7 @@ async fn update_handler() { let version = match std::env::var("VERSION") { Ok(ver) => ver, Err(e) => { - logger::write(format!("error in getting VERSION from env::var: {:?}", e)); + logger::write(format!("error in getting VERSION from env::var: {e:?}")); process::exit(constants::EXIT_CODE_UPDATE_TO_VERSION_ENV_VAR_NOTFOUND); } }; @@ -403,7 +399,7 @@ async fn update_handler() { break; } Err(e) => { - logger::write(format!("error in creating update tag file: {:?}", e)); + logger::write(format!("error in creating update tag file: {e:?}")); } } } diff --git a/proxy_agent_extension/src/logger.rs b/proxy_agent_extension/src/logger.rs index bc4d3a1e..f12cec8e 100644 --- a/proxy_agent_extension/src/logger.rs +++ b/proxy_agent_extension/src/logger.rs @@ -19,11 +19,11 @@ pub fn init_logger(log_folder: String, log_name: &str) { ); let mut loggers = std::collections::HashMap::new(); loggers.insert(log_name.to_string(), logger); - logger_manager::set_loggers(loggers, log_name.to_string()); + logger_manager::set_loggers(loggers, log_name.to_string(), LoggerLevel::Trace); if !LOGGER_KEY.initialized() { if let Err(e) = LOGGER_KEY.set(log_name.to_string()) { - eprintln!("Failed to set logger key: {}", e); + eprintln!("Failed to set logger key: {e}"); }; } } diff --git a/proxy_agent_extension/src/main.rs b/proxy_agent_extension/src/main.rs index d51bc835..0093e49b 100644 --- a/proxy_agent_extension/src/main.rs +++ b/proxy_agent_extension/src/main.rs @@ -86,7 +86,7 @@ async fn main() { #[cfg(windows)] { if let Err(e) = service_dispatcher::start(constants::PLUGIN_NAME, ffi_service_main) { - logger::write(format!("Failed to start the service: {}", e)); + logger::write(format!("Failed to start the service: {e}")); } } #[cfg(not(windows))] @@ -104,7 +104,7 @@ fn proxy_agent_extension_windows_service_main(args: Vec) { .expect("You must provide the Tokio runtime handle before this function is called"); handle.block_on(async { if let Err(e) = service_main::windows_main::run_service(args).await { - logger::write(format!("Failed to start the service: {}", e)); + logger::write(format!("Failed to start the service: {e}")); } }); } diff --git a/proxy_agent_extension/src/service_main.rs b/proxy_agent_extension/src/service_main.rs index 7bfe1763..936f5338 100644 --- a/proxy_agent_extension/src/service_main.rs +++ b/proxy_agent_extension/src/service_main.rs @@ -75,7 +75,7 @@ async fn monitor_thread() { let handler_environment = common::get_handler_environment(&exe_path); let status_folder_path: PathBuf = handler_environment.statusFolder.to_string().into(); let mut cache_seq_no = String::new(); - let proxyagent_file_version_in_extension = get_proxy_agent_file_version_in_extension(); + let mut proxyagent_file_version_in_extension = String::new(); let mut service_state = ServiceState::default(); let mut status = StatusObj { name: constants::PLUGIN_NAME.to_string(), @@ -94,13 +94,38 @@ async fn monitor_thread() { let mut restored_in_error = false; let mut proxy_agent_update_reported: Option = None; loop { - let current_seq_no = common::get_current_seq_no(&exe_path); + let current_seq_no: String = common::get_current_seq_no(&exe_path); + if proxyagent_file_version_in_extension.is_empty() { + // File version of proxy agent service already downloaded by VM Agent + let path = common::get_proxy_agent_exe_path(); + proxyagent_file_version_in_extension = + match misc_helpers::get_proxy_agent_version(&path) { + Ok(version) => version, + Err(e) => { + let error_message = format!( + "Failed to get GuestProxyAgent version from file {} with error: {}", + misc_helpers::path_to_string(&path), + e + ); + logger::write(error_message.clone()); + status.formattedMessage.message = error_message; + status.code = constants::STATUS_CODE_NOT_OK; + status.status = status_state_obj.update_state(false); + common::report_status( + status_folder_path.to_path_buf(), + ¤t_seq_no, + &status, + ); + tokio::time::sleep(Duration::from_secs(15)).await; + continue; + } + }; + } if cache_seq_no != current_seq_no { telemetry::event_logger::write_event( LoggerLevel::Info, format!( - "Current seq_no: {} does not match cached seq no {}", - current_seq_no, cache_seq_no + "Current seq_no: {current_seq_no} does not match cached seq no {cache_seq_no}" ), "monitor_thread", "service_main", @@ -125,9 +150,8 @@ async fn monitor_thread() { // Call setup tool to install or update proxy agent service telemetry::event_logger::write_event( LoggerLevel::Info, - format!("Version mismatch between file versions. ProxyAgentService File Version: {}, ProxyAgent in Extension File Version: {}", - proxyagent_service_file_version, - proxyagent_file_version_in_extension), + format!("Version mismatch between file versions. ProxyAgentService File Version: {proxyagent_service_file_version}, ProxyAgent in Extension File Version: {proxyagent_file_version_in_extension}" + ), "monitor_thread", "service_main", logger_key, @@ -301,7 +325,7 @@ fn backup_proxyagent(setup_tool: &String) { Err(e) => { telemetry::event_logger::write_event( LoggerLevel::Info, - format!("Error in running Backup Proxy Agent command: {}", e), + format!("Error in running Backup Proxy Agent command: {e}"), "backup_proxyagent", "service_main", &logger::get_logger_key(), @@ -345,8 +369,7 @@ fn report_proxy_agent_aggregate_status( ); } Err(e) => { - let error_message = - format!("Error in reading proxy agent aggregate status file: {}", e); + let error_message = format!("Error in reading proxy agent aggregate status file: {e}"); write_state_event( constants::STATE_KEY_READ_PROXY_AGENT_STATUS_FILE, constants::ERROR_STATUS, @@ -409,7 +432,7 @@ fn extension_substatus( proxy_agent_aggregate_status_obj.version.to_string(); if proxy_agent_aggregate_status_file_version != *proxyagent_file_version_in_extension { status.status = status_state_obj.update_state(false); - let version_mismatch_message = format!("Proxy agent aggregate status file version {} does not match proxy agent file version in extension {}", proxy_agent_aggregate_status_file_version, proxyagent_file_version_in_extension); + let version_mismatch_message = format!("Proxy agent aggregate status file version {proxy_agent_aggregate_status_file_version} does not match proxy agent file version in extension {proxyagent_file_version_in_extension}"); write_state_event( constants::STATE_KEY_FILE_VERSION, constants::ERROR_STATUS, @@ -459,7 +482,7 @@ fn extension_substatus( Ok(proxy_agent_aggregate_status) => proxy_agent_aggregate_status, Err(e) => { let error_message = - format!("Error in serializing proxy agent aggregate status: {}", e); + format!("Error in serializing proxy agent aggregate status: {e}"); logger::write(error_message.to_string()); error_message } @@ -482,8 +505,7 @@ fn extension_substatus( } Err(e) => { let error_message = format!( - "Error in serializing proxy agent aggregate connection status: {}", - e + "Error in serializing proxy agent aggregate connection status: {e}" ); logger::write(error_message.to_string()); substatus_proxy_agent_connection_message = error_message; @@ -511,8 +533,7 @@ fn extension_substatus( } Err(e) => { let error_message = format!( - "Error in serializing proxy agent aggregate failed auth status: {}", - e + "Error in serializing proxy agent aggregate failed auth status: {e}" ); logger::write(error_message.to_string()); substatus_failed_auth_message = error_message; @@ -631,7 +652,7 @@ fn restore_purge_proxyagent(status: &mut StatusObj) -> bool { Err(e) => { telemetry::event_logger::write_event( LoggerLevel::Info, - format!("Error in running Restore Proxy Agent command: {}", e), + format!("Error in running Restore Proxy Agent command: {e}"), "restore_purge_proxyagent", "service_main", &logger::get_logger_key(), @@ -663,7 +684,7 @@ fn restore_purge_proxyagent(status: &mut StatusObj) -> bool { Err(e) => { telemetry::event_logger::write_event( LoggerLevel::Info, - format!("Error in running Purge Proxy Agent command: {}", e), + format!("Error in running Purge Proxy Agent command: {e}"), "restore_purge_proxyagent", "service_main", &logger::get_logger_key(), @@ -724,7 +745,7 @@ fn report_proxy_agent_service_status( Err(e) => { telemetry::event_logger::write_event( LoggerLevel::Info, - format!("Error in running Update Proxy Agent command: {}", e), + format!("Error in running Update Proxy Agent command: {e}"), "report_proxy_agent_service_status", "service_main", &logger::get_logger_key(), @@ -734,30 +755,13 @@ fn report_proxy_agent_service_status( status.code = constants::STATUS_CODE_NOT_OK; status.status = status_state_obj.update_state(false); status.formattedMessage.message = - format!("Update Proxy Agent command failed with error: {}", e); + format!("Update Proxy Agent command failed with error: {e}"); status.substatus = Default::default(); common::report_status(status_folder, seq_no, status); } } } -fn get_proxy_agent_file_version_in_extension() -> String { - // File version of proxy agent service already downloaded by VM Agent - let path = common::get_proxy_agent_exe_path(); - match misc_helpers::get_proxy_agent_version(&path) { - Ok(version) => version, - Err(e) => { - logger::write(format!( - "Failed to get GuestProxyAgent version from file {} with error: {}", - misc_helpers::path_to_string(&path), - e - )); - // return empty string if failed to get version - "".to_string() - } - } -} - // test report status #[cfg(test)] mod tests { diff --git a/proxy_agent_extension/src/service_main/windows_main.rs b/proxy_agent_extension/src/service_main/windows_main.rs index 9441eb6a..a793cf72 100644 --- a/proxy_agent_extension/src/service_main/windows_main.rs +++ b/proxy_agent_extension/src/service_main/windows_main.rs @@ -36,7 +36,7 @@ pub async fn run_service(_args: Vec) -> Result<()> { process_id: None, }; if let Err(e) = status_handle.set_service_status(stop_state) { - logger::write(format!("Failed to set service status to Stopped: {}", e)); + logger::write(format!("Failed to set service status to Stopped: {e}")); } } else { // workaround to stop the service by exiting the process diff --git a/proxy_agent_extension/src/structs.rs b/proxy_agent_extension/src/structs.rs index 599ce238..bae1f39a 100644 --- a/proxy_agent_extension/src/structs.rs +++ b/proxy_agent_extension/src/structs.rs @@ -13,7 +13,7 @@ pub struct HandlerEnvironment { pub rolename: Option, pub instance: Option, pub hostResolverAddress: Option, - pub eventsFolder: String, + pub eventsFolder: Option, } impl Clone for HandlerEnvironment { fn clone(&self) -> Self { diff --git a/proxy_agent_setup/Cargo.toml b/proxy_agent_setup/Cargo.toml index 3ded82cd..698fdb9e 100644 --- a/proxy_agent_setup/Cargo.toml +++ b/proxy_agent_setup/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "proxy_agent_setup" -version = "1.0.31" +version = "1.0.32" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/proxy_agent_setup/src/args.rs b/proxy_agent_setup/src/args.rs index 8ab2a66c..16cdfcce 100644 --- a/proxy_agent_setup/src/args.rs +++ b/proxy_agent_setup/src/args.rs @@ -48,9 +48,9 @@ impl Display for Command { match self { Command::Backup => write!(f, "backup"), Command::Restore { delete_backup } => { - write!(f, "restore delete_backup={}", delete_backup) + write!(f, "restore delete_backup={delete_backup}") } - Command::Uninstall { uninstall_mode } => write!(f, "uninstall {}", uninstall_mode), + Command::Uninstall { uninstall_mode } => write!(f, "uninstall {uninstall_mode}"), Command::Install => write!(f, "install"), Command::Purge => write!(f, "purge"), } diff --git a/proxy_agent_setup/src/linux.rs b/proxy_agent_setup/src/linux.rs index ea71de3d..70921167 100644 --- a/proxy_agent_setup/src/linux.rs +++ b/proxy_agent_setup/src/linux.rs @@ -17,7 +17,7 @@ pub fn setup_service(service_name: &str, service_file_dir: PathBuf) -> Result Result { - let service_config_name = format!("{}.service", service_name); + let service_config_name = format!("{service_name}.service"); let src_config_file_path = service_file_dir.join(&service_config_name); let dst_config_file_path = PathBuf::from(proxy_agent_shared::linux::SERVICE_CONFIG_FOLDER_PATH) .join(&service_config_name); @@ -33,14 +33,12 @@ fn backup_service_config_file(backup_folder: PathBuf) { ) { Ok(_) => { logger::write(format!( - "Copied service config file to {:?}", - backup_service_file + "Copied service config file to {backup_service_file:?}" )); } Err(e) => { logger::write(format!( - "Failed to copy service config file to {:?}, error: {:?}", - backup_service_file, e + "Failed to copy service config file to {backup_service_file:?}, error: {e:?}" )); } } @@ -49,17 +47,16 @@ fn backup_service_config_file(backup_folder: PathBuf) { fn copy_file(src_file: PathBuf, dst_file: PathBuf) { if let Some(p) = dst_file.parent() { if let Err(e) = misc_helpers::try_create_folder(p) { - logger::write(format!("Failed to create folder {:?}, error: {:?}", p, e)); + logger::write(format!("Failed to create folder {p:?}, error: {e:?}")); } } match fs::copy(&src_file, &dst_file) { Ok(_) => { - logger::write(format!("Copied file {:?} to {:?}", src_file, dst_file)); + logger::write(format!("Copied file {src_file:?} to {dst_file:?}")); } Err(e) => { logger::write(format!( - "Failed to copy file {:?} to {:?}, error: {:?}", - src_file, dst_file, e + "Failed to copy file {src_file:?} to {dst_file:?}, error: {e:?}" )); } } @@ -68,12 +65,11 @@ fn copy_file(src_file: PathBuf, dst_file: PathBuf) { fn delete_file(file_to_be_delete: PathBuf) { match fs::remove_file(&file_to_be_delete) { Ok(_) => { - logger::write(format!("Deleted file {:?}", file_to_be_delete)); + logger::write(format!("Deleted file {file_to_be_delete:?}")); } Err(e) => { logger::write(format!( - "Failed to delete file {:?}, error: {:?}", - file_to_be_delete, e + "Failed to delete file {file_to_be_delete:?}, error: {e:?}" )); } } diff --git a/proxy_agent_setup/src/logger.rs b/proxy_agent_setup/src/logger.rs index 91c72dc7..7c870ec6 100644 --- a/proxy_agent_setup/src/logger.rs +++ b/proxy_agent_setup/src/logger.rs @@ -15,10 +15,10 @@ fn force_init_logger(log_folder: PathBuf, log_name: &str) { let logger = RollingLogger::create_new(log_folder, log_name.to_string(), 20 * 1024 * 1024, 30); let mut loggers = std::collections::HashMap::new(); loggers.insert(log_name.to_string(), logger); - logger_manager::set_loggers(loggers, log_name.to_string()); + logger_manager::set_loggers(loggers, log_name.to_string(), LoggerLevel::Trace); } pub fn write(message: String) { - println!("{}", message); + println!("{message}"); logger_manager::log(LOGGER_KEY.to_string(), LoggerLevel::Info, message); } diff --git a/proxy_agent_setup/src/main.rs b/proxy_agent_setup/src/main.rs index 02707190..17cdac12 100644 --- a/proxy_agent_setup/src/main.rs +++ b/proxy_agent_setup/src/main.rs @@ -127,8 +127,7 @@ fn copy_proxy_agent_files(src_folder: PathBuf, dst_folder: PathBuf) { Ok(_) => {} Err(e) => { logger::write(format!( - "Failed to create folder {:?}, error: {:?}", - dst_folder, e + "Failed to create folder {dst_folder:?}, error: {e:?}" )); } } @@ -139,12 +138,11 @@ fn copy_proxy_agent_files(src_folder: PathBuf, dst_folder: PathBuf) { let dst_file = dst_folder.join(&file_name); match fs::copy(&file, &dst_file) { Ok(_) => { - logger::write(format!("Copied {:?} to {:?}", file, dst_file)); + logger::write(format!("Copied {file:?} to {dst_file:?}")); } Err(e) => { logger::write(format!( - "Failed to copy {:?} to {:?}, error: {:?}", - file, dst_file, e + "Failed to copy {file:?} to {dst_file:?}, error: {e:?}" )); } } @@ -152,8 +150,7 @@ fn copy_proxy_agent_files(src_folder: PathBuf, dst_folder: PathBuf) { } Err(e) => { logger::write(format!( - "Failed to get files from {:?}, error: {:?}", - src_folder, e + "Failed to get files from {src_folder:?}, error: {e:?}" )); } } @@ -162,12 +159,11 @@ fn copy_proxy_agent_files(src_folder: PathBuf, dst_folder: PathBuf) { async fn stop_service() { match service::stop_service(SERVICE_NAME).await { Ok(_) => { - logger::write(format!("Stopped service {} successfully", SERVICE_NAME)); + logger::write(format!("Stopped service {SERVICE_NAME} successfully")); } Err(e) => { logger::write(format!( - "Stopped service {} failed, error: {:?}", - SERVICE_NAME, e + "Stopped service {SERVICE_NAME} failed, error: {e:?}" )); } } @@ -188,13 +184,10 @@ async fn setup_service(proxy_agent_target_folder: PathBuf, _service_config_folde { match linux::setup_service(SERVICE_NAME, _service_config_folder_path) { Ok(_) => { - logger::write(format!("Setup service {} successfully", SERVICE_NAME)); + logger::write(format!("Setup service {SERVICE_NAME} successfully")); } Err(e) => { - logger::write(format!( - "Setup service {} failed, error: {:?}", - SERVICE_NAME, e - )); + logger::write(format!("Setup service {SERVICE_NAME} failed, error: {e:?}")); process::exit(1); } } @@ -207,12 +200,11 @@ async fn setup_service(proxy_agent_target_folder: PathBuf, _service_config_folde setup::proxy_agent_exe_path(&proxy_agent_target_folder), ) { Ok(_) => { - logger::write(format!("Install service {} successfully", SERVICE_NAME)); + logger::write(format!("Install service {SERVICE_NAME} successfully")); } Err(e) => { logger::write(format!( - "Install service {} failed, error: {:?}", - SERVICE_NAME, e + "Install service {SERVICE_NAME} failed, error: {e:?}", )); process::exit(1); } @@ -243,8 +235,7 @@ async fn setup_service(proxy_agent_target_folder: PathBuf, _service_config_folde } Err(e) => { logger::write(format!( - "ebpf_setup: failed to invoke script file '{}', error: '{:?}'.", - setup_script_file_str, e + "ebpf_setup: failed to invoke script file '{setup_script_file_str}', error: '{e:?}'." )); } } @@ -253,25 +244,21 @@ async fn setup_service(proxy_agent_target_folder: PathBuf, _service_config_folde match service::start_service(SERVICE_NAME, 5, Duration::from_secs(15)).await { Ok(_) => { - logger::write(format!("Service {} start successfully", SERVICE_NAME)); + logger::write(format!("Service {SERVICE_NAME} start successfully")); } Err(e) => { - logger::write(format!( - "Service {} start failed, error: {:?}", - SERVICE_NAME, e - )); + logger::write(format!("Service {SERVICE_NAME} start failed, error: {e:?}")); process::exit(1); } } - logger::write(format!("Service {} start successfully", SERVICE_NAME)); + logger::write(format!("Service {SERVICE_NAME} start successfully")); } fn check_backup_exists() -> bool { let proxy_agent_exe = setup::proxy_agent_exe_path(&backup::proxy_agent_backup_package_folder()); if !proxy_agent_exe.exists() { logger::write(format!( - "GuestProxyAgent ({:?}) does not exists.", - proxy_agent_exe + "GuestProxyAgent ({proxy_agent_exe:?}) does not exists." )); return false; } @@ -284,12 +271,11 @@ async fn uninstall_service() -> PathBuf { match service::stop_and_delete_service(SERVICE_NAME).await { Ok(_) => { - logger::write(format!("Uninstall service {} successfully", SERVICE_NAME)); + logger::write(format!("Uninstall service {SERVICE_NAME} successfully")); } Err(e) => { logger::write(format!( - "Uninstall service {} failed, error: {:?}", - SERVICE_NAME, e + "Uninstall service {SERVICE_NAME} failed, error: {e:?}" )); process::exit(1); } @@ -312,12 +298,11 @@ fn delete_package(_proxy_agent_running_folder: PathBuf) { fn delete_folder(folder_to_be_delete: PathBuf) { match fs::remove_dir_all(&folder_to_be_delete) { Ok(_) => { - logger::write(format!("Deleted folder {:?}", folder_to_be_delete)); + logger::write(format!("Deleted folder {folder_to_be_delete:?}")); } Err(e) => { logger::write(format!( - "Failed to delete folder {:?}, error: {:?}", - folder_to_be_delete, e + "Failed to delete folder {folder_to_be_delete:?}, error: {e:?}" )); } } diff --git a/proxy_agent_setup/src/running.rs b/proxy_agent_setup/src/running.rs index ee0ca188..93905cb8 100644 --- a/proxy_agent_setup/src/running.rs +++ b/proxy_agent_setup/src/running.rs @@ -41,18 +41,15 @@ pub fn proxy_agent_version_target_folder(proxy_agent_exe: &Path) -> PathBuf { Ok(v) => v, Err(e) => { // This should not happen, if failed to get version, we should not proceed - logger::write(format!( - "Failed to get proxy agent version with error: {}", - e - )); - panic!("Failed to get proxy agent version with error: {}", e); + logger::write(format!("Failed to get proxy agent version with error: {e}")); + panic!("Failed to get proxy agent version with error: {e}"); } }; logger::write(format!("Proxy agent version: {}", &proxy_agent_version)); #[cfg(windows)] { let path = proxy_agent_parent_folder(); - path.join(format!("Package_{}", proxy_agent_version)) + path.join(format!("Package_{proxy_agent_version}")) } #[cfg(not(windows))] { diff --git a/proxy_agent_shared/Cargo.toml b/proxy_agent_shared/Cargo.toml index bb0bd216..098e387f 100644 --- a/proxy_agent_shared/Cargo.toml +++ b/proxy_agent_shared/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "proxy_agent_shared" -version = "1.0.31" +version = "1.0.32" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html @@ -18,18 +18,22 @@ thiserror = "1.0.64" tokio = { version = "1", features = ["rt", "macros", "sync", "time"] } log = { version = "0.4.26", features = ["std"] } ctor = "0.3.6" # used for test setup and clean up +backtrace = "0.3" # used for get the caller module and function name [target.'cfg(windows)'.dependencies] windows-service = "0.7.0" # windows NT service winreg = "0.11.0" # windows reg read/write +serde-xml-rs = "0.8.1" # xml Deserializer with xml attribute +chrono = "0.4.41" # parse date time string [target.'cfg(windows)'.dependencies.windows-sys] -version = "0.42.0" +version = "0.52.0" features = [ "Win32_Foundation", "Win32_Networking_WinSock", "Win32_System_IO", "Win32_Security", + "Win32_System_EventLog", "Win32_System_WindowsProgramming", "Win32_Security_Authentication_Identity", "Win32_System_Diagnostics_Debug", diff --git a/proxy_agent_shared/src/etw.rs b/proxy_agent_shared/src/etw.rs new file mode 100644 index 00000000..166b10d8 --- /dev/null +++ b/proxy_agent_shared/src/etw.rs @@ -0,0 +1,20 @@ +// Copyright (c) Microsoft Corporation +// SPDX-License-Identifier: MIT +//! This module provides functionality for ETW (Event Tracing for Windows) logging. + +pub mod etw_writter; + +/// This module provides functionality to read ETW events. +/// Test quality only so far. +#[cfg(test)] +mod etw_reader; + +use std::ffi::OsStr; +use std::iter::once; +use std::os::windows::ffi::OsStrExt; + +/// Converts a string to a wide character vector (u16). +/// This is used to convert Rust strings to the format required by Windows API functions. +pub fn to_wide(s: &str) -> Vec { + OsStr::new(s).encode_wide().chain(once(0)).collect() +} diff --git a/proxy_agent_shared/src/etw/etw_reader.rs b/proxy_agent_shared/src/etw/etw_reader.rs new file mode 100644 index 00000000..5c06065b --- /dev/null +++ b/proxy_agent_shared/src/etw/etw_reader.rs @@ -0,0 +1,273 @@ +// Copyright (c) Microsoft Corporation +// SPDX-License-Identifier: MIT + +use crate::error::Error; +use crate::result::Result; +use chrono::DateTime; +use serde_derive::{Deserialize, Serialize}; +use std::ffi::OsString; +use std::os::windows::ffi::OsStringExt; +use windows_sys::Win32::Foundation::GetLastError; +use windows_sys::Win32::Foundation::ERROR_NO_MORE_ITEMS; +use windows_sys::Win32::System::EventLog::{EvtClose, EvtNext, EvtQuery, EvtRender, EVT_HANDLE}; // wevtapi.dll +use windows_sys::Win32::System::EventLog::{EvtQueryReverseDirection, EvtRenderEventXml}; + +/// Represents an ETW event structure +/// as defined in the XML schema. +/// The structure is used to deserialize ETW events from XML format. +/// The `Event` struct contains a `System` and `EventData` field, +/// which hold the metadata and data of the event respectively. +#[derive(Debug, Deserialize, Serialize)] +#[serde(rename = "Event")] +pub struct Event { + #[serde(rename = "System")] + pub system: System, + #[serde(rename = "EventData", skip_serializing_if = "Option::is_none")] + pub event_data: Option, +} + +#[derive(Debug, Deserialize, Serialize)] +pub struct System { + #[serde(rename = "Provider")] + pub provider: Provider, + #[serde(rename = "EventID")] + pub event_id: u32, + #[serde(rename = "Version")] + pub version: u8, + #[serde(rename = "Level")] + pub level: u8, + #[serde(rename = "Task")] + pub task: u8, + #[serde(rename = "Opcode")] + pub opcode: u8, + #[serde(rename = "Keywords")] + pub keywords: String, + #[serde(rename = "TimeCreated")] + pub time_created: TimeCreated, + #[serde(rename = "EventRecordID")] + pub event_record_id: u64, + #[serde(rename = "Execution")] + pub execution: Execution, + #[serde(rename = "Channel")] + pub channel: String, + #[serde(rename = "Computer")] + pub computer: String, +} + +#[derive(Debug, Deserialize, Serialize)] +pub struct Provider { + #[serde(rename = "@Name", skip_serializing_if = "Option::is_none")] + pub name: Option, + #[serde(rename = "@EventSourceName", skip_serializing_if = "Option::is_none")] + pub event_source_name: Option, +} + +#[derive(Debug, Deserialize, Serialize)] +pub struct TimeCreated { + #[serde(rename = "@SystemTime", skip_serializing_if = "Option::is_none")] + pub system_time: Option, +} + +#[derive(Debug, Deserialize, Serialize)] +pub struct Execution { + #[serde(rename = "@ProcessID")] + pub process_id: u32, + #[serde(rename = "@ThreadID")] + pub thread_id: u32, +} + +#[derive(Debug, Deserialize, Serialize)] +pub struct EventData { + #[serde(rename = "Data")] + pub data: Option>, +} + +pub struct WindowsEventReader { + query_handle: EVT_HANDLE, + current_event: EVT_HANDLE, + source_name: String, + start_time: Option>, + end_time: Option>, +} + +impl WindowsEventReader { + pub fn new( + event_name: &str, + source_name: &str, + start_time: Option>, + end_time: Option>, + ) -> Result { + let event_name_wide = crate::etw::to_wide(event_name); + let h_query = unsafe { + EvtQuery( + 0, + event_name_wide.as_ptr(), + std::ptr::null(), + EvtQueryReverseDirection, + ) + }; + if h_query == 0 { + return Err(Error::WindowsApi( + "EvtQuery".to_string(), + std::io::Error::last_os_error(), + )); + } + + Ok(WindowsEventReader { + query_handle: h_query, + current_event: 0, + source_name: source_name.to_string(), + start_time, + end_time, + }) + } + // Additional methods for reading events can be implemented here +} + +impl Drop for WindowsEventReader { + fn drop(&mut self) { + // Close the query handle and current event handle if they are open + unsafe { + EvtClose(self.query_handle); + EvtClose(self.current_event); + } + } +} + +impl Iterator for WindowsEventReader { + type Item = Result; + + fn next(&mut self) -> Option { + let mut returned: u32 = 0; + + if unsafe { + EvtNext( + self.query_handle, + 1, + &mut self.current_event, + 0, + 0, + &mut returned, + ) + } == 0 + { + let error_code = unsafe { GetLastError() }; + if error_code == ERROR_NO_MORE_ITEMS { + // No more items to read + return None; + } else { + return Some(Err(Error::WindowsApi( + "EvtNext".to_string(), + std::io::Error::from_raw_os_error(error_code as i32), + ))); + } + } + + if returned == 0 { + return None; // No events read + } + + // First call to get buffer size + let mut buffer_used = 0; + let mut property_count = 0; + let status = unsafe { + EvtRender( + 0, + self.current_event, + EvtRenderEventXml, + 0, + std::ptr::null_mut(), + &mut buffer_used, + &mut property_count, + ) + }; + if status != 0 || buffer_used == 0 { + return Some(Err(Error::WindowsApi( + "EvtRender_Buffer_Size".to_string(), + std::io::Error::last_os_error(), + ))); + } + // Allocate buffer for rendering + let mut buffer: Vec = vec![0; buffer_used as usize / 2]; + if unsafe { + EvtRender( + 0, + self.current_event, + EvtRenderEventXml, + buffer_used, + buffer.as_mut_ptr() as *mut _, + &mut buffer_used, + &mut property_count, + ) + } == 0 + { + return Some(Err(Error::WindowsApi( + "EvtRender".to_string(), + std::io::Error::last_os_error(), + ))); + } + + // Convert the buffer to a xml string + let xml = OsString::from_wide(&buffer) + .to_string_lossy() + .trim_end_matches('\0') + .to_string(); + + // Parse the XML string into an Event struct + match serde_xml_rs::from_str::(&xml) { + Ok(event) => { + let mut skip_event = false; + // Check if the event is from the specified source + if event.system.provider.name == Some(self.source_name.clone()) { + // Check if the event is within the specified time range + let time_created = event.system.time_created.system_time.clone(); + println!( + "Event '{}' Time Created: {:?}", + self.source_name, time_created + ); + + if let Some(start_time) = self.start_time { + match time_created.clone() { + Some(time) => { + if let Ok(event_time) = + time.parse::>() + { + if event_time < start_time { + skip_event = true; // Skip this event + } + } + } + None => skip_event = true, // Skip this event if time is not available + } + } + if let Some(end_time) = self.end_time { + match time_created { + Some(time) => { + if let Ok(event_time) = + time.parse::>() + { + if event_time > end_time { + skip_event = true; // Skip this event + } + } + } + None => skip_event = true, // Skip this event if time is not available + } + } + } else { + skip_event = true; // Skip this event + } + + if skip_event { + self.next() // Skip to the next event + } else { + Some(Ok(event)) // Return the event + } + } + Err(e) => Some(Err(Error::Io(std::io::Error::new( + std::io::ErrorKind::InvalidData, + format!("Failed to parse event XML: {e}"), + )))), + } + } +} diff --git a/proxy_agent_shared/src/etw/etw_writter.rs b/proxy_agent_shared/src/etw/etw_writter.rs new file mode 100644 index 00000000..bc71d821 --- /dev/null +++ b/proxy_agent_shared/src/etw/etw_writter.rs @@ -0,0 +1,200 @@ +// Copyright (c) Microsoft Corporation +// SPDX-License-Identifier: MIT + +//! This module provides functionality for Windows event +//! logging using the Windows Event Log API. +//! It allows registering an event source, writing logs to the Event Log. + +use crate::error::Error; +use crate::logger::LoggerLevel; +use crate::result::Result; +use windows_sys::core::PWSTR; +use windows_sys::Win32::Foundation::HANDLE; +use windows_sys::Win32::System::EventLog::{ + DeregisterEventSource, RegisterEventSourceW, ReportEventW, +}; // advapi32.dll +use windows_sys::Win32::System::EventLog::{ + EVENTLOG_ERROR_TYPE, EVENTLOG_INFORMATION_TYPE, EVENTLOG_WARNING_TYPE, REPORT_EVENT_TYPE, +}; + +/// Converts a `LoggerLevel` to a `REPORT_EVENT_TYPE`. +/// This function maps the logging levels to the corresponding Windows Event Log types. +fn to_event_level(level: LoggerLevel) -> REPORT_EVENT_TYPE { + match level { + LoggerLevel::Trace => EVENTLOG_INFORMATION_TYPE, + LoggerLevel::Debug => EVENTLOG_INFORMATION_TYPE, + LoggerLevel::Info => EVENTLOG_INFORMATION_TYPE, + LoggerLevel::Warn => EVENTLOG_WARNING_TYPE, + LoggerLevel::Error => EVENTLOG_ERROR_TYPE, + } +} + +/// A struct for writing windows etw events to the Windows Event Log. +/// It registers an event source and provides a method to write logs. +/// It also ensures that the event source is deregistered when the struct is dropped. +pub struct WindowsEventWritter { + event_source: HANDLE, +} + +impl WindowsEventWritter { + pub fn new(event_log_name: &str, source_name: &str) -> Result { + // Add event source in the Windows Registry before retrieving the event source handle. + // `HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\EventLog\{event_log_name}\{source_name}` + let key_name = format!( + "SYSTEM\\CurrentControlSet\\Services\\EventLog\\{event_log_name}\\{source_name}" + ); + let value = crate::misc_helpers::resolve_env_variables( + r"%SystemRoot%\Microsoft.NET\Framework64\v4.0.30319\EventLogMessages.dll", + )?; + crate::windows::set_reg_string(&key_name, "EventMessageFile", value)?; + + let source_name_wide = super::to_wide(source_name); + let event_source = + unsafe { RegisterEventSourceW(std::ptr::null(), source_name_wide.as_ptr()) }; + if event_source == 0 { + return Err(Error::WindowsApi( + "RegisterEventSourceW".to_string(), + std::io::Error::last_os_error(), + )); + } + + Ok(WindowsEventWritter { event_source }) + } + + pub fn write(&self, log_level: LoggerLevel, message: String) { + let wide_message = super::to_wide(&message); + let wide_message_ptrs: [PWSTR; 1] = [wide_message.as_ptr() as PWSTR]; + + unsafe { + ReportEventW( + self.event_source, + to_event_level(log_level), + 0, + 0, + std::ptr::null_mut(), + 1, + 0, + wide_message_ptrs.as_ptr() as *const *const u16, + std::ptr::null(), + ); + } + } +} + +impl Drop for WindowsEventWritter { + fn drop(&mut self) { + unsafe { + DeregisterEventSource(self.event_source); + } + } +} + +#[cfg(test)] +mod tests { + use super::WindowsEventWritter; + use crate::etw::etw_reader::WindowsEventReader; + use crate::logger::LoggerLevel; + use chrono::DateTime; + + /// This test verifies that the WindowsEventWritter can write to the Windows Event Log + /// and that the written log can be queried successfully. + /// It creates a new event source, writes a log message, + /// and then queries the event log to verify that the message was written correctly. + /// The test also checks for logs within a specific time range + /// to ensure that the event log is being written correctly. + /// # Note: This test picks `Application` as the event log name, + /// as `Windows Container` does have its own Registry but not its own Event Log System. + /// https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-registereventsourcew#remarks + /// RegisterEventSourceW retrieves a registered handle to the specified event log, + /// but if the source name cannot be found, the event logging service uses the `Application` log. + #[test] + fn write_event_log_test() { + // According to the test log, it indicates that Windows Container may have few milliseconds difference against its current host time. + // Therefore, we set the start time to 1 second before the current time. + let start_time = chrono::Utc::now() - chrono::Duration::seconds(1); + let end_time = start_time + chrono::Duration::seconds(60); + + let event_log_name = "Application"; + let source_name = "Azure_GuestProxyAgent_TestApplication"; + let message = "This is a test log message"; + let event_writer = WindowsEventWritter::new(event_log_name, source_name).unwrap(); + event_writer.write(LoggerLevel::Info, message.to_string()); + + println!("Verifying event log for source: {}", source_name); + let data = query_windows_event(event_log_name, source_name, None, None); + assert_eq!( + data, message, + "Event log data does not match the expected message" + ); + + println!( + "Verifying event log for source: {} after {}", + source_name, start_time + ); + let data = query_windows_event(event_log_name, source_name, Some(start_time), None); + assert_eq!( + data, message, + "Event log data does not match the expected message" + ); + + println!( + "Verifying event log for source: {} before {}", + source_name, end_time + ); + let data = query_windows_event(event_log_name, source_name, None, Some(end_time)); + assert_eq!( + data, message, + "Event log data does not match the expected message" + ); + + println!( + "Verifying event log for source: {} between {} and {}", + source_name, start_time, end_time + ); + let data = query_windows_event( + event_log_name, + source_name, + Some(start_time), + Some(end_time), + ); + assert_eq!( + data, message, + "Event log data does not match the expected message" + ); + + // Clean up: Remove the event log from the Windows Registry + let key_name = format!( + r"SYSTEM\CurrentControlSet\Services\EventLog\{}\{}", + event_log_name, source_name + ); + if let Err(e) = crate::windows::remove_reg_key(&key_name) { + eprintln!("Failed to remove event source from registry: {}", e); + } + } + + fn query_windows_event( + event_log_name: &str, + source_name: &str, + start_time: Option>, + end_time: Option>, + ) -> String { + let mut reader = + WindowsEventReader::new(event_log_name, source_name, start_time, end_time).unwrap(); + let data = reader + .next() + .map(|event| { + event + .unwrap() + .event_data + .unwrap() + .data + .unwrap() + .iter() + .map(|d| d.to_string()) + .collect::>() + }) + .unwrap_or_else(|| vec!["No data found".to_string()]); + + return data.join("\n"); + } +} diff --git a/proxy_agent_shared/src/lib.rs b/proxy_agent_shared/src/lib.rs index 4ba2f5bb..27a01e6a 100644 --- a/proxy_agent_shared/src/lib.rs +++ b/proxy_agent_shared/src/lib.rs @@ -2,6 +2,8 @@ // SPDX-License-Identifier: MIT pub mod error; +#[cfg(windows)] +pub mod etw; pub mod logger; pub mod misc_helpers; pub mod proxy_agent_aggregate_status; diff --git a/proxy_agent_shared/src/linux.rs b/proxy_agent_shared/src/linux.rs index ac75187e..138d8782 100644 --- a/proxy_agent_shared/src/linux.rs +++ b/proxy_agent_shared/src/linux.rs @@ -47,8 +47,7 @@ pub fn get_os_version() -> String { } Err(e) => { let message = format!( - "Failed to read os-release file in get_os_version(): {} with error: {}", - OS_RELEASE_PATH, e + "Failed to read os-release file in get_os_version(): {OS_RELEASE_PATH} with error: {e}", ); logger_manager::write_warn(message); return "Unknown".to_string(); @@ -78,8 +77,7 @@ pub fn get_os_type() -> String { } Err(e) => { let message = format!( - "Failed to read os-release file in get_os_type(): {} with error: {}", - OS_RELEASE_PATH, e + "Failed to read os-release file in get_os_type(): {OS_RELEASE_PATH} with error: {e}", ); logger_manager::write_warn(message); return "Unknown".to_string(); diff --git a/proxy_agent_shared/src/logger.rs b/proxy_agent_shared/src/logger.rs index 0eb677f3..f80ccf63 100644 --- a/proxy_agent_shared/src/logger.rs +++ b/proxy_agent_shared/src/logger.rs @@ -8,13 +8,96 @@ pub mod rolling_logger; pub type LoggerLevel = log::Level; +const HEADER_LENGTH: usize = 34; pub fn get_log_header(level: LoggerLevel) -> String { - format!( - "{} [{}] ", + get_log_header_with_length( + level, misc_helpers::get_date_time_string_with_milliseconds(), - level - )[..34] - .to_string() + HEADER_LENGTH, + ) +} + +fn get_log_header_with_length( + level: LoggerLevel, + date_time_string: String, + length: usize, +) -> String { + let header = format!("{date_time_string} [{level}] ") + .chars() + .take(length) + .collect::(); + + // padding if the header is shorter than HEADER_LENGTH + if header.len() < length { + let padding = " ".repeat(length - header.len()); + return format!("{header}{padding}"); + } + header +} + +const ASYNC_FUNCTION_NAME: &str = "{closure"; +const INTERNAL_BACKTRACE: &str = "backtrace"; +const CURRENT_FUNCTION: &str = "::logger::get_caller_info"; +const RUNTIME_TASK_SCHEDULER: &str = "::runtime::task::Schedule"; // The runtime scheduler function that runs the tasks + +#[cfg(test)] +const TEST_CODE_COVERAGE_FUNCTIONS: &str = "__covrec_"; // code coverage recording, generated by a code coverage tool such as llvm-cov, or a similar instrumentation framework +#[cfg(test)] +const TEST_INTERNAL_FUNCTION: &str = "test::run_test"; // The test framework's internal function that runs the tests + +pub fn get_caller_info(module_to_skip: &str) -> (String, String) { + let bt = backtrace::Backtrace::new(); + for frame in bt.frames().iter() { + for symbol in frame.symbols() { + if let Some(name) = symbol.name() { + let name_str = name.to_string(); + + let mut found_function: bool = true; + // Skip internal frames, current function frame and `module_to_skip` to find the first relevant caller + found_function = found_function + && !name_str.contains(INTERNAL_BACKTRACE) + && !name_str.contains(CURRENT_FUNCTION) + && !name_str.contains(RUNTIME_TASK_SCHEDULER) + && !name_str.contains(module_to_skip); + + #[cfg(test)] + { + found_function = found_function + && !name_str.contains(TEST_CODE_COVERAGE_FUNCTIONS) + && !name_str.starts_with(TEST_INTERNAL_FUNCTION); + } + + if found_function { + // If the name contains `{{closure}}`, it indicates an async function + // We need to find the first segment that contains the async function name + // Example: `azure_proxy_agent::proxy::proxy_server::ProxyServer::handle_new_tcp_connection::{{closure}}::{{closure}}::h537d19fb7a504d22` + let seg = name_str.split("::").collect::>(); + let seg_len = seg.len(); + let mut function_last_index = 0; + for i in 0..seg_len { + if seg[seg_len - 1 - i].contains(ASYNC_FUNCTION_NAME) { + function_last_index = i + 1; + } + } + let caller_name = seg + .get(seg_len - 1 - function_last_index) + .unwrap_or(&"unknown") + .to_string(); + // Get the module name from the first to `function_last_index` segment + let module_name = seg + .into_iter() + .map(String::from) + .collect::>() + .into_iter() + .take(seg_len - 1 - function_last_index) + .collect::>() + .join("::"); + return (module_name, caller_name); + } + } + } + } + ("unknown".to_string(), "unknown".to_string()) } #[cfg(test)] @@ -39,4 +122,39 @@ mod tests { "Trace level should be greater than or equal to Trace level" ); } + + #[tokio::test] + async fn invoke_get_caller_info_test() { + test_get_caller_info_test("invoke_get_caller_info_test"); + } + + fn test_get_caller_info_test(expected_caller_name: &str) { + let (module_name, caller_name) = super::get_caller_info("test_get_caller_info_test"); + println!("Module Name: {}", module_name); + println!("Caller Name: {}", caller_name); + // Check if the caller name is as expected + assert_eq!(caller_name, expected_caller_name); + } + + #[test] + fn get_log_header_with_length_test() { + let header = super::get_log_header_with_length( + Level::Info, + "2023-10-01 12:00:00.000".to_string(), + 34, + ); + assert_eq!(header, "2023-10-01 12:00:00.000 [INFO] "); + let header = super::get_log_header_with_length( + Level::Error, + "2023-10-01 12:00:00.000".to_string(), + 34, + ); + assert_eq!(header, "2023-10-01 12:00:00.000 [ERROR] "); + let header = super::get_log_header_with_length( + Level::Warn, + "2023-10-01 12:00:00.00".to_string(), + 34, + ); + assert_eq!(header, "2023-10-01 12:00:00.00 [WARN] "); + } } diff --git a/proxy_agent_shared/src/logger/logger_manager.rs b/proxy_agent_shared/src/logger/logger_manager.rs index 97784746..4ab046b8 100644 --- a/proxy_agent_shared/src/logger/logger_manager.rs +++ b/proxy_agent_shared/src/logger/logger_manager.rs @@ -1,22 +1,50 @@ // Copyright (c) Microsoft Corporation // SPDX-License-Identifier: MIT +//! This module manages the loggers for the application. +//! It provides functionality to set up loggers, write logs, and manage log levels. +//! It uses a static `OnceCell` to ensure that the loggers are initialized only once. use super::rolling_logger::RollingLogger; -use log::Level; +#[cfg(windows)] +use crate::etw::etw_writter::WindowsEventWritter; +use crate::logger::LoggerLevel; use std::collections::HashMap; +// The loggers are stored in a static `OnceCell` to ensure they are initialized only once. static LOGGERS: tokio::sync::OnceCell> = tokio::sync::OnceCell::const_new(); +// The `DEFAULT_LOGGER_KEY` is used to specify which rolling logger should be used by default when no key is provided. static DEFAULT_LOGGER_KEY: tokio::sync::OnceCell = tokio::sync::OnceCell::const_new(); -static MAX_LOG_LEVEL: tokio::sync::OnceCell = tokio::sync::OnceCell::const_new(); +// The `MAX_LOG_LEVEL` is used to set the maximum log level for the loggers. +static MAX_LOG_LEVEL: tokio::sync::OnceCell = tokio::sync::OnceCell::const_new(); +// The `MAX_SYSTEM_LOG_LEVEL` is used to set the maximum log level for system logs. +static MAX_SYSTEM_LOG_LEVEL: tokio::sync::OnceCell = + tokio::sync::OnceCell::const_new(); +#[cfg(windows)] +static WINDOWS_ETW_LOGGER: tokio::sync::OnceCell = + tokio::sync::OnceCell::const_new(); /// Setup the loggers and set the default logger key /// # Arguments /// * `loggers` - A hashmap of loggers /// * `default_logger_key` - The default logger key +/// * `max_log_level` - The maximum log level for file logging /// # Panics /// * If the default logger key is not found in the loggers hashmap -pub fn set_loggers(loggers: HashMap, default_logger_key: String) { +pub fn set_loggers( + loggers: HashMap, + default_logger_key: String, + max_log_level: LoggerLevel, +) { + if !MAX_LOG_LEVEL.initialized() { + if let Err(e) = MAX_LOG_LEVEL.set(max_log_level) { + write_system_log( + LoggerLevel::Error, + format!("Failed to set logger level: {e}"), + ); + } + } + if LOGGERS.initialized() { return; } @@ -26,21 +54,54 @@ pub fn set_loggers(loggers: HashMap, default_logger_key: } // set the loggers once - LOGGERS.set(loggers).unwrap(); - DEFAULT_LOGGER_KEY.set(default_logger_key).unwrap(); + if let Err(e) = LOGGERS.set(loggers) { + write_system_log(LoggerLevel::Error, format!("Failed to set loggers: {e}")); + }; + if let Err(e) = DEFAULT_LOGGER_KEY.set(default_logger_key) { + write_system_log( + LoggerLevel::Error, + format!("Failed to set default logger key: {e}"), + ); + } } -pub fn set_logger_level(log_level: Level) { - if MAX_LOG_LEVEL.initialized() { - return; +pub fn set_system_logger(max_log_level: LoggerLevel, _event_log_name: &str, _service_name: &str) { + #[cfg(windows)] + { + if !WINDOWS_ETW_LOGGER.initialized() { + match WindowsEventWritter::new(_event_log_name, _service_name) { + Ok(logger) => { + if let Err(e) = WINDOWS_ETW_LOGGER.set(logger) { + write_system_log( + LoggerLevel::Error, + format!("Failed to set Windows ETW logger: {e}"), + ); + } + } + Err(e) => { + write_system_log( + LoggerLevel::Error, + format!("Failed to create Windows ETW logger: {e}"), + ); + } + } + } + } + + if !MAX_SYSTEM_LOG_LEVEL.initialized() { + if let Err(e) = MAX_SYSTEM_LOG_LEVEL.set(max_log_level) { + write_system_log( + LoggerLevel::Error, + format!("Failed to set system logger level: {e}"), + ); + } } - MAX_LOG_LEVEL.set(log_level).unwrap(); } -pub fn get_logger_level() -> Level { +pub fn get_max_logger_level() -> LoggerLevel { let level = match MAX_LOG_LEVEL.get() { Some(l) => *l, // No need to use `clone` on type `Level` which implements the `Copy` trait - None => Level::Trace, + None => LoggerLevel::Trace, }; level } @@ -56,59 +117,85 @@ fn get_logger(logger_key: Option) -> Option<&'static RollingLogger> { None } -pub fn log(logger_key: String, log_level: Level, message: String) { - if log_level > get_logger_level() { +fn internal_log(logger_key: Option, log_level: LoggerLevel, message: String) { + // By default, we write the log to the system log + // This is useful for debugging and monitoring purposes. + write_system_log(log_level, message.clone()); + + if log_level > get_max_logger_level() { return; } - if let Some(logger) = get_logger(Some(logger_key)) { + if let Some(logger) = get_logger(logger_key) { if let Err(e) = logger.write(log_level, message) { - eprintln!("Error writing to log: {}", e); + eprintln!("Error writing to log: {e}"); } } } -pub fn write_log(log_level: Level, message: String) { - let level = match MAX_LOG_LEVEL.get() { - Some(l) => *l, // No need to use `clone` on type `Level` which implements the `Copy` trait - None => Level::Trace, - }; - if log_level > level { - return; - } +pub fn log(logger_key: String, log_level: LoggerLevel, message: String) { + internal_log(Some(logger_key), log_level, message); +} - if let Some(logger) = get_logger(None) { - if let Err(e) = logger.write(log_level, message) { - eprintln!("Error writing to log: {}", e); - } - } +pub fn write_log(log_level: LoggerLevel, message: String) { + internal_log(None, log_level, message); } pub fn write_info(message: String) { - write_log(Level::Info, message); + write_log(LoggerLevel::Info, message); } pub fn write_warn(message: String) { - write_log(Level::Warn, message); + write_log(LoggerLevel::Warn, message); } pub fn write_err(message: String) { - write_log(Level::Error, message); + write_log(LoggerLevel::Error, message); } pub fn write_many(logger_key: Option, messages: Vec) { if let Some(logger) = get_logger(logger_key) { if let Err(e) = logger.write_many(messages) { - eprintln!("Error writing to log: {}", e); + eprintln!("Error writing to log: {e}"); + } + } +} + +pub fn write_system_log(log_level: LoggerLevel, message: String) { + if log_level > get_max_system_logger_level() { + return; + } + + // Linux automatically captures console logs to syslog. + if log_level == LoggerLevel::Error { + eprintln!("{message}",); + } else { + println!("{message}",); + } + + #[cfg(windows)] + { + if let Some(logger) = WINDOWS_ETW_LOGGER.get() { + logger.write(log_level, message); + } else { + eprintln!("Windows ETW Application logger is not initialized."); } } } +fn get_max_system_logger_level() -> LoggerLevel { + let level = match MAX_SYSTEM_LOG_LEVEL.get() { + Some(l) => *l, // No need to use `clone` on type `Level` which implements the `Copy` trait + None => LoggerLevel::Error, + }; + level +} + #[cfg(test)] mod tests { + use crate::logger::LoggerLevel; use crate::misc_helpers; use ctor::{ctor, dtor}; - use log::Level; use std::env; use std::fs; @@ -131,7 +218,11 @@ mod tests { ); let mut loggers = std::collections::HashMap::new(); loggers.insert(TEST_LOGGER_KEY.to_string(), logger); - crate::logger::logger_manager::set_loggers(loggers, TEST_LOGGER_KEY.to_string()); + crate::logger::logger_manager::set_loggers( + loggers, + TEST_LOGGER_KEY.to_string(), + LoggerLevel::Trace, + ); } #[dtor] @@ -144,16 +235,16 @@ mod tests { fn logger_manager_test() { for _ in [0; 20] { super::write_log( - Level::Trace, + LoggerLevel::Trace, String::from("This is a test message This is a test message"), ); super::write_log( - Level::Debug, + LoggerLevel::Debug, String::from("This is a test message This is a test message"), ); - super::write_log(Level::Info, "message from write_info".to_string()); - super::write_log(Level::Warn, "message from write_warn".to_string()); - super::write_log(Level::Error, "message from write_err".to_string()); + super::write_log(LoggerLevel::Info, "message from write_info".to_string()); + super::write_log(LoggerLevel::Warn, "message from write_warn".to_string()); + super::write_log(LoggerLevel::Error, "message from write_err".to_string()); } let file_count = misc_helpers::get_files(&get_temp_test_dir()).unwrap(); diff --git a/proxy_agent_shared/src/misc_helpers.rs b/proxy_agent_shared/src/misc_helpers.rs index fd304656..149b2188 100644 --- a/proxy_agent_shared/src/misc_helpers.rs +++ b/proxy_agent_shared/src/misc_helpers.rs @@ -268,13 +268,13 @@ pub fn get_proxy_agent_version(proxy_agent_exe: &Path) -> Result { if !proxy_agent_exe.exists() { return Err(Error::Io(std::io::Error::new( std::io::ErrorKind::NotFound, - format!("File '{}' does not found", proxy_agent_exe_str), + format!("File '{proxy_agent_exe_str}' does not found"), ))); } if !proxy_agent_exe.is_file() { return Err(Error::Io(std::io::Error::new( std::io::ErrorKind::InvalidInput, - format!("'{}' is not a file", proxy_agent_exe_str), + format!("'{proxy_agent_exe_str}' is not a file"), ))); } diff --git a/proxy_agent_shared/src/service.rs b/proxy_agent_shared/src/service.rs index 0cd0f1b1..5ca4b892 100644 --- a/proxy_agent_shared/src/service.rs +++ b/proxy_agent_shared/src/service.rs @@ -99,18 +99,14 @@ pub fn query_service_executable_path(_service_name: &str) -> PathBuf { { match windows_service::query_service_config(_service_name) { Ok(service_config) => { - logger_manager::write_info(format!( - "Service {} successfully queried", - _service_name - )); + logger_manager::write_info( + format!("Service {_service_name} successfully queried",), + ); service_config.executable_path.to_path_buf() } Err(e) => { - logger_manager::write_info(format!( - "Service {} query failed: {}", - _service_name, e - )); - eprintln!("Service {} query failed: {}", _service_name, e); + logger_manager::write_info(format!("Service {_service_name} query failed: {e}",)); + eprintln!("Service {_service_name} query failed: {e}"); PathBuf::new() } } @@ -129,14 +125,13 @@ pub fn check_service_installed(_service_name: &str) -> (bool, String) { match windows_service::query_service_config(_service_name) { Ok(_service_config) => { message = format!( - "check_service_installed: Ebpf Driver: {} successfully queried.", - _service_name + "check_service_installed: Ebpf Driver: {_service_name} successfully queried.", ); (true, message) } Err(e) => { message = format!( - "check_service_installed: Ebpf Driver: {} unsuccessfully queried with error: {}.", _service_name, e + "check_service_installed: Ebpf Driver: {_service_name} unsuccessfully queried with error: {e}" ); (false, message) } diff --git a/proxy_agent_shared/src/service/linux_service.rs b/proxy_agent_shared/src/service/linux_service.rs index a27144b1..84efd3e8 100644 --- a/proxy_agent_shared/src/service/linux_service.rs +++ b/proxy_agent_shared/src/service/linux_service.rs @@ -79,7 +79,7 @@ fn enable_service(service_name: &str) -> Result<()> { fn delete_service_config_file(service_name: &str) -> Result<()> { let config_file_path = - PathBuf::from(linux::SERVICE_CONFIG_FOLDER_PATH).join(format!("{}.service", service_name)); + PathBuf::from(linux::SERVICE_CONFIG_FOLDER_PATH).join(format!("{service_name}.service")); match fs::remove_file(&config_file_path) { Ok(_) => { reload_systemd_daemon()?; diff --git a/proxy_agent_shared/src/service/windows_service.rs b/proxy_agent_shared/src/service/windows_service.rs index fcdef742..975e7803 100644 --- a/proxy_agent_shared/src/service/windows_service.rs +++ b/proxy_agent_shared/src/service/windows_service.rs @@ -21,14 +21,13 @@ pub async fn start_service_with_retry( duration: std::time::Duration, ) -> Result<()> { for i in 0..retry_count { - logger_manager::write_info(format!("Starting service {} attempt {}", service_name, i)); + logger_manager::write_info(format!("Starting service '{service_name}' attempt {i}")); match start_service_once(service_name).await { Ok(service) => { if service.current_state == ServiceState::Running { logger_manager::write_info(format!( - "Service {} is at Running state", - service_name + "Service '{service_name}' is at Running state" )); return Ok(()); } @@ -43,19 +42,13 @@ pub async fn start_service_with_retry( } Err(e) => { logger_manager::write_warn( - format!( - "Extension service {} start failed with error: {}", - service_name, e - ) - .to_string(), + format!("Extension service '{service_name}' start failed with error: {e}") + .to_string(), ); if (i + 1) == retry_count { logger_manager::write_err( - format!( - "Service {} failed to start after {} attempts", - service_name, i - ) - .to_string(), + format!("Service '{service_name}' failed to start after {i} attempts") + .to_string(), ); return Err(e); } @@ -70,10 +63,10 @@ async fn start_service_once(service_name: &str) -> Result { // Start service if it already isn't running let service = query_service_status(service_name)?; if service.current_state == ServiceState::Running { - logger_manager::write_info(format!("Service '{}' is already running", service_name)); + logger_manager::write_info(format!("Service '{service_name}' is already running")); Ok(service) } else { - logger_manager::write_info(format!("Starting service '{}'", service_name)); + logger_manager::write_info(format!("Starting service '{service_name}'")); let service_manager: ServiceManager = ServiceManager::local_computer(None::<&str>, ServiceManagerAccess::CONNECT) .map_err(|e| Error::WindowsService(e, std::io::Error::last_os_error()))?; @@ -122,8 +115,7 @@ pub async fn stop_service(service_name: &str) -> Result { } Err(e) => { logger_manager::write_info(format!( - "Stopped service {} failed, error: {:?}", - service_name, e + "Stopped service {service_name} failed, error: {e:?}" )); } } diff --git a/proxy_agent_shared/src/telemetry/event_logger.rs b/proxy_agent_shared/src/telemetry/event_logger.rs index a9731c7b..6d7ea3a9 100644 --- a/proxy_agent_shared/src/telemetry/event_logger.rs +++ b/proxy_agent_shared/src/telemetry/event_logger.rs @@ -33,7 +33,7 @@ pub async fn start( logger_manager::write_log(Level::Info, message.to_string()); if let Err(e) = misc_helpers::try_create_folder(&event_dir) { - let message = format!("Failed to create event folder with error: {}", e); + let message = format!("Failed to create event folder with error: {e}"); set_status_fn(message.to_string()); } @@ -75,9 +75,8 @@ pub async fn start( match misc_helpers::get_files(&event_dir) { Ok(files) => { if files.len() >= max_event_file_count { - logger_manager::write_log( Level::Warn,format!( - "Event files exceed the max file count {}, drop and skip the write to disk.", - max_event_file_count + logger_manager::write_log(Level::Warn, format!( + "Event files exceed the max file count {max_event_file_count}, drop and skip the write to disk." )); continue; } @@ -85,7 +84,7 @@ pub async fn start( Err(e) => { logger_manager::write_log( Level::Warn, - format!("Failed to get event files with error: {}", e), + format!("Failed to get event files with error: {e}"), ); } } @@ -128,27 +127,29 @@ pub fn write_event( module_name: &str, logger_key: &str, ) { + write_event_only(level, message.to_string(), method_name, module_name); + + // wrap file log within event log + logger_manager::log(logger_key.to_string(), level, message); +} + +pub fn write_event_only(level: Level, message: String, method_name: &str, module_name: &str) { let event_message = if message.len() > MAX_MESSAGE_LENGTH { message[..MAX_MESSAGE_LENGTH].to_string() } else { message.to_string() }; - let logger_key = logger_key.to_string(); match EVENT_QUEUE.push(Event::new( level.to_string(), event_message, method_name.to_string(), module_name.to_string(), )) { - Ok(()) => { - // wrap file log within event log - logger_manager::log(logger_key, level, message); - } + Ok(()) => {} Err(e) => { - logger_manager::log( - logger_key, + logger_manager::write_log( Level::Warn, - format!("Failed to push event to the queue with error: {}", e), + format!("Failed to push event to the queue with error: {e}"), ); } }; diff --git a/proxy_agent_shared/src/version.rs b/proxy_agent_shared/src/version.rs index 2d543116..f01c5388 100644 --- a/proxy_agent_shared/src/version.rs +++ b/proxy_agent_shared/src/version.rs @@ -85,14 +85,14 @@ impl Display for Version { let mut ver = format!("{}.{}", self.major, self.minor); if let Some(b) = self.build { - ver = format!("{}.{}", ver, b); + ver = format!("{ver}.{b}"); if let Some(r) = self.revision { - ver = format!("{}.{}", ver, r); + ver = format!("{ver}.{r}"); } } - write!(f, "{}", ver) + write!(f, "{ver}") } } diff --git a/proxy_agent_shared/src/windows.rs b/proxy_agent_shared/src/windows.rs index 27f2e0d3..83eb9171 100644 --- a/proxy_agent_shared/src/windows.rs +++ b/proxy_agent_shared/src/windows.rs @@ -26,11 +26,11 @@ fn read_reg_int(key_name: &str, value_name: &str, default_value: Option) -> Ok(key) => match key.get_value(value_name) { Ok(val) => return Some(val), Err(e) => { - print!("{}", e); + print!("{e}"); } }, Err(e) => { - print!("{}", e); + print!("{e}"); } } @@ -49,6 +49,19 @@ fn read_reg_string(key_name: &str, value_name: &str, default_value: String) -> S default_value } +pub fn set_reg_string(key_name: &str, value_name: &str, value: String) -> Result<()> { + let hklm = RegKey::predef(HKEY_LOCAL_MACHINE); + let (key, _) = hklm.create_subkey(key_name)?; + key.set_value(value_name, &value)?; + Ok(()) +} + +pub fn remove_reg_key(key_name: &str) -> Result<()> { + let hklm = RegKey::predef(HKEY_LOCAL_MACHINE); + hklm.delete_subkey_all(key_name)?; + Ok(()) +} + const OS_VERSION_REGISTRY_KEY: &str = "Software\\Microsoft\\Windows NT\\CurrentVersion"; const PRODUCT_NAME_VAL_STRING: &str = "ProductName"; const CURRENT_MAJOR_VERSION_NUMBER_STRING: &str = "CurrentMajorVersionNumber"; @@ -74,7 +87,7 @@ pub fn get_os_version() -> Result { Ok(u) => major = u, Err(_) => { return Err(Error::ParseVersion(ParseVersionErrorType::MajorBuild( - format!("{} ({})", major_str, CURRENT_MAJOR_VERSION_NUMBER_STRING), + format!("{major_str} ({CURRENT_MAJOR_VERSION_NUMBER_STRING})"), ))); } } @@ -98,7 +111,7 @@ pub fn get_os_version() -> Result { Ok(u) => minor = u, Err(_) => { return Err(Error::ParseVersion(ParseVersionErrorType::MinorBuild( - format!("{} ({})", major_str, CURRENT_MINOR_VERSION_NUMBER_STRING), + format!("{major_str} ({CURRENT_MINOR_VERSION_NUMBER_STRING})"), ))); } } @@ -174,11 +187,11 @@ pub fn get_processor_arch() -> String { .Anonymous .wProcessorArchitecture { - windows_sys::Win32::System::Diagnostics::Debug::PROCESSOR_ARCHITECTURE_INTEL => "x86", // 0 - windows_sys::Win32::System::Diagnostics::Debug::PROCESSOR_ARCHITECTURE_ARM => "ARM", // 5 - windows_sys::Win32::System::Diagnostics::Debug::PROCESSOR_ARCHITECTURE_IA64 => "IA64", // 6 - windows_sys::Win32::System::Diagnostics::Debug::PROCESSOR_ARCHITECTURE_AMD64 => "AMD64", // 9 - 12 => "ARM64", // 12 - ARM64 is missed here + windows_sys::Win32::System::SystemInformation::PROCESSOR_ARCHITECTURE_INTEL => "x86", // 0 + windows_sys::Win32::System::SystemInformation::PROCESSOR_ARCHITECTURE_ARM => "ARM", // 5 + windows_sys::Win32::System::SystemInformation::PROCESSOR_ARCHITECTURE_IA64 => "IA64", // 6 + windows_sys::Win32::System::SystemInformation::PROCESSOR_ARCHITECTURE_AMD64 => "AMD64", // 9 + windows_sys::Win32::System::SystemInformation::PROCESSOR_ARCHITECTURE_ARM64 => "ARM64", // 12 _ => "unknown", } .to_owned() @@ -302,10 +315,7 @@ pub fn get_file_product_version(file_path: &Path) -> Result { } if fixed_file_info_size != std::mem::size_of::() as u32 { return Err(Error::ParseVersion(ParseVersionErrorType::InvalidString( - format!( - "Invalid VS_FIXEDFILEINFO size '{}' returned", - fixed_file_info_size - ), + format!("Invalid VS_FIXEDFILEINFO size '{fixed_file_info_size}' returned"), ))); } @@ -369,4 +379,21 @@ mod tests { println!("kernel32.dll File product version: {}", version); assert_eq!(version.major, 10, "major version mismatch"); } + + #[test] + fn reg_set_test() { + let key_name = "Software\\TestKey"; + let value_name = "TestValue"; + let value = "TestValueData".to_string(); + + // Set the registry value + super::set_reg_string(key_name, value_name, value.clone()).unwrap(); + + // Read the registry value + let read_value = super::read_reg_string(key_name, value_name, "".to_string()); + assert_eq!(value, read_value, "Registry value mismatch"); + + // Clean up + super::remove_reg_key(key_name).unwrap(); + } }