From e5c3dde1f771b9c0efd1682c58bd316ecf9eb8fb Mon Sep 17 00:00:00 2001 From: Prashant Kumar Date: Thu, 6 Aug 2026 15:55:43 +0530 Subject: [PATCH 1/5] Merge MongoDB YCSB Ubuntu/AzureLinux profiles using shell-based package manager detection The Ubuntu and AzureLinux MongoDB YCSB profiles were identical except for the MongoDB repository setup and install steps (apt/gnupg vs rpm/dnf). Collapse the six divergent dependency steps into single ExecuteCommand steps that run with UseShell and branch on the available package manager, so one profile covers both operating systems. Removes PERF-MONGODB-YCSB-AZURELINUX.json. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../PERF-MONGODB-YCSB-THREAD-SWEEP.json | 322 ++++++++++++++++++ .../profiles/PERF-MONGODB-YCSB.json | 43 +-- .../workloads/mongodb/mongodb-profiles.md | 1 + 3 files changed, 334 insertions(+), 32 deletions(-) create mode 100644 src/VirtualClient/VirtualClient.Main/profiles/PERF-MONGODB-YCSB-THREAD-SWEEP.json diff --git a/src/VirtualClient/VirtualClient.Main/profiles/PERF-MONGODB-YCSB-THREAD-SWEEP.json b/src/VirtualClient/VirtualClient.Main/profiles/PERF-MONGODB-YCSB-THREAD-SWEEP.json new file mode 100644 index 0000000000..0a5cc3ce52 --- /dev/null +++ b/src/VirtualClient/VirtualClient.Main/profiles/PERF-MONGODB-YCSB-THREAD-SWEEP.json @@ -0,0 +1,322 @@ +{ + "Description": "MongoDB YCSB client-server workload with a thread-count sweep (2-VM)", + "Metadata": { + "RecommendedMinimumExecutionTime": "01:00:00", + "SupportedPlatforms": "linux-x64,linux-arm64", + "SupportedOperatingSystems": "AzureLinux,Ubuntu", + "Notes": "Repeats load+run for each thread value (4, 8, 16, 32, 64) using YCSB workloada. Each load action drops the existing database before reloading, so every thread iteration starts from a clean database. Total execution time scales with the number of thread values swept." + }, + "Parameters": { + "Port": 27017, + "Database": "mongodb", + "Duration": "00:05:00", + "RecordCount": "500000", + "DiskFilter": "BiggestSize" + }, + "Actions": [ + { + "Type": "MongoDBServerExecutor", + "Parameters": { + "Scenario": "ServerSetup", + "Role": "Server", + "Port": "$.Parameters.Port", + "Database": "$.Parameters.Database", + "DiskFilter": "$.Parameters.DiskFilter" + } + }, + { + "Type": "MongoDBClientExecutor", + "Parameters": { + "Scenario": "Load_Database_Threads_4", + "Role": "Client", + "Database": "$.Parameters.Database", + "Port": "$.Parameters.Port", + "LoadCommand": "load {Database} -s -p maxexecutiontime=600 -p recordcount={RecordCount} -p fieldcount={FieldCount} -p fieldlength={FieldLength} -threads {ThreadCount} -p mongodb.url=mongodb://{ServerIP}:{Port}/ycsb -P {PackagePath:ycsb}/ycsb-0.17.0/workloads/workloada", + "Duration": "$.Parameters.Duration", + "ThreadCount": "4", + "YCSBPackageName": "ycsb", + "JdkPackageName": "javadevelopmentkit", + "RecordCount": "$.Parameters.RecordCount", + "FieldCount": "128", + "FieldLength": "128" + } + }, + { + "Type": "MongoDBClientExecutor", + "Parameters": { + "Scenario": "Workload_A_Threads_4", + "Role": "Client", + "MetricScenario": "workloada_th4", + "Database": "$.Parameters.Database", + "Port": "$.Parameters.Port", + "RunCommand": "run {Database} -s -p maxexecutiontime={Duration.TotalSeconds} -p operationcount={OperationCount} -p recordcount={RecordCount} -threads {ThreadCount} -p fieldcount={FieldCount} -p fieldlength={FieldLength} -p mongodb.url=mongodb://{ServerIP}:{Port}/ycsb -P {PackagePath:ycsb}/ycsb-0.17.0/workloads/workloada", + "Duration": "$.Parameters.Duration", + "ThreadCount": "4", + "OperationCount": "5000000", + "YCSBPackageName": "ycsb", + "JdkPackageName": "javadevelopmentkit", + "RecordCount": "$.Parameters.RecordCount", + "FieldCount": "128", + "FieldLength": "128" + } + }, + { + "Type": "MongoDBClientExecutor", + "Parameters": { + "Scenario": "Load_Database_Threads_8", + "Role": "Client", + "Database": "$.Parameters.Database", + "Port": "$.Parameters.Port", + "LoadCommand": "load {Database} -s -p maxexecutiontime=600 -p recordcount={RecordCount} -p fieldcount={FieldCount} -p fieldlength={FieldLength} -threads {ThreadCount} -p mongodb.url=mongodb://{ServerIP}:{Port}/ycsb -P {PackagePath:ycsb}/ycsb-0.17.0/workloads/workloada", + "Duration": "$.Parameters.Duration", + "ThreadCount": "8", + "YCSBPackageName": "ycsb", + "JdkPackageName": "javadevelopmentkit", + "RecordCount": "$.Parameters.RecordCount", + "FieldCount": "128", + "FieldLength": "128" + } + }, + { + "Type": "MongoDBClientExecutor", + "Parameters": { + "Scenario": "Workload_A_Threads_8", + "Role": "Client", + "MetricScenario": "workloada_th8", + "Database": "$.Parameters.Database", + "Port": "$.Parameters.Port", + "RunCommand": "run {Database} -s -p maxexecutiontime={Duration.TotalSeconds} -p operationcount={OperationCount} -p recordcount={RecordCount} -threads {ThreadCount} -p fieldcount={FieldCount} -p fieldlength={FieldLength} -p mongodb.url=mongodb://{ServerIP}:{Port}/ycsb -P {PackagePath:ycsb}/ycsb-0.17.0/workloads/workloada", + "Duration": "$.Parameters.Duration", + "ThreadCount": "8", + "OperationCount": "5000000", + "YCSBPackageName": "ycsb", + "JdkPackageName": "javadevelopmentkit", + "RecordCount": "$.Parameters.RecordCount", + "FieldCount": "128", + "FieldLength": "128" + } + }, + { + "Type": "MongoDBClientExecutor", + "Parameters": { + "Scenario": "Load_Database_Threads_16", + "Role": "Client", + "Database": "$.Parameters.Database", + "Port": "$.Parameters.Port", + "LoadCommand": "load {Database} -s -p maxexecutiontime=600 -p recordcount={RecordCount} -p fieldcount={FieldCount} -p fieldlength={FieldLength} -threads {ThreadCount} -p mongodb.url=mongodb://{ServerIP}:{Port}/ycsb -P {PackagePath:ycsb}/ycsb-0.17.0/workloads/workloada", + "Duration": "$.Parameters.Duration", + "ThreadCount": "16", + "YCSBPackageName": "ycsb", + "JdkPackageName": "javadevelopmentkit", + "RecordCount": "$.Parameters.RecordCount", + "FieldCount": "128", + "FieldLength": "128" + } + }, + { + "Type": "MongoDBClientExecutor", + "Parameters": { + "Scenario": "Workload_A_Threads_16", + "Role": "Client", + "MetricScenario": "workloada_th16", + "Database": "$.Parameters.Database", + "Port": "$.Parameters.Port", + "RunCommand": "run {Database} -s -p maxexecutiontime={Duration.TotalSeconds} -p operationcount={OperationCount} -p recordcount={RecordCount} -threads {ThreadCount} -p fieldcount={FieldCount} -p fieldlength={FieldLength} -p mongodb.url=mongodb://{ServerIP}:{Port}/ycsb -P {PackagePath:ycsb}/ycsb-0.17.0/workloads/workloada", + "Duration": "$.Parameters.Duration", + "ThreadCount": "16", + "OperationCount": "5000000", + "YCSBPackageName": "ycsb", + "JdkPackageName": "javadevelopmentkit", + "RecordCount": "$.Parameters.RecordCount", + "FieldCount": "128", + "FieldLength": "128" + } + }, + { + "Type": "MongoDBClientExecutor", + "Parameters": { + "Scenario": "Load_Database_Threads_32", + "Role": "Client", + "Database": "$.Parameters.Database", + "Port": "$.Parameters.Port", + "LoadCommand": "load {Database} -s -p maxexecutiontime=600 -p recordcount={RecordCount} -p fieldcount={FieldCount} -p fieldlength={FieldLength} -threads {ThreadCount} -p mongodb.url=mongodb://{ServerIP}:{Port}/ycsb -P {PackagePath:ycsb}/ycsb-0.17.0/workloads/workloada", + "Duration": "$.Parameters.Duration", + "ThreadCount": "32", + "YCSBPackageName": "ycsb", + "JdkPackageName": "javadevelopmentkit", + "RecordCount": "$.Parameters.RecordCount", + "FieldCount": "128", + "FieldLength": "128" + } + }, + { + "Type": "MongoDBClientExecutor", + "Parameters": { + "Scenario": "Workload_A_Threads_32", + "Role": "Client", + "MetricScenario": "workloada_th32", + "Database": "$.Parameters.Database", + "Port": "$.Parameters.Port", + "RunCommand": "run {Database} -s -p maxexecutiontime={Duration.TotalSeconds} -p operationcount={OperationCount} -p recordcount={RecordCount} -threads {ThreadCount} -p fieldcount={FieldCount} -p fieldlength={FieldLength} -p mongodb.url=mongodb://{ServerIP}:{Port}/ycsb -P {PackagePath:ycsb}/ycsb-0.17.0/workloads/workloada", + "Duration": "$.Parameters.Duration", + "ThreadCount": "32", + "OperationCount": "5000000", + "YCSBPackageName": "ycsb", + "JdkPackageName": "javadevelopmentkit", + "RecordCount": "$.Parameters.RecordCount", + "FieldCount": "128", + "FieldLength": "128" + } + }, + { + "Type": "MongoDBClientExecutor", + "Parameters": { + "Scenario": "Load_Database_Threads_64", + "Role": "Client", + "Database": "$.Parameters.Database", + "Port": "$.Parameters.Port", + "LoadCommand": "load {Database} -s -p maxexecutiontime=600 -p recordcount={RecordCount} -p fieldcount={FieldCount} -p fieldlength={FieldLength} -threads {ThreadCount} -p mongodb.url=mongodb://{ServerIP}:{Port}/ycsb -P {PackagePath:ycsb}/ycsb-0.17.0/workloads/workloada", + "Duration": "$.Parameters.Duration", + "ThreadCount": "64", + "YCSBPackageName": "ycsb", + "JdkPackageName": "javadevelopmentkit", + "RecordCount": "$.Parameters.RecordCount", + "FieldCount": "128", + "FieldLength": "128" + } + }, + { + "Type": "MongoDBClientExecutor", + "Parameters": { + "Scenario": "Workload_A_Threads_64", + "Role": "Client", + "MetricScenario": "workloada_th64", + "Database": "$.Parameters.Database", + "Port": "$.Parameters.Port", + "RunCommand": "run {Database} -s -p maxexecutiontime={Duration.TotalSeconds} -p operationcount={OperationCount} -p recordcount={RecordCount} -threads {ThreadCount} -p fieldcount={FieldCount} -p fieldlength={FieldLength} -p mongodb.url=mongodb://{ServerIP}:{Port}/ycsb -P {PackagePath:ycsb}/ycsb-0.17.0/workloads/workloada", + "Duration": "$.Parameters.Duration", + "ThreadCount": "64", + "OperationCount": "5000000", + "YCSBPackageName": "ycsb", + "JdkPackageName": "javadevelopmentkit", + "RecordCount": "$.Parameters.RecordCount", + "FieldCount": "128", + "FieldLength": "128" + } + } + ], + "Dependencies": [ + { + "Type": "JDKPackageDependencyInstallation", + "Parameters": { + "Scenario": "InstallJDKPackage", + "BlobContainer": "packages", + "BlobName": "microsoft-jdk-21.0.1.zip", + "PackageName": "javadevelopmentkit", + "Extract": true, + "Role": "Client" + } + }, + { + "Type": "LinuxPackageInstallation", + "Parameters": { + "Scenario": "InstallMongoPrereqs", + "Packages-Apt": "gnupg,curl,lshw", + "Packages-Dnf": "gnupg2,curl,lshw", + "Packages-Yum": "gnupg2,curl,lshw", + "Packages-Zypper": "gpg2,curl,lshw" + } + }, + { + "Type": "ExecuteCommand", + "Parameters": { + "Scenario": "MongoAddRepository", + "SupportedPlatforms": "linux-x64,linux-arm64", + "UseShell": true, + "Command": "set -e; if command -v apt-get >/dev/null 2>&1; then curl -fsSL https://www.mongodb.org/static/pgp/server-8.0.asc -o /tmp/mongodb-server-8.0.asc; sudo gpg --batch --yes --dearmor -o /usr/share/keyrings/mongodb-server-8.0.gpg /tmp/mongodb-server-8.0.asc; echo 'deb [ arch=amd64,arm64 signed-by=/usr/share/keyrings/mongodb-server-8.0.gpg ] https://repo.mongodb.org/apt/ubuntu noble/mongodb-org/8.0 multiverse' | sudo tee /etc/apt/sources.list.d/mongodb-org-8.0.list; sudo apt-get update; elif command -v dnf >/dev/null 2>&1 || command -v tdnf >/dev/null 2>&1; then sudo rpm --import https://pgp.mongodb.com/server-8.0.asc; { echo '[mongodb-org-8.0]'; echo 'name=MongoDB Repository'; echo 'baseurl=https://repo.mongodb.org/yum/redhat/9/mongodb-org/8.0/$basearch/'; echo 'gpgcheck=1'; echo 'enabled=1'; echo 'gpgkey=https://pgp.mongodb.com/server-8.0.asc'; } | sudo tee /etc/yum.repos.d/mongodb-org-8.0.repo; sudo dnf makecache --refresh; else echo 'Unsupported package manager. MongoDB repository setup requires apt-get or dnf.' 1>&2; exit 1; fi" + } + }, + { + "Type": "ExecuteCommand", + "Parameters": { + "Scenario": "MongoInstallServer", + "SupportedPlatforms": "linux-x64,linux-arm64", + "UseShell": true, + "Command": "set -e; if command -v apt-get >/dev/null 2>&1; then sudo apt-get install -y mongodb-org; else sudo dnf install -y mongodb-org; fi", + "Role": "Server" + } + }, + { + "Type": "ExecuteCommand", + "Parameters": { + "Scenario": "MongoInstallClient", + "SupportedPlatforms": "linux-x64,linux-arm64", + "UseShell": true, + "Command": "set -e; if command -v apt-get >/dev/null 2>&1; then sudo apt-get install -y mongodb-mongosh; else sudo dnf install -y mongodb-mongosh; fi", + "Role": "Client" + } + }, + { + "Type": "ExecuteCommand", + "Parameters": { + "Scenario": "MongoDaemon", + "SupportedPlatforms": "linux-x64,linux-arm64", + "Command": "sudo systemctl daemon-reload", + "Role": "Server" + } + }, + { + "Type": "ExecuteCommand", + "Parameters": { + "Scenario": "MongoStartService", + "SupportedPlatforms": "linux-x64,linux-arm64", + "Command": "sudo systemctl start mongod", + "Role": "Server" + } + }, + { + "Type": "ExecuteCommand", + "Parameters": { + "Scenario": "MongoEnableService", + "SupportedPlatforms": "linux-x64,linux-arm64", + "Command": "sudo systemctl enable mongod", + "Role": "Server" + } + }, + { + "Type": "ExecuteCommand", + "Parameters": { + "Scenario": "MongoServerStatus", + "SupportedPlatforms": "linux-x64,linux-arm64", + "Command": "sudo systemctl status mongod", + "Role": "Server" + } + }, + { + "Type": "ExecuteCommand", + "Parameters": { + "Scenario": "MongoStopService", + "SupportedPlatforms": "linux-x64,linux-arm64", + "Command": "sudo systemctl stop mongod", + "Role": "Server" + } + }, + { + "Type": "DependencyPackageInstallation", + "Parameters": { + "Scenario": "InstallYCSBPackage", + "BlobContainer": "packages", + "BlobName": "ycsb-0.17.0.zip", + "PackageName": "ycsb", + "Extract": true, + "Role": "Client" + } + }, + { + "Type": "ApiServer", + "Parameters": { + "Scenario": "StartAPIServer" + } + } + ] +} diff --git a/src/VirtualClient/VirtualClient.Main/profiles/PERF-MONGODB-YCSB.json b/src/VirtualClient/VirtualClient.Main/profiles/PERF-MONGODB-YCSB.json index a70ac9ef05..0ff2a18d20 100644 --- a/src/VirtualClient/VirtualClient.Main/profiles/PERF-MONGODB-YCSB.json +++ b/src/VirtualClient/VirtualClient.Main/profiles/PERF-MONGODB-YCSB.json @@ -3,7 +3,7 @@ "Metadata": { "RecommendedMinimumExecutionTime": "00:15:00", "SupportedPlatforms": "linux-x64,linux-arm64", - "SupportedOperatingSystems": "Ubuntu", + "SupportedOperatingSystems": "AzureLinux,Ubuntu", "Notes": "Database sizes vary based on RecordCount: Small (500000 records) ~8-10 GB, Medium (2500000 records) ~40-50 GB, Large (20000000 records) ~320-400 GB, XLarge (55000000 records) ~900 GB-1 TB. Default configuration uses Medium size (~40-50 GB) with 2500000 records." }, "Parameters": { @@ -173,26 +173,10 @@ "Type": "LinuxPackageInstallation", "Parameters": { "Scenario": "InstallMongoPrereqs", - "Packages-Apt": "gnupg,curl", - "Packages-Dnf": "gnupg,curl", - "Packages-Yum": "gnupg,curl", - "Packages-Zypper": "gpg2,curl" - } - }, - { - "Type": "ExecuteCommand", - "Parameters": { - "Scenario": "MongoGPGKey", - "SupportedPlatforms": "linux-x64,linux-arm64", - "Command": "curl -fsSL https://www.mongodb.org/static/pgp/server-8.0.asc -o server-8.0.asc" - } - }, - { - "Type": "ExecuteCommand", - "Parameters": { - "Scenario": "MongoGPGDearmor", - "SupportedPlatforms": "linux-x64,linux-arm64", - "Command": "sudo gpg --batch --yes --dearmor -o /usr/share/keyrings/mongodb-server-8.0.gpg server-8.0.asc" + "Packages-Apt": "gnupg,curl,lshw", + "Packages-Dnf": "gnupg2,curl,lshw", + "Packages-Yum": "gnupg2,curl,lshw", + "Packages-Zypper": "gpg2,curl,lshw" } }, { @@ -200,15 +184,8 @@ "Parameters": { "Scenario": "MongoAddRepository", "SupportedPlatforms": "linux-x64,linux-arm64", - "Command": "sudo sh -c \"echo 'deb [ arch=amd64,arm64 signed-by=/usr/share/keyrings/mongodb-server-8.0.gpg ] https://repo.mongodb.org/apt/ubuntu noble/mongodb-org/8.0 multiverse' > /etc/apt/sources.list.d/mongodb-org-8.0.list\"" - } - }, - { - "Type": "ExecuteCommand", - "Parameters": { - "Scenario": "MongoUpdatePackageList", - "SupportedPlatforms": "linux-x64,linux-arm64", - "Command": "sudo apt-get update" + "UseShell": true, + "Command": "set -e; if command -v apt-get >/dev/null 2>&1; then curl -fsSL https://www.mongodb.org/static/pgp/server-8.0.asc -o /tmp/mongodb-server-8.0.asc; sudo gpg --batch --yes --dearmor -o /usr/share/keyrings/mongodb-server-8.0.gpg /tmp/mongodb-server-8.0.asc; echo 'deb [ arch=amd64,arm64 signed-by=/usr/share/keyrings/mongodb-server-8.0.gpg ] https://repo.mongodb.org/apt/ubuntu noble/mongodb-org/8.0 multiverse' | sudo tee /etc/apt/sources.list.d/mongodb-org-8.0.list; sudo apt-get update; elif command -v dnf >/dev/null 2>&1 || command -v tdnf >/dev/null 2>&1; then sudo rpm --import https://pgp.mongodb.com/server-8.0.asc; { echo '[mongodb-org-8.0]'; echo 'name=MongoDB Repository'; echo 'baseurl=https://repo.mongodb.org/yum/redhat/9/mongodb-org/8.0/$basearch/'; echo 'gpgcheck=1'; echo 'enabled=1'; echo 'gpgkey=https://pgp.mongodb.com/server-8.0.asc'; } | sudo tee /etc/yum.repos.d/mongodb-org-8.0.repo; sudo dnf makecache --refresh; else echo 'Unsupported package manager. MongoDB repository setup requires apt-get or dnf.' 1>&2; exit 1; fi" } }, { @@ -216,7 +193,8 @@ "Parameters": { "Scenario": "MongoInstallServer", "SupportedPlatforms": "linux-x64,linux-arm64", - "Command": "sudo apt-get install -y mongodb-org", + "UseShell": true, + "Command": "set -e; if command -v apt-get >/dev/null 2>&1; then sudo apt-get install -y mongodb-org; else sudo dnf install -y mongodb-org; fi", "Role": "Server" } }, @@ -225,7 +203,8 @@ "Parameters": { "Scenario": "MongoInstallClient", "SupportedPlatforms": "linux-x64,linux-arm64", - "Command": "sudo apt-get install -y mongodb-mongosh", + "UseShell": true, + "Command": "set -e; if command -v apt-get >/dev/null 2>&1; then sudo apt-get install -y mongodb-mongosh; else sudo dnf install -y mongodb-mongosh; fi", "Role": "Client" } }, diff --git a/website/docs/workloads/mongodb/mongodb-profiles.md b/website/docs/workloads/mongodb/mongodb-profiles.md index f5cad62fab..61acb18c3a 100644 --- a/website/docs/workloads/mongodb/mongodb-profiles.md +++ b/website/docs/workloads/mongodb/mongodb-profiles.md @@ -50,6 +50,7 @@ This profile loads a dataset into MongoDB and then runs various read, write, sca * linux-arm64 * **Supported Operating Systems** + * AzureLinux * Ubuntu * **Supports Disconnected Scenarios** From 913355b7fc5331f1c574a22c7a060b2932adbb70 Mon Sep 17 00:00:00 2001 From: Prashant Kumar Date: Fri, 7 Aug 2026 19:21:25 +0530 Subject: [PATCH 2/5] Fix MongoDB server setup on RPM-based Linux distributions Resolve the mongod service account at runtime instead of hardcoding 'mongodb'. RPM packages (Azure Linux, RHEL, Fedora) create a 'mongod' account while Debian packages create 'mongodb', so the data directory was left owned by root and mongod exited with status 100. Open the MongoDB port via IFirewallManager during initialization. Azure Linux applies a default-deny inbound policy (iptables INPUT policy DROP), so the client could not reach the server. Both failures were previously downgraded to warnings, so runs reported exit code 0 while MongoDB had never started. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../MongoDB/MongoDBServerExecutorTests.cs | 71 +++++++++++++++++++ .../MongoDB/MongoDBServerExecutor.cs | 42 ++++++++++- 2 files changed, 111 insertions(+), 2 deletions(-) diff --git a/src/VirtualClient/VirtualClient.Actions.UnitTests/MongoDB/MongoDBServerExecutorTests.cs b/src/VirtualClient/VirtualClient.Actions.UnitTests/MongoDB/MongoDBServerExecutorTests.cs index e188862b90..08446fde78 100644 --- a/src/VirtualClient/VirtualClient.Actions.UnitTests/MongoDB/MongoDBServerExecutorTests.cs +++ b/src/VirtualClient/VirtualClient.Actions.UnitTests/MongoDB/MongoDBServerExecutorTests.cs @@ -342,6 +342,77 @@ public async Task MongoDBServerExecutor_InitializeAsync_WithDiskFilter_CallsInit "ServerApiClient should be initialized"); } + [Test] + public async Task MongoDBServerExecutor_ConfigureDisk_ResolvesTheMongoDBServiceUserForThePlatform() + { + // SETUP: A DiskFilter triggers the disk configuration workflow. + this.mockFixture.Parameters["DiskFilter"] = "BiggestSize"; + this.mockFixture.Parameters["DiskDevicePath"] = "/dev/nvme0n1"; + + var volumes = new List(); + var disk = new Disk(index: 0, devicePath: "/dev/nvme0n1", volumes: volumes, properties: null); + this.mockFixture.DiskManager.Setup(dm => dm.GetDisksAsync(It.IsAny())) + .ReturnsAsync(new List { disk }); + + List commandsExecuted = new List(); + this.mockFixture.ProcessManager.OnCreateProcess = (exe, args, workingDir) => + { + commandsExecuted.Add($"{exe} {args}"); + this.mockFixture.Process.StandardOutput.Clear(); + this.mockFixture.Process.StandardOutput.Append("{ \"ok\" : 1 }"); + this.mockFixture.Process.ExitCode = 0; + return this.mockFixture.Process; + }; + + var executor = new TestableMongoDBServerExecutor(this.mockFixture.Dependencies, this.mockFixture.Parameters); + + // ACT + await executor.InitializeAsync(EventContext.Persisted(), CancellationToken.None); + + // ASSERT: The MongoDB service account is named 'mongodb' by Debian/Ubuntu packages but + // 'mongod' by RPM packages (Azure Linux, RHEL, Fedora). Hardcoding either one leaves the + // data directory owned by root on the other, and mongod then fails to create its journal. + string chownCommand = commandsExecuted.FirstOrDefault(cmd => cmd.Contains("chown", StringComparison.OrdinalIgnoreCase)); + + Assert.IsNotNull(chownCommand, "The data directory ownership command should have been executed."); + + Assert.IsFalse( + chownCommand.Contains("chown -R mongodb:mongodb", StringComparison.OrdinalIgnoreCase), + "The ownership command must not hardcode the Debian-only 'mongodb' account."); + + Assert.IsTrue( + chownCommand.Contains("id -u mongod", StringComparison.OrdinalIgnoreCase), + "The ownership command should probe for the RPM 'mongod' account."); + + Assert.IsTrue( + chownCommand.Contains("echo mongodb", StringComparison.OrdinalIgnoreCase), + "The ownership command should fall back to the Debian 'mongodb' account."); + } + + [Test] + public async Task MongoDBServerExecutor_InitializeAsync_OpensTheMongoDBPortOnTheLocalFirewall() + { + // SETUP: Capture the firewall entries the executor asks to be opened. + List firewallEntries = new List(); + this.mockFixture.FirewallManager + .Setup(mgr => mgr.EnableInboundConnectionsAsync(It.IsAny>(), It.IsAny())) + .Callback, CancellationToken>((entries, token) => firewallEntries.AddRange(entries)) + .Returns(Task.CompletedTask); + + this.mockFixture.Parameters["Port"] = 27017; + + var executor = new TestableMongoDBServerExecutor(this.mockFixture.Dependencies, this.mockFixture.Parameters); + + // ACT + await executor.InitializeAsync(EventContext.Persisted(), CancellationToken.None); + + // ASSERT: Distros such as Azure Linux apply a default-deny inbound policy. Without opening + // the port, the YCSB client times out connecting to the server and loads zero records. + Assert.AreEqual(1, firewallEntries.Count, "The MongoDB port should have been opened on the local firewall."); + Assert.AreEqual("tcp", firewallEntries[0].Protocol); + CollectionAssert.AreEqual(new List { 27017 }, firewallEntries[0].Ports.ToList()); + } + [Test] public async Task MongoDBServerExecutor_InitializeAsync_CallsConfigureBindAddressAndStartServer() { diff --git a/src/VirtualClient/VirtualClient.Actions/MongoDB/MongoDBServerExecutor.cs b/src/VirtualClient/VirtualClient.Actions/MongoDB/MongoDBServerExecutor.cs index 2d52e0e828..a4d6544b0d 100644 --- a/src/VirtualClient/VirtualClient.Actions/MongoDB/MongoDBServerExecutor.cs +++ b/src/VirtualClient/VirtualClient.Actions/MongoDB/MongoDBServerExecutor.cs @@ -24,6 +24,16 @@ namespace VirtualClient.Actions [SupportedPlatforms("linux-arm64,linux-x64")] public class MongoDBServerExecutor : MongoDBExecutor { + /// + /// The MongoDB service account created by RPM-based packages (Azure Linux, RHEL, Fedora). + /// + private const string RpmServiceUser = "mongod"; + + /// + /// The MongoDB service account created by Debian-based packages (Ubuntu, Debian). + /// + private const string DebianServiceUser = "mongodb"; + private IFileSystem fileSystem; private ISystemManagement systemManagement; private bool disposed; @@ -68,6 +78,9 @@ protected override async Task InitializeAsync(EventContext telemetryContext, Can this.InitializeApiClients(); + await MongoDBServerExecutor.OpenFirewallPortsAsync(this.Port, this.systemManagement.FirewallManager, cancellationToken) + .ConfigureAwait(false); + // Initialize disk if DiskFilter is specified if (!string.IsNullOrWhiteSpace(this.DiskFilter)) { @@ -122,6 +135,25 @@ protected override void Dispose(bool disposing) } } + /// + /// Opens the MongoDB port on the local firewall so that the client instance is able to + /// connect to the MongoDB server. Distros such as Azure Linux apply a default-deny policy + /// to inbound traffic, so the port must be opened explicitly. + /// + private static Task OpenFirewallPortsAsync(int port, IFirewallManager firewallManager, CancellationToken cancellationToken) + { + return firewallManager.EnableInboundConnectionsAsync( + new List + { + new FirewallEntry( + "MongoDB: Allow Multiple Machines communications", + "Allows individual machine instances to communicate with other machine in client-server scenario", + "tcp", + new List { port }) + }, + cancellationToken); + } + /// /// Configures MongoDB to bind to all network interfaces. /// @@ -266,10 +298,16 @@ await this.ExecuteMongoDBCommandAsync( telemetryContext, cancellationToken).ConfigureAwait(false); - // Set permissions + // Set permissions. The MongoDB service account name differs by package format: + // Debian/Ubuntu packages create 'mongodb' whereas RPM-based distributions + // (Azure Linux, RHEL, Fedora) create 'mongod'. Resolve it at runtime so the + // data directory is owned by the account mongod actually runs as. + string resolveServiceUser = $"MONGO_USER=$(id -u {MongoDBServerExecutor.RpmServiceUser} >/dev/null 2>&1 && echo {MongoDBServerExecutor.RpmServiceUser} || echo {MongoDBServerExecutor.DebianServiceUser}); " + + $"sudo chown -R $MONGO_USER:$MONGO_USER {mongoDataPath}"; + await this.ExecuteMongoDBCommandAsync( "bash", - $"-c \"sudo chown -R mongodb:mongodb {mongoDataPath}\"", + $"-c \"{resolveServiceUser}\"", "SetPermissions", telemetryContext, cancellationToken).ConfigureAwait(false); From 2905bd4baa1bd9685be030e0d98a5fc0377e3658 Mon Sep 17 00:00:00 2001 From: Prashant Kumar Date: Mon, 10 Aug 2026 12:17:02 +0530 Subject: [PATCH 3/5] Remove PERF-MONGODB-YCSB-THREAD-SWEEP.json profile The thread sweep profile is out of scope for the Azure Linux onboarding change and is not referenced by any test, documentation, or other profile. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../PERF-MONGODB-YCSB-THREAD-SWEEP.json | 322 ------------------ 1 file changed, 322 deletions(-) delete mode 100644 src/VirtualClient/VirtualClient.Main/profiles/PERF-MONGODB-YCSB-THREAD-SWEEP.json diff --git a/src/VirtualClient/VirtualClient.Main/profiles/PERF-MONGODB-YCSB-THREAD-SWEEP.json b/src/VirtualClient/VirtualClient.Main/profiles/PERF-MONGODB-YCSB-THREAD-SWEEP.json deleted file mode 100644 index 0a5cc3ce52..0000000000 --- a/src/VirtualClient/VirtualClient.Main/profiles/PERF-MONGODB-YCSB-THREAD-SWEEP.json +++ /dev/null @@ -1,322 +0,0 @@ -{ - "Description": "MongoDB YCSB client-server workload with a thread-count sweep (2-VM)", - "Metadata": { - "RecommendedMinimumExecutionTime": "01:00:00", - "SupportedPlatforms": "linux-x64,linux-arm64", - "SupportedOperatingSystems": "AzureLinux,Ubuntu", - "Notes": "Repeats load+run for each thread value (4, 8, 16, 32, 64) using YCSB workloada. Each load action drops the existing database before reloading, so every thread iteration starts from a clean database. Total execution time scales with the number of thread values swept." - }, - "Parameters": { - "Port": 27017, - "Database": "mongodb", - "Duration": "00:05:00", - "RecordCount": "500000", - "DiskFilter": "BiggestSize" - }, - "Actions": [ - { - "Type": "MongoDBServerExecutor", - "Parameters": { - "Scenario": "ServerSetup", - "Role": "Server", - "Port": "$.Parameters.Port", - "Database": "$.Parameters.Database", - "DiskFilter": "$.Parameters.DiskFilter" - } - }, - { - "Type": "MongoDBClientExecutor", - "Parameters": { - "Scenario": "Load_Database_Threads_4", - "Role": "Client", - "Database": "$.Parameters.Database", - "Port": "$.Parameters.Port", - "LoadCommand": "load {Database} -s -p maxexecutiontime=600 -p recordcount={RecordCount} -p fieldcount={FieldCount} -p fieldlength={FieldLength} -threads {ThreadCount} -p mongodb.url=mongodb://{ServerIP}:{Port}/ycsb -P {PackagePath:ycsb}/ycsb-0.17.0/workloads/workloada", - "Duration": "$.Parameters.Duration", - "ThreadCount": "4", - "YCSBPackageName": "ycsb", - "JdkPackageName": "javadevelopmentkit", - "RecordCount": "$.Parameters.RecordCount", - "FieldCount": "128", - "FieldLength": "128" - } - }, - { - "Type": "MongoDBClientExecutor", - "Parameters": { - "Scenario": "Workload_A_Threads_4", - "Role": "Client", - "MetricScenario": "workloada_th4", - "Database": "$.Parameters.Database", - "Port": "$.Parameters.Port", - "RunCommand": "run {Database} -s -p maxexecutiontime={Duration.TotalSeconds} -p operationcount={OperationCount} -p recordcount={RecordCount} -threads {ThreadCount} -p fieldcount={FieldCount} -p fieldlength={FieldLength} -p mongodb.url=mongodb://{ServerIP}:{Port}/ycsb -P {PackagePath:ycsb}/ycsb-0.17.0/workloads/workloada", - "Duration": "$.Parameters.Duration", - "ThreadCount": "4", - "OperationCount": "5000000", - "YCSBPackageName": "ycsb", - "JdkPackageName": "javadevelopmentkit", - "RecordCount": "$.Parameters.RecordCount", - "FieldCount": "128", - "FieldLength": "128" - } - }, - { - "Type": "MongoDBClientExecutor", - "Parameters": { - "Scenario": "Load_Database_Threads_8", - "Role": "Client", - "Database": "$.Parameters.Database", - "Port": "$.Parameters.Port", - "LoadCommand": "load {Database} -s -p maxexecutiontime=600 -p recordcount={RecordCount} -p fieldcount={FieldCount} -p fieldlength={FieldLength} -threads {ThreadCount} -p mongodb.url=mongodb://{ServerIP}:{Port}/ycsb -P {PackagePath:ycsb}/ycsb-0.17.0/workloads/workloada", - "Duration": "$.Parameters.Duration", - "ThreadCount": "8", - "YCSBPackageName": "ycsb", - "JdkPackageName": "javadevelopmentkit", - "RecordCount": "$.Parameters.RecordCount", - "FieldCount": "128", - "FieldLength": "128" - } - }, - { - "Type": "MongoDBClientExecutor", - "Parameters": { - "Scenario": "Workload_A_Threads_8", - "Role": "Client", - "MetricScenario": "workloada_th8", - "Database": "$.Parameters.Database", - "Port": "$.Parameters.Port", - "RunCommand": "run {Database} -s -p maxexecutiontime={Duration.TotalSeconds} -p operationcount={OperationCount} -p recordcount={RecordCount} -threads {ThreadCount} -p fieldcount={FieldCount} -p fieldlength={FieldLength} -p mongodb.url=mongodb://{ServerIP}:{Port}/ycsb -P {PackagePath:ycsb}/ycsb-0.17.0/workloads/workloada", - "Duration": "$.Parameters.Duration", - "ThreadCount": "8", - "OperationCount": "5000000", - "YCSBPackageName": "ycsb", - "JdkPackageName": "javadevelopmentkit", - "RecordCount": "$.Parameters.RecordCount", - "FieldCount": "128", - "FieldLength": "128" - } - }, - { - "Type": "MongoDBClientExecutor", - "Parameters": { - "Scenario": "Load_Database_Threads_16", - "Role": "Client", - "Database": "$.Parameters.Database", - "Port": "$.Parameters.Port", - "LoadCommand": "load {Database} -s -p maxexecutiontime=600 -p recordcount={RecordCount} -p fieldcount={FieldCount} -p fieldlength={FieldLength} -threads {ThreadCount} -p mongodb.url=mongodb://{ServerIP}:{Port}/ycsb -P {PackagePath:ycsb}/ycsb-0.17.0/workloads/workloada", - "Duration": "$.Parameters.Duration", - "ThreadCount": "16", - "YCSBPackageName": "ycsb", - "JdkPackageName": "javadevelopmentkit", - "RecordCount": "$.Parameters.RecordCount", - "FieldCount": "128", - "FieldLength": "128" - } - }, - { - "Type": "MongoDBClientExecutor", - "Parameters": { - "Scenario": "Workload_A_Threads_16", - "Role": "Client", - "MetricScenario": "workloada_th16", - "Database": "$.Parameters.Database", - "Port": "$.Parameters.Port", - "RunCommand": "run {Database} -s -p maxexecutiontime={Duration.TotalSeconds} -p operationcount={OperationCount} -p recordcount={RecordCount} -threads {ThreadCount} -p fieldcount={FieldCount} -p fieldlength={FieldLength} -p mongodb.url=mongodb://{ServerIP}:{Port}/ycsb -P {PackagePath:ycsb}/ycsb-0.17.0/workloads/workloada", - "Duration": "$.Parameters.Duration", - "ThreadCount": "16", - "OperationCount": "5000000", - "YCSBPackageName": "ycsb", - "JdkPackageName": "javadevelopmentkit", - "RecordCount": "$.Parameters.RecordCount", - "FieldCount": "128", - "FieldLength": "128" - } - }, - { - "Type": "MongoDBClientExecutor", - "Parameters": { - "Scenario": "Load_Database_Threads_32", - "Role": "Client", - "Database": "$.Parameters.Database", - "Port": "$.Parameters.Port", - "LoadCommand": "load {Database} -s -p maxexecutiontime=600 -p recordcount={RecordCount} -p fieldcount={FieldCount} -p fieldlength={FieldLength} -threads {ThreadCount} -p mongodb.url=mongodb://{ServerIP}:{Port}/ycsb -P {PackagePath:ycsb}/ycsb-0.17.0/workloads/workloada", - "Duration": "$.Parameters.Duration", - "ThreadCount": "32", - "YCSBPackageName": "ycsb", - "JdkPackageName": "javadevelopmentkit", - "RecordCount": "$.Parameters.RecordCount", - "FieldCount": "128", - "FieldLength": "128" - } - }, - { - "Type": "MongoDBClientExecutor", - "Parameters": { - "Scenario": "Workload_A_Threads_32", - "Role": "Client", - "MetricScenario": "workloada_th32", - "Database": "$.Parameters.Database", - "Port": "$.Parameters.Port", - "RunCommand": "run {Database} -s -p maxexecutiontime={Duration.TotalSeconds} -p operationcount={OperationCount} -p recordcount={RecordCount} -threads {ThreadCount} -p fieldcount={FieldCount} -p fieldlength={FieldLength} -p mongodb.url=mongodb://{ServerIP}:{Port}/ycsb -P {PackagePath:ycsb}/ycsb-0.17.0/workloads/workloada", - "Duration": "$.Parameters.Duration", - "ThreadCount": "32", - "OperationCount": "5000000", - "YCSBPackageName": "ycsb", - "JdkPackageName": "javadevelopmentkit", - "RecordCount": "$.Parameters.RecordCount", - "FieldCount": "128", - "FieldLength": "128" - } - }, - { - "Type": "MongoDBClientExecutor", - "Parameters": { - "Scenario": "Load_Database_Threads_64", - "Role": "Client", - "Database": "$.Parameters.Database", - "Port": "$.Parameters.Port", - "LoadCommand": "load {Database} -s -p maxexecutiontime=600 -p recordcount={RecordCount} -p fieldcount={FieldCount} -p fieldlength={FieldLength} -threads {ThreadCount} -p mongodb.url=mongodb://{ServerIP}:{Port}/ycsb -P {PackagePath:ycsb}/ycsb-0.17.0/workloads/workloada", - "Duration": "$.Parameters.Duration", - "ThreadCount": "64", - "YCSBPackageName": "ycsb", - "JdkPackageName": "javadevelopmentkit", - "RecordCount": "$.Parameters.RecordCount", - "FieldCount": "128", - "FieldLength": "128" - } - }, - { - "Type": "MongoDBClientExecutor", - "Parameters": { - "Scenario": "Workload_A_Threads_64", - "Role": "Client", - "MetricScenario": "workloada_th64", - "Database": "$.Parameters.Database", - "Port": "$.Parameters.Port", - "RunCommand": "run {Database} -s -p maxexecutiontime={Duration.TotalSeconds} -p operationcount={OperationCount} -p recordcount={RecordCount} -threads {ThreadCount} -p fieldcount={FieldCount} -p fieldlength={FieldLength} -p mongodb.url=mongodb://{ServerIP}:{Port}/ycsb -P {PackagePath:ycsb}/ycsb-0.17.0/workloads/workloada", - "Duration": "$.Parameters.Duration", - "ThreadCount": "64", - "OperationCount": "5000000", - "YCSBPackageName": "ycsb", - "JdkPackageName": "javadevelopmentkit", - "RecordCount": "$.Parameters.RecordCount", - "FieldCount": "128", - "FieldLength": "128" - } - } - ], - "Dependencies": [ - { - "Type": "JDKPackageDependencyInstallation", - "Parameters": { - "Scenario": "InstallJDKPackage", - "BlobContainer": "packages", - "BlobName": "microsoft-jdk-21.0.1.zip", - "PackageName": "javadevelopmentkit", - "Extract": true, - "Role": "Client" - } - }, - { - "Type": "LinuxPackageInstallation", - "Parameters": { - "Scenario": "InstallMongoPrereqs", - "Packages-Apt": "gnupg,curl,lshw", - "Packages-Dnf": "gnupg2,curl,lshw", - "Packages-Yum": "gnupg2,curl,lshw", - "Packages-Zypper": "gpg2,curl,lshw" - } - }, - { - "Type": "ExecuteCommand", - "Parameters": { - "Scenario": "MongoAddRepository", - "SupportedPlatforms": "linux-x64,linux-arm64", - "UseShell": true, - "Command": "set -e; if command -v apt-get >/dev/null 2>&1; then curl -fsSL https://www.mongodb.org/static/pgp/server-8.0.asc -o /tmp/mongodb-server-8.0.asc; sudo gpg --batch --yes --dearmor -o /usr/share/keyrings/mongodb-server-8.0.gpg /tmp/mongodb-server-8.0.asc; echo 'deb [ arch=amd64,arm64 signed-by=/usr/share/keyrings/mongodb-server-8.0.gpg ] https://repo.mongodb.org/apt/ubuntu noble/mongodb-org/8.0 multiverse' | sudo tee /etc/apt/sources.list.d/mongodb-org-8.0.list; sudo apt-get update; elif command -v dnf >/dev/null 2>&1 || command -v tdnf >/dev/null 2>&1; then sudo rpm --import https://pgp.mongodb.com/server-8.0.asc; { echo '[mongodb-org-8.0]'; echo 'name=MongoDB Repository'; echo 'baseurl=https://repo.mongodb.org/yum/redhat/9/mongodb-org/8.0/$basearch/'; echo 'gpgcheck=1'; echo 'enabled=1'; echo 'gpgkey=https://pgp.mongodb.com/server-8.0.asc'; } | sudo tee /etc/yum.repos.d/mongodb-org-8.0.repo; sudo dnf makecache --refresh; else echo 'Unsupported package manager. MongoDB repository setup requires apt-get or dnf.' 1>&2; exit 1; fi" - } - }, - { - "Type": "ExecuteCommand", - "Parameters": { - "Scenario": "MongoInstallServer", - "SupportedPlatforms": "linux-x64,linux-arm64", - "UseShell": true, - "Command": "set -e; if command -v apt-get >/dev/null 2>&1; then sudo apt-get install -y mongodb-org; else sudo dnf install -y mongodb-org; fi", - "Role": "Server" - } - }, - { - "Type": "ExecuteCommand", - "Parameters": { - "Scenario": "MongoInstallClient", - "SupportedPlatforms": "linux-x64,linux-arm64", - "UseShell": true, - "Command": "set -e; if command -v apt-get >/dev/null 2>&1; then sudo apt-get install -y mongodb-mongosh; else sudo dnf install -y mongodb-mongosh; fi", - "Role": "Client" - } - }, - { - "Type": "ExecuteCommand", - "Parameters": { - "Scenario": "MongoDaemon", - "SupportedPlatforms": "linux-x64,linux-arm64", - "Command": "sudo systemctl daemon-reload", - "Role": "Server" - } - }, - { - "Type": "ExecuteCommand", - "Parameters": { - "Scenario": "MongoStartService", - "SupportedPlatforms": "linux-x64,linux-arm64", - "Command": "sudo systemctl start mongod", - "Role": "Server" - } - }, - { - "Type": "ExecuteCommand", - "Parameters": { - "Scenario": "MongoEnableService", - "SupportedPlatforms": "linux-x64,linux-arm64", - "Command": "sudo systemctl enable mongod", - "Role": "Server" - } - }, - { - "Type": "ExecuteCommand", - "Parameters": { - "Scenario": "MongoServerStatus", - "SupportedPlatforms": "linux-x64,linux-arm64", - "Command": "sudo systemctl status mongod", - "Role": "Server" - } - }, - { - "Type": "ExecuteCommand", - "Parameters": { - "Scenario": "MongoStopService", - "SupportedPlatforms": "linux-x64,linux-arm64", - "Command": "sudo systemctl stop mongod", - "Role": "Server" - } - }, - { - "Type": "DependencyPackageInstallation", - "Parameters": { - "Scenario": "InstallYCSBPackage", - "BlobContainer": "packages", - "BlobName": "ycsb-0.17.0.zip", - "PackageName": "ycsb", - "Extract": true, - "Role": "Client" - } - }, - { - "Type": "ApiServer", - "Parameters": { - "Scenario": "StartAPIServer" - } - } - ] -} From f8866733550e5a7140f729764c9c2bfc303e4528 Mon Sep 17 00:00:00 2001 From: Prashant Kumar Date: Tue, 11 Aug 2026 10:46:40 +0530 Subject: [PATCH 4/5] Fix duplicate key insert failures in YCSB run-phase insert scenarios Read_Latest (workloadd) and Short_Range_Scan (workloade) both perform 5% run-phase inserts. YCSB seeds the insert key sequence for both scenarios at recordcount, so the scenario that runs second collides with keys already written by the first and every insert fails with: E11000 duplicate key error collection: ycsb.usertable index: _id_ Measured on a 2500000 record run, Short_Range_Scan reported INSERT-Operations=0 with INSERT-FAILED-Operations=3445, matching the 3445 duplicate key errors in the logs exactly. Setting mongodb.upsert=true makes colliding inserts update the existing document instead of failing. This is the documented behaviour of the YCSB MongoDB binding for partially loaded data sets and requires no change to RecordCount, operation mix, metric names or scenario names. This issue is not platform specific and reproduces on both Ubuntu and Azure Linux. Verified on Azure Linux 3 and Ubuntu 24.04 (2 VM client/server, exit code 0, all 7 scenarios): Short_Range_Scan now reports non-zero INSERT-Operations with zero failed operations and no E11000 errors. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../VirtualClient.Main/profiles/PERF-MONGODB-YCSB.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/VirtualClient/VirtualClient.Main/profiles/PERF-MONGODB-YCSB.json b/src/VirtualClient/VirtualClient.Main/profiles/PERF-MONGODB-YCSB.json index 0ff2a18d20..f900c5d429 100644 --- a/src/VirtualClient/VirtualClient.Main/profiles/PERF-MONGODB-YCSB.json +++ b/src/VirtualClient/VirtualClient.Main/profiles/PERF-MONGODB-YCSB.json @@ -107,7 +107,7 @@ "MetricScenario": "Read_Latest_95_Read_5_Insert_{RecordCount}_Records", "Database": "$.Parameters.Database", "Port": "$.Parameters.Port", - "RunCommand": "run {Database} -s -p maxexecutiontime={Duration.TotalSeconds} -p operationcount={OperationCount} -p recordcount={RecordCount} -threads {ThreadCount} -p fieldcount={FieldCount} -p fieldlength={FieldLength} -p mongodb.url=mongodb://{ServerIP}:{Port}/ycsb -P {PackagePath:ycsb}/ycsb-0.17.0/workloads/workloadd", + "RunCommand": "run {Database} -s -p maxexecutiontime={Duration.TotalSeconds} -p operationcount={OperationCount} -p recordcount={RecordCount} -threads {ThreadCount} -p fieldcount={FieldCount} -p fieldlength={FieldLength} -p mongodb.url=mongodb://{ServerIP}:{Port}/ycsb -p mongodb.upsert=true -P {PackagePath:ycsb}/ycsb-0.17.0/workloads/workloadd", "Duration": "$.Parameters.Duration", "ThreadCount": "$.Parameters.ThreadCount", "OperationCount": "5000000", @@ -126,7 +126,7 @@ "MetricScenario": "Short_Range_Scan_95_Scan_5_Insert_{RecordCount}_Records", "Database": "$.Parameters.Database", "Port": "$.Parameters.Port", - "RunCommand": "run {Database} -s -p maxexecutiontime={Duration.TotalSeconds} -p operationcount={OperationCount} -p recordcount={RecordCount} -threads {ThreadCount} -p fieldcount={FieldCount} -p fieldlength={FieldLength} -p mongodb.url=mongodb://{ServerIP}:{Port}/ycsb -P {PackagePath:ycsb}/ycsb-0.17.0/workloads/workloade", + "RunCommand": "run {Database} -s -p maxexecutiontime={Duration.TotalSeconds} -p operationcount={OperationCount} -p recordcount={RecordCount} -threads {ThreadCount} -p fieldcount={FieldCount} -p fieldlength={FieldLength} -p mongodb.url=mongodb://{ServerIP}:{Port}/ycsb -p mongodb.upsert=true -P {PackagePath:ycsb}/ycsb-0.17.0/workloads/workloade", "Duration": "$.Parameters.Duration", "ThreadCount": "$.Parameters.ThreadCount", "OperationCount": "5000000", From 77143aeb6431e1a8736210a45b6d1df80e5c1614 Mon Sep 17 00:00:00 2001 From: Prashant Kumar Date: Tue, 11 Aug 2026 11:10:58 +0530 Subject: [PATCH 5/5] Split combined MongoDB repository setup into atomic dependency steps The Azure Linux support work had merged four dependency steps (MongoGPGKey, MongoGPGDearmor, MongoAddRepository, MongoUpdatePackageList) into a single MongoAddRepository scenario. That removed three scenario names that exist on main, which changes the telemetry emitted for the workload and breaks any downstream query or dashboard that filters on those names. Restore the four steps as separate dependencies so each one performs a single action, while keeping the package-manager detection that provides Azure Linux support. The dependency scenario list is now identical to main. Also complete the package manager guards on MongoInstallServer and MongoInstallClient. These previously used a two-way if/else that silently fell through to dnf on any host without apt-get. They now explicitly test for dnf/tdnf and fail with a clear message on unsupported package managers, matching the guards used by the repository setup steps. Note: the unsupported package manager branch is unverified. Both test hosts had a supported package manager present, so the exit 1 path was never exercised. Verified on Azure Linux 3 and Ubuntu 24.04 (2 VM client/server, exit code 0, all 7 scenarios, no failed operations). All four steps execute in order on both distributions. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../profiles/PERF-MONGODB-YCSB.json | 33 +++++++++++++++++-- 1 file changed, 30 insertions(+), 3 deletions(-) diff --git a/src/VirtualClient/VirtualClient.Main/profiles/PERF-MONGODB-YCSB.json b/src/VirtualClient/VirtualClient.Main/profiles/PERF-MONGODB-YCSB.json index f900c5d429..a5796cbc51 100644 --- a/src/VirtualClient/VirtualClient.Main/profiles/PERF-MONGODB-YCSB.json +++ b/src/VirtualClient/VirtualClient.Main/profiles/PERF-MONGODB-YCSB.json @@ -179,13 +179,40 @@ "Packages-Zypper": "gpg2,curl,lshw" } }, + { + "Type": "ExecuteCommand", + "Parameters": { + "Scenario": "MongoGPGKey", + "SupportedPlatforms": "linux-x64,linux-arm64", + "UseShell": true, + "Command": "set -e; if command -v apt-get >/dev/null 2>&1; then curl -fsSL https://www.mongodb.org/static/pgp/server-8.0.asc -o /tmp/mongodb-server-8.0.asc; elif command -v dnf >/dev/null 2>&1 || command -v tdnf >/dev/null 2>&1; then sudo rpm --import https://pgp.mongodb.com/server-8.0.asc; else echo 'Unsupported package manager. MongoDB repository setup requires apt-get or dnf.' 1>&2; exit 1; fi" + } + }, + { + "Type": "ExecuteCommand", + "Parameters": { + "Scenario": "MongoGPGDearmor", + "SupportedPlatforms": "linux-x64,linux-arm64", + "UseShell": true, + "Command": "set -e; if command -v apt-get >/dev/null 2>&1; then sudo gpg --batch --yes --dearmor -o /usr/share/keyrings/mongodb-server-8.0.gpg /tmp/mongodb-server-8.0.asc; elif command -v dnf >/dev/null 2>&1 || command -v tdnf >/dev/null 2>&1; then echo 'Not applicable. RPM-based distributions import the key directly via rpm --import.'; else echo 'Unsupported package manager. MongoDB repository setup requires apt-get or dnf.' 1>&2; exit 1; fi" + } + }, { "Type": "ExecuteCommand", "Parameters": { "Scenario": "MongoAddRepository", "SupportedPlatforms": "linux-x64,linux-arm64", "UseShell": true, - "Command": "set -e; if command -v apt-get >/dev/null 2>&1; then curl -fsSL https://www.mongodb.org/static/pgp/server-8.0.asc -o /tmp/mongodb-server-8.0.asc; sudo gpg --batch --yes --dearmor -o /usr/share/keyrings/mongodb-server-8.0.gpg /tmp/mongodb-server-8.0.asc; echo 'deb [ arch=amd64,arm64 signed-by=/usr/share/keyrings/mongodb-server-8.0.gpg ] https://repo.mongodb.org/apt/ubuntu noble/mongodb-org/8.0 multiverse' | sudo tee /etc/apt/sources.list.d/mongodb-org-8.0.list; sudo apt-get update; elif command -v dnf >/dev/null 2>&1 || command -v tdnf >/dev/null 2>&1; then sudo rpm --import https://pgp.mongodb.com/server-8.0.asc; { echo '[mongodb-org-8.0]'; echo 'name=MongoDB Repository'; echo 'baseurl=https://repo.mongodb.org/yum/redhat/9/mongodb-org/8.0/$basearch/'; echo 'gpgcheck=1'; echo 'enabled=1'; echo 'gpgkey=https://pgp.mongodb.com/server-8.0.asc'; } | sudo tee /etc/yum.repos.d/mongodb-org-8.0.repo; sudo dnf makecache --refresh; else echo 'Unsupported package manager. MongoDB repository setup requires apt-get or dnf.' 1>&2; exit 1; fi" + "Command": "set -e; if command -v apt-get >/dev/null 2>&1; then echo 'deb [ arch=amd64,arm64 signed-by=/usr/share/keyrings/mongodb-server-8.0.gpg ] https://repo.mongodb.org/apt/ubuntu noble/mongodb-org/8.0 multiverse' | sudo tee /etc/apt/sources.list.d/mongodb-org-8.0.list; elif command -v dnf >/dev/null 2>&1 || command -v tdnf >/dev/null 2>&1; then { echo '[mongodb-org-8.0]'; echo 'name=MongoDB Repository'; echo 'baseurl=https://repo.mongodb.org/yum/redhat/9/mongodb-org/8.0/$basearch/'; echo 'gpgcheck=1'; echo 'enabled=1'; echo 'gpgkey=https://pgp.mongodb.com/server-8.0.asc'; } | sudo tee /etc/yum.repos.d/mongodb-org-8.0.repo; else echo 'Unsupported package manager. MongoDB repository setup requires apt-get or dnf.' 1>&2; exit 1; fi" + } + }, + { + "Type": "ExecuteCommand", + "Parameters": { + "Scenario": "MongoUpdatePackageList", + "SupportedPlatforms": "linux-x64,linux-arm64", + "UseShell": true, + "Command": "set -e; if command -v apt-get >/dev/null 2>&1; then sudo apt-get update; elif command -v dnf >/dev/null 2>&1 || command -v tdnf >/dev/null 2>&1; then sudo dnf makecache --refresh; else echo 'Unsupported package manager. MongoDB repository setup requires apt-get or dnf.' 1>&2; exit 1; fi" } }, { @@ -194,7 +221,7 @@ "Scenario": "MongoInstallServer", "SupportedPlatforms": "linux-x64,linux-arm64", "UseShell": true, - "Command": "set -e; if command -v apt-get >/dev/null 2>&1; then sudo apt-get install -y mongodb-org; else sudo dnf install -y mongodb-org; fi", + "Command": "set -e; if command -v apt-get >/dev/null 2>&1; then sudo apt-get install -y mongodb-org; elif command -v dnf >/dev/null 2>&1 || command -v tdnf >/dev/null 2>&1; then sudo dnf install -y mongodb-org; else echo 'Unsupported package manager. MongoDB installation requires apt-get or dnf.' 1>&2; exit 1; fi", "Role": "Server" } }, @@ -204,7 +231,7 @@ "Scenario": "MongoInstallClient", "SupportedPlatforms": "linux-x64,linux-arm64", "UseShell": true, - "Command": "set -e; if command -v apt-get >/dev/null 2>&1; then sudo apt-get install -y mongodb-mongosh; else sudo dnf install -y mongodb-mongosh; fi", + "Command": "set -e; if command -v apt-get >/dev/null 2>&1; then sudo apt-get install -y mongodb-mongosh; elif command -v dnf >/dev/null 2>&1 || command -v tdnf >/dev/null 2>&1; then sudo dnf install -y mongodb-mongosh; else echo 'Unsupported package manager. MongoDB installation requires apt-get or dnf.' 1>&2; exit 1; fi", "Role": "Client" } },