From 9a5a001e05193e2b9b2136b9d5776c905f8ac088 Mon Sep 17 00:00:00 2001 From: Zhidong Peng Date: Fri, 8 Aug 2025 20:21:09 -0700 Subject: [PATCH 1/8] Fix clippy error from rust v1.89 (#265) * fix error from \cargo-clippy.cmd * fix error from ./cargo-clippy.sh --------- Co-authored-by: Zhidong Peng --- proxy_agent/src/proxy/proxy_authorizer.rs | 6 +++--- proxy_agent_extension/src/handler_main.rs | 14 +++++++------- proxy_agent_extension/src/service_main.rs | 4 ++-- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/proxy_agent/src/proxy/proxy_authorizer.rs b/proxy_agent/src/proxy/proxy_authorizer.rs index cbe575f7..1707f55e 100644 --- a/proxy_agent/src/proxy/proxy_authorizer.rs +++ b/proxy_agent/src/proxy/proxy_authorizer.rs @@ -198,11 +198,11 @@ pub fn get_authorizer(ip: String, port: u16, claims: Claims) -> Box bool { if linux_type.contains("ubuntu") { version.major >= constants::linux::MIN_SUPPORTED_UBUNTU_OS_VERSION_MAJOR } else if linux_type.contains("mariner") { - return version.major >= constants::linux::MIN_SUPPORTED_MARINER_OS_VERSION_MAJOR; + version.major >= constants::linux::MIN_SUPPORTED_MARINER_OS_VERSION_MAJOR } else if linux_type.contains("azure linux") { - return version.major >= constants::linux::MIN_SUPPORTED_AZURE_LINUX_OS_VERSION_MAJOR; + version.major >= constants::linux::MIN_SUPPORTED_AZURE_LINUX_OS_VERSION_MAJOR } else if linux_type.contains(constants::linux::RED_HAT_OS_NAME) { - return version.major >= constants::linux::MIN_RED_HAT_OS_VERSION_MAJOR; + version.major >= constants::linux::MIN_RED_HAT_OS_VERSION_MAJOR } else if linux_type.contains(constants::linux::ROCKY_OS_NAME) { - return version.major >= constants::linux::MIN_ROCKY_OS_VERSION_MAJOR; + version.major >= constants::linux::MIN_ROCKY_OS_VERSION_MAJOR } else if linux_type.contains(constants::linux::SUSE_OS_NAME) { // SUSE 15 SP4+ is supported - return version.major > constants::linux::MIN_SUSE_OS_VERSION_MAJOR + version.major > constants::linux::MIN_SUSE_OS_VERSION_MAJOR || (version.major == constants::linux::MIN_SUSE_OS_VERSION_MAJOR - && version.minor >= constants::linux::MIN_SUSE_OS_VERSION_MINOR); + && version.minor >= constants::linux::MIN_SUSE_OS_VERSION_MINOR) } else { - return false; + false } } diff --git a/proxy_agent_extension/src/service_main.rs b/proxy_agent_extension/src/service_main.rs index 936f5338..d547ac06 100644 --- a/proxy_agent_extension/src/service_main.rs +++ b/proxy_agent_extension/src/service_main.rs @@ -691,9 +691,9 @@ fn restore_purge_proxyagent(status: &mut StatusObj) -> bool { ); } } - return true; + true } else { - return false; + false } } From 5e1e2a4d48b125e349a88c1aabf09b15c8baf0e1 Mon Sep 17 00:00:00 2001 From: Zhidong Peng Date: Mon, 11 Aug 2025 13:12:18 -0700 Subject: [PATCH 2/8] windows gpa to skip the lookup for builtin system user (#264) * upgrade rust version to 1.88 * add more unit tests * format * fix ut for linux * Skip "tokio::runtime::scheduler" in command `cargo llvm-cov --target x86_64-unknown-linux-musl` with rust-1.88.0 * remove debug log * formatting * fix * windows gpa to skip the lookup for builtin system user * push new tcp connection to kusto * filter account 998 too --------- Co-authored-by: Zhidong Peng --- proxy_agent/src/proxy/proxy_server.rs | 2 +- proxy_agent/src/proxy/windows.rs | 15 +++++++++++++-- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/proxy_agent/src/proxy/proxy_server.rs b/proxy_agent/src/proxy/proxy_server.rs index 8a4e4214..bbfb8a54 100644 --- a/proxy_agent/src/proxy/proxy_server.rs +++ b/proxy_agent/src/proxy/proxy_server.rs @@ -239,7 +239,7 @@ impl ProxyServer { }; let mut tcp_connection_logger = ConnectionLogger::new(tcp_connection_id, 0); tcp_connection_logger.write( - LoggerLevel::Trace, + LoggerLevel::Info, format!("Accepted new tcp connection [{tcp_connection_id}]."), ); diff --git a/proxy_agent/src/proxy/windows.rs b/proxy_agent/src/proxy/windows.rs index 74085f59..f5acc659 100644 --- a/proxy_agent/src/proxy/windows.rs +++ b/proxy_agent/src/proxy/windows.rs @@ -88,13 +88,15 @@ fn net_user_get_local_groups( } } +const BUILTIN_SYSTEM_LOGIN_ID_999: u64 = 0x3e7; // SYSTEM user login id +const BUILTIN_SYSTEM_LOGIN_ID_998: u64 = 0x3e6; // SYSTEM user login id static BUILTIN_USERS: Lazy> = Lazy::new(load_users); fn load_users() -> HashMap { let mut users = HashMap::new(); users.insert(0x3e4, "NETWORK SERVICE"); users.insert(0x3e5, "LOCAL SERVICE"); - users.insert(0x3e6, "SYSTEM"); - users.insert(0x3e7, "SYSTEM"); + users.insert(BUILTIN_SYSTEM_LOGIN_ID_998, "SYSTEM"); + users.insert(BUILTIN_SYSTEM_LOGIN_ID_999, "SYSTEM"); users.insert(0x3e8, "IIS_IUSRS"); users.insert(0x3e9, "IUSR"); users @@ -104,6 +106,15 @@ fn load_users() -> HashMap { Get user name and user group names */ pub fn get_user(logon_id: u64) -> Result<(String, Vec)> { + // Check if the logon_id is a built-in SYSTEM user + // if it is, return the user name and an empty group list + // https://learn.microsoft.com/en-us/windows/security/identity-protection/access-control/local-accounts#default-local-system-accounts + // It's an internal account that doesn't show up in User Manager, and it can't be added to any groups. + if logon_id == BUILTIN_SYSTEM_LOGIN_ID_998 || logon_id == BUILTIN_SYSTEM_LOGIN_ID_999 { + // if logon_id is the SYSTEM user, return it directly + return Ok((BUILTIN_USERS[&logon_id].to_string(), Vec::new())); + } + let mut user_name; let luid = LUID { LowPart: (logon_id & 0xFFFFFFFF) as u32, // get lower part of 32 bits From c647f6ae7d401c66d56dadbe53088604ac39a865 Mon Sep 17 00:00:00 2001 From: Zhidong Peng Date: Mon, 25 Aug 2025 09:09:55 -0700 Subject: [PATCH 3/8] Enable ProxyAgentExtension Arm64 tests (#261) * move update_current_secure_channel_state before reportting attest the key. * Add tag { "EnforceArchitectureTypeForExtensions": "true" } for Arm64 VMs * enable arm64 extension tests * E2E tests program accepts proxyAgentVersion parameter. * fix * add more test logging * Fix * workarounds to use ARM64 VM Extension * fix spelling --- .github/actions/spelling/expect.txt | 2 ++ .../GuestProxyAgentScenarioTests.cs | 9 +++-- .../Models/TestScenarioStatusDetails.cs | 2 +- e2etest/GuestProxyAgentTest/Program.cs | 6 ++-- .../Settings/TestScenarioSetting.cs | 9 +++++ .../Settings/TestSetting.cs | 4 ++- .../TestCases/AddLinuxVMExtensionCase.cs | 2 +- .../TestMap/AzureLinux3-Arm64-TestGroup.yml | 2 ++ .../TestMap/Ubuntu24-Arm64-TestGroup.yml | 4 ++- .../TestMap/WinClient11-Arm64-TestGroup.yml | 2 ++ .../TestScenarios/ProxyAgentExtension.cs | 36 ++++--------------- .../TestScenarios/TestScenarioBase.cs | 4 ++- .../Utilities/Constants.cs | 11 ++---- .../Utilities/TestCommonUtilities.cs | 4 +-- .../Utilities/VMBuilder.cs | 9 ++++- 15 files changed, 55 insertions(+), 51 deletions(-) diff --git a/.github/actions/spelling/expect.txt b/.github/actions/spelling/expect.txt index 6142f860..06de539d 100644 --- a/.github/actions/spelling/expect.txt +++ b/.github/actions/spelling/expect.txt @@ -210,6 +210,7 @@ pprev prandom predef prefmaxlen +preprovisioned printk PROCESSINFOCLASS proxyagent @@ -342,6 +343,7 @@ wireserver wireserverand wireserverandimds WMI +workarounds WORKDIR WScript wsf diff --git a/e2etest/GuestProxyAgentTest/GuestProxyAgentScenarioTests.cs b/e2etest/GuestProxyAgentTest/GuestProxyAgentScenarioTests.cs index 501645b7..90df2803 100644 --- a/e2etest/GuestProxyAgentTest/GuestProxyAgentScenarioTests.cs +++ b/e2etest/GuestProxyAgentTest/GuestProxyAgentScenarioTests.cs @@ -21,7 +21,7 @@ public class GuestProxyAgentScenarioTests public async Task StartAsync(List testScenarioList) { var groupTestResultBuilderMap = new Dictionary(); - foreach(var testGroupName in testScenarioList.Select(x => x.testGroupName).ToHashSet()) + foreach (var testGroupName in testScenarioList.Select(x => x.testGroupName).ToHashSet()) { groupTestResultBuilderMap[testGroupName] = new JunitTestResultBuilder(TestSetting.Instance.testResultFolder, testGroupName); } @@ -57,7 +57,6 @@ public async Task StartAsync(List testScenarioList) testScenarioStatusDetails.Status = ScenarioTestStatus.Completed; testScenarioStatusDetails.ErrorMessage = "Failed to create the scenario class instance: " + testScenario.testScenarioClassName; } - } catch (Exception ex) { @@ -72,6 +71,10 @@ public async Task StartAsync(List testScenarioList) { taskList.Add(testScenarioTask); } + var message = string.Format("Test Group: {0}, Test Scenario: {1}: {2} ({3})" + , testScenario.testGroupName, testScenario.testScenarioName + , testScenarioStatusDetails.Result, testScenarioStatusDetails.ErrorMessage); + Console.WriteLine(message); } } var stopMonitor = new ManualResetEvent(false); @@ -91,7 +94,7 @@ public async Task StartAsync(List testScenarioList) { Console.WriteLine($"Test execution exception: {ex.Message}"); } - + stopMonitor.Set(); foreach (var groupName in groupTestResultBuilderMap.Keys) diff --git a/e2etest/GuestProxyAgentTest/Models/TestScenarioStatusDetails.cs b/e2etest/GuestProxyAgentTest/Models/TestScenarioStatusDetails.cs index b19a1f23..84824594 100644 --- a/e2etest/GuestProxyAgentTest/Models/TestScenarioStatusDetails.cs +++ b/e2etest/GuestProxyAgentTest/Models/TestScenarioStatusDetails.cs @@ -37,7 +37,7 @@ public string TestCasesErrorMessage { get { - return FailedCases.Count() == 0? "": $"Test Scenario:{ScenarioName} failed by test cases: {string.Join(',', FailedCases)}, Check the test case log for error details."; + return FailedCases.Count() == 0 ? "" : $"Test Scenario:{ScenarioName} failed by test cases: {string.Join(',', FailedCases)}, Check the test case log for error details."; } } } diff --git a/e2etest/GuestProxyAgentTest/Program.cs b/e2etest/GuestProxyAgentTest/Program.cs index b47c3814..330f6e23 100644 --- a/e2etest/GuestProxyAgentTest/Program.cs +++ b/e2etest/GuestProxyAgentTest/Program.cs @@ -23,13 +23,15 @@ static async Task Main(string[] args) var testConfigFilePath = args[0]; var testResultFolder = args[1]; var guestProxyAgentZipFilePath = args[2]; + var proxyAgentVersion = args[3]; var test_arm64 = false; - if (args.Length > 3 && args[3].Equals("arm64", StringComparison.InvariantCultureIgnoreCase)) + if (args.Length > 4 && args[4].Equals("arm64", StringComparison.InvariantCultureIgnoreCase)) { test_arm64 = true; } + - TestCommonUtilities.TestSetup(guestProxyAgentZipFilePath, testConfigFilePath, testResultFolder); + TestCommonUtilities.TestSetup(guestProxyAgentZipFilePath, testConfigFilePath, testResultFolder, proxyAgentVersion); VMHelper.Instance.CleanupOldTestResourcesAndForget(); diff --git a/e2etest/GuestProxyAgentTest/Settings/TestScenarioSetting.cs b/e2etest/GuestProxyAgentTest/Settings/TestScenarioSetting.cs index 80ab01e3..9772c200 100644 --- a/e2etest/GuestProxyAgentTest/Settings/TestScenarioSetting.cs +++ b/e2etest/GuestProxyAgentTest/Settings/TestScenarioSetting.cs @@ -54,5 +54,14 @@ public class VMImageDetails public string Offer { get; set; } = null!; public string Sku { get; set; } = null!; public string Version { get; set; } = null!; + + public bool IsArm64 + { + get + { + return (Offer == null ? false : Offer.Contains("arm64", StringComparison.OrdinalIgnoreCase)) || + (Sku == null ? false : Sku.Contains("arm64", StringComparison.OrdinalIgnoreCase)); + } + } } } diff --git a/e2etest/GuestProxyAgentTest/Settings/TestSetting.cs b/e2etest/GuestProxyAgentTest/Settings/TestSetting.cs index bb085093..19e2e066 100644 --- a/e2etest/GuestProxyAgentTest/Settings/TestSetting.cs +++ b/e2etest/GuestProxyAgentTest/Settings/TestSetting.cs @@ -35,6 +35,7 @@ public static TestSetting Instance internal string zipFilePath = null!; internal string sharedStorageAccountUrl = null!; internal string testResultFolder = null!; + internal string proxyAgentVersion = null!; internal int testMapTimeoutMilliseconds = 1000 * 60 * 180; internal string windowsInVmWireServerAccessControlProfileReferenceId = null!; internal string windowsInVmIMDSAccessControlProfileReferenceId = null!; @@ -53,7 +54,7 @@ internal string InVmIMDSAccessControlProfileReferenceId private TestSetting() { } - public static void Init(TestConfig testConfig, string zipFilePath, string testResultFolder) + public static void Init(TestConfig testConfig, string zipFilePath, string testResultFolder, string proxyAgentVersion) { var scriptsFolder = Constants.IS_WINDOWS() ? "Scripts" : "LinuxScripts"; @@ -78,6 +79,7 @@ public static void Init(TestConfig testConfig, string zipFilePath, string testRe linuxInVmIMDSAccessControlProfileReferenceId = testConfig.LinuxInVmIMDSAccessControlProfileReferenceId, zipFilePath = zipFilePath, testResultFolder = testResultFolder, + proxyAgentVersion = proxyAgentVersion, }; } } diff --git a/e2etest/GuestProxyAgentTest/TestCases/AddLinuxVMExtensionCase.cs b/e2etest/GuestProxyAgentTest/TestCases/AddLinuxVMExtensionCase.cs index bfd53f28..6fb80a58 100644 --- a/e2etest/GuestProxyAgentTest/TestCases/AddLinuxVMExtensionCase.cs +++ b/e2etest/GuestProxyAgentTest/TestCases/AddLinuxVMExtensionCase.cs @@ -24,7 +24,7 @@ public override async Task StartAsync(TestCaseExecutionContext context) { Location = GuestProxyAgentTest.Settings.TestSetting.Instance.location, Publisher = "Microsoft.CPlat.ProxyAgent", - ExtensionType = "ProxyAgentLinuxTest", + ExtensionType = context.ScenarioSetting.VMImageDetails.IsArm64 ? "ProxyAgentLinuxARM64Test" : "ProxyAgentLinuxTest", TypeHandlerVersion = "1.0", AutoUpgradeMinorVersion = false, EnableAutomaticUpgrade = false, diff --git a/e2etest/GuestProxyAgentTest/TestMap/AzureLinux3-Arm64-TestGroup.yml b/e2etest/GuestProxyAgentTest/TestMap/AzureLinux3-Arm64-TestGroup.yml index 623567bb..d5dfdccb 100644 --- a/e2etest/GuestProxyAgentTest/TestMap/AzureLinux3-Arm64-TestGroup.yml +++ b/e2etest/GuestProxyAgentTest/TestMap/AzureLinux3-Arm64-TestGroup.yml @@ -8,3 +8,5 @@ scenarios: name: BVTScenario - name: LinuxPackageScenario className: GuestProxyAgentTest.TestScenarios.LinuxPackageScenario + - name: ProxyAgentExtension + className: GuestProxyAgentTest.TestScenarios.ProxyAgentExtension \ No newline at end of file diff --git a/e2etest/GuestProxyAgentTest/TestMap/Ubuntu24-Arm64-TestGroup.yml b/e2etest/GuestProxyAgentTest/TestMap/Ubuntu24-Arm64-TestGroup.yml index 5e5f64b1..e10e26b1 100644 --- a/e2etest/GuestProxyAgentTest/TestMap/Ubuntu24-Arm64-TestGroup.yml +++ b/e2etest/GuestProxyAgentTest/TestMap/Ubuntu24-Arm64-TestGroup.yml @@ -7,4 +7,6 @@ scenarios: - className: GuestProxyAgentTest.TestScenarios.BVTScenario name: BVTScenario - name: LinuxPackageScenario - className: GuestProxyAgentTest.TestScenarios.LinuxPackageScenario \ No newline at end of file + className: GuestProxyAgentTest.TestScenarios.LinuxPackageScenario + - name: ProxyAgentExtension + className: GuestProxyAgentTest.TestScenarios.ProxyAgentExtension \ No newline at end of file diff --git a/e2etest/GuestProxyAgentTest/TestMap/WinClient11-Arm64-TestGroup.yml b/e2etest/GuestProxyAgentTest/TestMap/WinClient11-Arm64-TestGroup.yml index 6a38d313..de35ae28 100644 --- a/e2etest/GuestProxyAgentTest/TestMap/WinClient11-Arm64-TestGroup.yml +++ b/e2etest/GuestProxyAgentTest/TestMap/WinClient11-Arm64-TestGroup.yml @@ -8,4 +8,6 @@ scenarios: className: GuestProxyAgentTest.TestScenarios.BVTScenario - name: BugFixesScenario className: GuestProxyAgentTest.TestScenarios.BugFixesScenario + - name: ProxyAgentExtension + className: GuestProxyAgentTest.TestScenarios.ProxyAgentExtension diff --git a/e2etest/GuestProxyAgentTest/TestScenarios/ProxyAgentExtension.cs b/e2etest/GuestProxyAgentTest/TestScenarios/ProxyAgentExtension.cs index 02f6befc..5be330e7 100644 --- a/e2etest/GuestProxyAgentTest/TestScenarios/ProxyAgentExtension.cs +++ b/e2etest/GuestProxyAgentTest/TestScenarios/ProxyAgentExtension.cs @@ -14,47 +14,23 @@ public override void TestScenarioSetup() string zipFile = Settings.TestSetting.Instance.zipFilePath; string withoutExt = Path.GetFileNameWithoutExtension(zipFile); string extractPath = Path.Combine(Path.GetDirectoryName(zipFile), withoutExt); - string proxyAgentVersion = ""; - string exePath = ""; - try - { - ZipFile.ExtractToDirectory(zipFile, extractPath); - Console.WriteLine("Extraction successful!"); - } - catch (Exception ex) - { - Console.WriteLine($"An error occurred: {ex.Message}"); - } + // Passing in 0 version number for the first validation case + string proxyAgentVersionBeforeUpdate = "0"; + string proxyAgentVersion = Settings.TestSetting.Instance.proxyAgentVersion; + ConsoleLog(string.Format("Received ProxyAgent Version:{0}", proxyAgentVersion)); + if (!Constants.IS_WINDOWS()) { AddTestCase(new SetupCGroup2TestCase("SetupCGroup2")); AddTestCase(new RebootVMCase("RebootVMCaseAfterSetupCGroup2")); AddTestCase(new AddLinuxVMExtensionCase("AddLinuxVMExtensionCase")); AddTestCase(new EnableProxyAgentCase()); - exePath = extractPath + "/ProxyAgent/ProxyAgent/azure-proxy-agent"; } else { EnableProxyAgentForNewVM = true; - exePath = extractPath + "\\ProxyAgent\\ProxyAgent\\GuestProxyAgent.exe"; } - var process = new Process() - { - StartInfo = new ProcessStartInfo - { - FileName = exePath, - Arguments = "--version", - RedirectStandardOutput = true, - RedirectStandardError = true, - UseShellExecute = false, - CreateNoWindow = true, - } - }; - process.Start(); - proxyAgentVersion = process.StandardOutput.ReadToEnd(); - process.WaitForExit(); - // Passing in 0 version number for the first validation case - string proxyAgentVersionBeforeUpdate = "0"; + AddTestCase(new GuestProxyAgentExtensionValidationCase("GuestProxyAgentExtensionValidationCaseBeforeUpdate", proxyAgentVersionBeforeUpdate)); AddTestCase(new InstallOrUpdateGuestProxyAgentExtensionCase()); AddTestCase(new GuestProxyAgentExtensionValidationCase("GuestProxyAgentExtensionValidationCaseAfterUpdate", proxyAgentVersion)); diff --git a/e2etest/GuestProxyAgentTest/TestScenarios/TestScenarioBase.cs b/e2etest/GuestProxyAgentTest/TestScenarios/TestScenarioBase.cs index 92863025..4381952c 100644 --- a/e2etest/GuestProxyAgentTest/TestScenarios/TestScenarioBase.cs +++ b/e2etest/GuestProxyAgentTest/TestScenarios/TestScenarioBase.cs @@ -58,7 +58,8 @@ private string LogPrefix { get { - return "Test Group: " + _testScenarioSetting.testGroupName + ", Test Scenario: " + _testScenarioSetting.testScenarioName + ": "; + // _testScenarioSetting may still null in constructor functions + return "Test Group: " + _testScenarioSetting?.testGroupName + ", Test Scenario: " + _testScenarioSetting?.testScenarioName + ": "; } } @@ -153,6 +154,7 @@ private async Task DoStartAsync(TestScenarioStatusDetails testScenarioStatusDeta var vmCreateTestName = "CreateVM"; try { + ConsoleLog(string.Format("Creating {0} VM...", _testScenarioSetting.VMImageDetails.IsArm64 ? "ARM64" : "AMD64")); vmr = await _vmBuilder.Build(this.EnableProxyAgentForNewVM, cancellationToken); ConsoleLog("VM Create succeed"); sw.Stop(); diff --git a/e2etest/GuestProxyAgentTest/Utilities/Constants.cs b/e2etest/GuestProxyAgentTest/Utilities/Constants.cs index 18679fbc..bbfa7da1 100644 --- a/e2etest/GuestProxyAgentTest/Utilities/Constants.cs +++ b/e2etest/GuestProxyAgentTest/Utilities/Constants.cs @@ -1,13 +1,6 @@ // Copyright (c) Microsoft Corporation // SPDX-License-Identifier: MIT -using Azure.Core; -using Azure.ResourceManager.Network.Models; -using System; -using System.Collections.Generic; -using System.Linq; using System.Runtime.InteropServices; -using System.Text; -using System.Threading.Tasks; namespace GuestProxyAgentTest.Utilities { @@ -23,6 +16,8 @@ public static class Constants public static readonly string RUNCOMMAND_ERROR_OUTPUT_FILE_NAME = "runCommandErr.txt"; public static readonly string RUNCOMMAND_CUSTOM_OUTPUT_SAS_PARAMETER_NAME = "customOutputJsonSAS"; public static readonly string COULD_CLEANUP_TAG_NAME = "CouldCleanup"; + public static readonly string TAGS_ENFORCE_ARCHITECTURE_TYPE_FOR_EXTENSIONS = "EnforceArchitectureTypeForExtensions"; + public static readonly string TAGS_MUST_NOT_REUSE_PREPROVISIONED_VM = "MustNotReusePreprovisionedVM"; public const string INSTALL_LINUX_GUEST_PROXY_AGENT_PACKAGE_SCRIPT_NAME = "InstallGuestProxyAgentPackage.sh"; public static readonly string GUEST_PROXY_AGENT_E2E_ACCESS_TOKEN_ENV = "GuestProxyAgentE2EAccessToken"; public static readonly string GUEST_PROXY_AGENT_E2E_ACCESS_TOKEN_STORAGE_ACCOUNT_ENV = "GuestProxyAgentE2EAccessTokenForStorageAccount"; @@ -59,7 +54,7 @@ static Constants() public static bool IS_WINDOWS() { - return RuntimeInformation.IsOSPlatform(OSPlatform.Windows); + return RuntimeInformation.IsOSPlatform(OSPlatform.Windows); } } } diff --git a/e2etest/GuestProxyAgentTest/Utilities/TestCommonUtilities.cs b/e2etest/GuestProxyAgentTest/Utilities/TestCommonUtilities.cs index d71cf554..a9a0a8a4 100644 --- a/e2etest/GuestProxyAgentTest/Utilities/TestCommonUtilities.cs +++ b/e2etest/GuestProxyAgentTest/Utilities/TestCommonUtilities.cs @@ -16,9 +16,9 @@ public static class TestCommonUtilities /// /// /// - public static void TestSetup(string guestProxyAgentZipFilePath, string testConfigFilePath, string testResultFolder) + public static void TestSetup(string guestProxyAgentZipFilePath, string testConfigFilePath, string testResultFolder, string proxyAgentVersion) { - TestSetting.Init(YamlUtils.DeserializeYaml(testConfigFilePath), guestProxyAgentZipFilePath, testResultFolder); + TestSetting.Init(YamlUtils.DeserializeYaml(testConfigFilePath), guestProxyAgentZipFilePath, testResultFolder, proxyAgentVersion); StorageHelper.Init(TestSetting.Instance.tenantId, TestSetting.Instance.appClientId); VMHelper.Init(TestSetting.Instance.tenantId, TestSetting.Instance.appClientId, TestSetting.Instance.subscriptionId); diff --git a/e2etest/GuestProxyAgentTest/Utilities/VMBuilder.cs b/e2etest/GuestProxyAgentTest/Utilities/VMBuilder.cs index 727c5d85..7dc8b460 100644 --- a/e2etest/GuestProxyAgentTest/Utilities/VMBuilder.cs +++ b/e2etest/GuestProxyAgentTest/Utilities/VMBuilder.cs @@ -172,7 +172,14 @@ private async Task DoCreateVMData(ResourceGroupResource rgr, Product = this.testScenarioSetting.VMImageDetails.Offer, }; } - + + if (this.testScenarioSetting.VMImageDetails.IsArm64) + { + // workarounds to use ARM64 VM Extension + vmData.Tags.Add(Constants.TAGS_ENFORCE_ARCHITECTURE_TYPE_FOR_EXTENSIONS, "true"); + vmData.Tags.Add(Constants.TAGS_MUST_NOT_REUSE_PREPROVISIONED_VM, "true"); + } + return vmData; } From 222be13c9d3491a0dbdc4a47c42300ce4f8a8aa7 Mon Sep 17 00:00:00 2001 From: shahneerali <131208062+shahneerali@users.noreply.github.com> Date: Mon, 25 Aug 2025 10:35:16 -0700 Subject: [PATCH 4/8] Add Logging for Proxy Agent Update Command (#266) * update logging * lint * build * update log * nit --- proxy_agent_extension/src/service_main.rs | 55 +++++++++++++---------- 1 file changed, 31 insertions(+), 24 deletions(-) diff --git a/proxy_agent_extension/src/service_main.rs b/proxy_agent_extension/src/service_main.rs index d547ac06..4ad85e32 100644 --- a/proxy_agent_extension/src/service_main.rs +++ b/proxy_agent_extension/src/service_main.rs @@ -85,7 +85,7 @@ async fn monitor_thread() { status: constants::SUCCESS_STATUS.to_string(), formattedMessage: FormattedMessage { lang: constants::LANG_EN_US.to_string(), - message: "Update Proxy Agent command output successfully".to_string(), + message: "Started ProxyAgent Extension Monitoring thread.".to_string(), }, substatus: Default::default(), }; @@ -310,22 +310,24 @@ fn backup_proxyagent(setup_tool: &String) { } else { LoggerLevel::Warn }; + let message = format!( + "Backup Proxy Agent command finished with stdoutput: {}, stderr: {}", + String::from_utf8_lossy(&output.stdout), + String::from_utf8_lossy(&output.stderr) + ); telemetry::event_logger::write_event( event_level, - format!( - "Backup Proxy Agent command finished with stdoutput: {}, stderr: {}", - String::from_utf8_lossy(&output.stdout), - String::from_utf8_lossy(&output.stderr) - ), + message.clone(), "backup_proxyagent", "service_main", &logger::get_logger_key(), ); } Err(e) => { + let message = format!("Error in running Backup Proxy Agent command: {e}"); telemetry::event_logger::write_event( - LoggerLevel::Info, - format!("Error in running Backup Proxy Agent command: {e}"), + LoggerLevel::Warn, + message.clone(), "backup_proxyagent", "service_main", &logger::get_logger_key(), @@ -706,26 +708,30 @@ fn report_proxy_agent_service_status( ) { match output { Ok(output) => { + let message = + "Successfully Executed Setup Tool Install Command for Proxy Agent Version Upgrade" + .to_string(); logger::write(format!( - "Update Proxy Agent command output: {}", - String::from_utf8_lossy(&output.stdout) + "{} with stdoutput: {}, stderr: {}", + message.clone(), + String::from_utf8_lossy(&output.stdout), + String::from_utf8_lossy(&output.stderr) )); if output.status.success() { - logger::write("Update Proxy Agent command output successfully".to_string()); status.configurationAppliedTime = misc_helpers::get_date_time_string(); status.code = constants::STATUS_CODE_OK; status.status = status_state_obj.update_state(false); - status.formattedMessage.message = - "Update Proxy Agent command output successfully".to_string(); + status.formattedMessage.message = message; status.substatus = Default::default(); common::report_status(status_folder, seq_no, status); } else { + let err_message = format!( + "Execute Install Command in Proxy Agent Setup Tool Output Status Not Success: {}", + String::from_utf8_lossy(&output.stderr) + ); telemetry::event_logger::write_event( - LoggerLevel::Info, - format!( - "Update Proxy Agent command failed with error: {}", - String::from_utf8_lossy(&output.stderr) - ), + LoggerLevel::Warn, + err_message.clone(), "report_proxy_agent_service_status", "service_main", &logger::get_logger_key(), @@ -736,16 +742,18 @@ fn report_proxy_agent_service_status( .code() .unwrap_or(constants::STATUS_CODE_NOT_OK); status.status = status_state_obj.update_state(false); - status.formattedMessage.message = - "Update Proxy Agent command failed with error".to_string(); + status.formattedMessage.message = err_message.clone(); status.substatus = Default::default(); common::report_status(status_folder, seq_no, status); } } Err(e) => { + let err_message = format!( + "Failed to execute Install Proxy Agent Command Through Setup Tool with error: {e}" + ); telemetry::event_logger::write_event( - LoggerLevel::Info, - format!("Error in running Update Proxy Agent command: {e}"), + LoggerLevel::Warn, + err_message.clone(), "report_proxy_agent_service_status", "service_main", &logger::get_logger_key(), @@ -754,8 +762,7 @@ fn report_proxy_agent_service_status( status.configurationAppliedTime = misc_helpers::get_date_time_string(); 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}"); + status.formattedMessage.message = err_message.clone(); status.substatus = Default::default(); common::report_status(status_folder, seq_no, status); } From c97dacac61f07fb817fb8fce88e13827db2b6210 Mon Sep 17 00:00:00 2001 From: Zhidong Peng Date: Wed, 27 Aug 2025 12:01:13 -0700 Subject: [PATCH 5/8] Change windows GuestProxyAgent service cpu quota to 15 (#267) * Add more trace logging * change windows GuestProxyAgent service cpu quota to 15 --------- Co-authored-by: Zhidong Peng --- proxy_agent/src/proxy/proxy_server.rs | 38 ++++++++++++++++++- .../src/windows/HandlerManifest.json | 2 +- 2 files changed, 38 insertions(+), 2 deletions(-) diff --git a/proxy_agent/src/proxy/proxy_server.rs b/proxy_agent/src/proxy/proxy_server.rs index bbfb8a54..b75eedb9 100644 --- a/proxy_agent/src/proxy/proxy_server.rs +++ b/proxy_agent/src/proxy/proxy_server.rs @@ -458,7 +458,7 @@ impl ProxyServer { return Ok(Self::closed_response(StatusCode::MISDIRECTED_REQUEST)); } }; - http_connection_context.log(LoggerLevel::Trace, claim_details.to_string()); + http_connection_context.log(LoggerLevel::Info, claim_details.to_string()); // authenticate the connection let access_control_rules = match proxy_authorizer::get_access_control_rules( @@ -560,6 +560,13 @@ impl ProxyServer { } // start new request to the Host endpoint + http_connection_context.log( + LoggerLevel::Trace, + format!( + "Start new request to {} {}", + http_connection_context.method, http_connection_context.url + ), + ); let request = match Self::convert_request(proxy_request).await { Ok(r) => r, Err(e) => { @@ -570,7 +577,21 @@ impl ProxyServer { return Ok(Self::closed_response(StatusCode::BAD_REQUEST)); } }; + http_connection_context.log( + LoggerLevel::Trace, + format!( + "Forwarding request to {} {}", + http_connection_context.method, http_connection_context.url + ), + ); let proxy_response = http_connection_context.send_request(request).await; + http_connection_context.log( + LoggerLevel::Trace, + format!( + "Received response from {} {}", + http_connection_context.method, http_connection_context.url + ), + ); self.forward_response(proxy_response, http_connection_context) .await } @@ -923,7 +944,22 @@ impl ProxyServer { } // start new request to the Host endpoint + http_connection_context.log( + LoggerLevel::Trace, + format!( + "Forwarding request to {} {}", + http_connection_context.method, http_connection_context.url + ), + ); let proxy_response = http_connection_context.send_request(proxy_request).await; + http_connection_context.log( + LoggerLevel::Trace, + format!( + "Received response from {} {}", + http_connection_context.method, http_connection_context.url + ), + ); + // forward the response to the client self.forward_response(proxy_response, http_connection_context) .await } diff --git a/proxy_agent_extension/src/windows/HandlerManifest.json b/proxy_agent_extension/src/windows/HandlerManifest.json index 991ec4b7..07dafeea 100644 --- a/proxy_agent_extension/src/windows/HandlerManifest.json +++ b/proxy_agent_extension/src/windows/HandlerManifest.json @@ -19,7 +19,7 @@ }, { "name": "GuestProxyAgent", - "cpuQuotaPercentage": 2, + "cpuQuotaPercentage": 15, "memoryQuotaMB": 17 }] } From e739aad1619f89e196027a2db2d9246a7e21f091 Mon Sep 17 00:00:00 2001 From: Zhidong Peng Date: Tue, 2 Sep 2025 10:33:47 -0700 Subject: [PATCH 6/8] proxy_agent_setup tool write_error if process exit non-0 code. (#268) * proxy_agent_setup tool write_error if process exit non-0 code. * formatting. --- proxy_agent_setup/src/logger.rs | 5 +++++ proxy_agent_setup/src/main.rs | 8 ++++---- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/proxy_agent_setup/src/logger.rs b/proxy_agent_setup/src/logger.rs index 7c870ec6..00db3cc2 100644 --- a/proxy_agent_setup/src/logger.rs +++ b/proxy_agent_setup/src/logger.rs @@ -22,3 +22,8 @@ pub fn write(message: String) { println!("{message}"); logger_manager::log(LOGGER_KEY.to_string(), LoggerLevel::Info, message); } + +pub fn write_error(message: String) { + eprintln!("{message}"); + logger_manager::log(LOGGER_KEY.to_string(), LoggerLevel::Error, message); +} diff --git a/proxy_agent_setup/src/main.rs b/proxy_agent_setup/src/main.rs index 17cdac12..d7584b84 100644 --- a/proxy_agent_setup/src/main.rs +++ b/proxy_agent_setup/src/main.rs @@ -187,7 +187,7 @@ async fn setup_service(proxy_agent_target_folder: PathBuf, _service_config_folde logger::write(format!("Setup service {SERVICE_NAME} successfully")); } Err(e) => { - logger::write(format!("Setup service {SERVICE_NAME} failed, error: {e:?}")); + logger::write_error(format!("Setup service {SERVICE_NAME} failed, error: {e:?}")); process::exit(1); } } @@ -203,7 +203,7 @@ async fn setup_service(proxy_agent_target_folder: PathBuf, _service_config_folde logger::write(format!("Install service {SERVICE_NAME} successfully")); } Err(e) => { - logger::write(format!( + logger::write_error(format!( "Install service {SERVICE_NAME} failed, error: {e:?}", )); process::exit(1); @@ -247,7 +247,7 @@ async fn setup_service(proxy_agent_target_folder: PathBuf, _service_config_folde logger::write(format!("Service {SERVICE_NAME} start successfully")); } Err(e) => { - logger::write(format!("Service {SERVICE_NAME} start failed, error: {e:?}")); + logger::write_error(format!("Service {SERVICE_NAME} start failed, error: {e:?}")); process::exit(1); } } @@ -274,7 +274,7 @@ async fn uninstall_service() -> PathBuf { logger::write(format!("Uninstall service {SERVICE_NAME} successfully")); } Err(e) => { - logger::write(format!( + logger::write_error(format!( "Uninstall service {SERVICE_NAME} failed, error: {e:?}" )); process::exit(1); From 1ecb9a63d67bd050d1ba138a11b33032e67dad29 Mon Sep 17 00:00:00 2001 From: Zhidong Peng Date: Tue, 2 Sep 2025 12:21:56 -0700 Subject: [PATCH 7/8] Windows GPA to close the process handler using `close_process_handler` (#269) * Windows GPA to close the process handler using `close_process_handler` * fix spelling --- .github/actions/spelling/expect.txt | 4 +++ build.cmd | 5 ++-- proxy_agent/src/proxy.rs | 4 +++ proxy_agent/src/proxy/windows.rs | 39 +++++++++++++++++++++++++---- 4 files changed, 45 insertions(+), 7 deletions(-) diff --git a/.github/actions/spelling/expect.txt b/.github/actions/spelling/expect.txt index 06de539d..7809ed51 100644 --- a/.github/actions/spelling/expect.txt +++ b/.github/actions/spelling/expect.txt @@ -34,6 +34,7 @@ ccbf cicd cimv cla +closehandle cmds codeofconduct codeql @@ -120,6 +121,7 @@ gpalinuxdev gpawindev guestproxyagentmsis guiddef +handleapi hklm hlist hostga @@ -195,6 +197,7 @@ ntdll NTSTATUS onscreen onebranch +openprocess oneshot opencode opensource @@ -213,6 +216,7 @@ prefmaxlen preprovisioned printk PROCESSINFOCLASS +processthreadsapi proxyagent proxyagentextensionvalidation proxyagentvalidation diff --git a/build.cmd b/build.cmd index 903c08b5..998a99da 100644 --- a/build.cmd +++ b/build.cmd @@ -243,7 +243,8 @@ xcopy /Y %out_dir%\proxy_agent_setup.pdb %out_package_dir%\ echo ======= copy to ProxyAgent folder xcopy /Y %out_dir%\azure-proxy-agent.exe %out_package_proxyagent_dir%\GuestProxyAgent.exe* -xcopy /Y %out_dir%\azure_proxy_agent.pdb %out_package_proxyagent_dir%\GuestProxyAgent.pdb* +REM do NOT rename pdb file, as it is used by the debugger to load the symbols automatically +xcopy /Y %out_dir%\azure_proxy_agent.pdb %out_package_proxyagent_dir%\ xcopy /Y %out_dir%\GuestProxyAgent.json %out_package_proxyagent_dir%\ SET out_package_proxyagent_extension_dir=%out_package_dir%\ProxyAgent_Extension @@ -254,7 +255,7 @@ for %%F in (%extension_src_path%\*.cmd) do ( echo Found file: %%F xcopy /Y %%F %out_package_proxyagent_extension_dir%\ ) -xcopy /Y %out_dir%\ProxyAgentExt.exe %out_package_proxyagent_extension_dir%\ +xcopy /Y %out_dir%\ProxyAgentExt.* %out_package_proxyagent_extension_dir%\ echo ======= copy e2e test project to Package folder SET out_package_e2etest_dir=%out_package_dir%\e2etest diff --git a/proxy_agent/src/proxy.rs b/proxy_agent/src/proxy.rs index 19be4655..23a87f2d 100644 --- a/proxy_agent/src/proxy.rs +++ b/proxy_agent/src/proxy.rs @@ -181,6 +181,10 @@ impl Process { println!("Failed to query basic process info: {e}"); } } + // close the handle + if let Err(e) = windows::close_process_handler(handler) { + println!("Failed to close process handler: {e}"); + } } #[cfg(not(windows))] { diff --git a/proxy_agent/src/proxy/windows.rs b/proxy_agent/src/proxy/windows.rs index f5acc659..145b84d7 100644 --- a/proxy_agent/src/proxy/windows.rs +++ b/proxy_agent/src/proxy/windows.rs @@ -15,7 +15,7 @@ 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::Foundation::{CloseHandle, BOOL, HANDLE, LUID, NTSTATUS, UNICODE_STRING}; use windows_sys::Win32::Security::Authentication::Identity; use windows_sys::Win32::Security::Authentication::Identity::{ LSA_UNICODE_STRING, SECURITY_LOGON_SESSION_DATA, @@ -269,21 +269,50 @@ pub fn query_basic_process_info(handler: isize) -> Result` - Process handler +/// # Errors +/// * `Error::Invalid` - If the pid is 0 +/// * `Error::WindowsApi` - If the OpenProcess call fails +/// # Safety +/// This function is safe to call as it does not dereference any raw pointers. +/// However, the caller is responsible for closing the process handler using `close_process_handler` +/// when it is no longer needed to avoid resource leaks. pub fn get_process_handler(pid: u32) -> Result { if pid == 0 { return Err(Error::Invalid("pid 0".to_string())); } let options = PROCESS_QUERY_INFORMATION | PROCESS_VM_READ; - unsafe { - let handler = OpenProcess(options, FALSE, pid); - if handler == 0 { + // https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-openprocess + let handler = unsafe { OpenProcess(options, FALSE, pid) }; + if handler == 0 { + return Err(Error::WindowsApi(WindowsApiErrorType::WindowsOsError( + std::io::Error::last_os_error(), + ))); + } + Ok(handler) +} + +/// Close process handler +/// # Arguments +/// * `handler` - Process handler +/// # Returns +/// * `Result<()>` - Ok if successful, Err if failed +pub fn close_process_handler(handler: HANDLE) -> Result<()> { + if handler != 0 { + // https://learn.microsoft.com/en-us/windows/win32/api/handleapi/nf-handleapi-closehandle + if 0 != unsafe { CloseHandle(handler) } { return Err(Error::WindowsApi(WindowsApiErrorType::WindowsOsError( std::io::Error::last_os_error(), ))); } - Ok(handler) } + Ok(()) } pub fn get_process_cmd(handler: isize) -> Result { From a9aa9a43b61f06126008e9251db16d82bc41752c Mon Sep 17 00:00:00 2001 From: Zhidong Peng Date: Tue, 2 Sep 2025 12:26:00 -0700 Subject: [PATCH 8/8] Prepre build for 1.0.36 release --- Cargo.lock | 8 ++++---- proxy_agent/Cargo.toml | 2 +- proxy_agent_extension/Cargo.toml | 2 +- proxy_agent_setup/Cargo.toml | 2 +- proxy_agent_shared/Cargo.toml | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 68b70c82..43e2eec2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,7 +4,7 @@ version = 4 [[package]] name = "ProxyAgentExt" -version = "1.0.35" +version = "1.0.36" dependencies = [ "clap", "ctor", @@ -172,7 +172,7 @@ dependencies = [ [[package]] name = "azure-proxy-agent" -version = "1.0.35" +version = "1.0.36" dependencies = [ "aya", "bitflags", @@ -865,7 +865,7 @@ dependencies = [ [[package]] name = "proxy_agent_setup" -version = "1.0.35" +version = "1.0.36" dependencies = [ "clap", "proxy_agent_shared", @@ -877,7 +877,7 @@ dependencies = [ [[package]] name = "proxy_agent_shared" -version = "1.0.35" +version = "1.0.36" dependencies = [ "backtrace", "chrono", diff --git a/proxy_agent/Cargo.toml b/proxy_agent/Cargo.toml index 07c9ef65..45633eb2 100644 --- a/proxy_agent/Cargo.toml +++ b/proxy_agent/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "azure-proxy-agent" -version = "1.0.35" # always 3-number version +version = "1.0.36" # 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 diff --git a/proxy_agent_extension/Cargo.toml b/proxy_agent_extension/Cargo.toml index 990ed6c5..1636785b 100644 --- a/proxy_agent_extension/Cargo.toml +++ b/proxy_agent_extension/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ProxyAgentExt" -version = "1.0.35" # always 3-number version +version = "1.0.36" # 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_setup/Cargo.toml b/proxy_agent_setup/Cargo.toml index 383f70bd..4ed7be5f 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.35" +version = "1.0.36" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/proxy_agent_shared/Cargo.toml b/proxy_agent_shared/Cargo.toml index 14cfb01e..45832cc1 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.35" +version = "1.0.36" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html