diff --git a/.github/workflows/pull-request-linux.yml b/.github/workflows/pull-request-linux.yml
index 77bd4109e9..99eed1c791 100644
--- a/.github/workflows/pull-request-linux.yml
+++ b/.github/workflows/pull-request-linux.yml
@@ -26,10 +26,10 @@ jobs:
# Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
- name: Setup .NET
- uses: actions/setup-dotnet@v3
+ uses: actions/setup-dotnet@v4
with:
dotnet-version: 9.0.x
@@ -37,7 +37,7 @@ jobs:
run: chmod -R +x *.sh
- name: Initialize CodeQL
- uses: github/codeql-action/init@v2
+ uses: github/codeql-action/init@v3
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
@@ -54,6 +54,6 @@ jobs:
run: ./build-test.sh
- name: Perform CodeQL Analysis
- uses: github/codeql-action/analyze@v2
+ uses: github/codeql-action/analyze@v3
with:
category: "/language:${{matrix.language}}"
diff --git a/.github/workflows/pull-request.yml b/.github/workflows/pull-request.yml
index e14ccf3cd6..0c7be0e4e8 100644
--- a/.github/workflows/pull-request.yml
+++ b/.github/workflows/pull-request.yml
@@ -26,16 +26,16 @@ jobs:
# Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
- name: Setup .NET
- uses: actions/setup-dotnet@v3
+ uses: actions/setup-dotnet@v4
with:
dotnet-version: 9.0.x
- name: Initialize CodeQL
if: false # this is causing PR to fail on Windows with single slashes on Windows, temporarily disabling since we have it in Linux PR
- uses: github/codeql-action/init@v2
+ uses: github/codeql-action/init@v3
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
@@ -53,6 +53,6 @@ jobs:
- name: Perform CodeQL Analysis
if: false # this is causing PR to fail on Windows with single slashes on Windows, temporarily disabling since we have it in Linux PR
- uses: github/codeql-action/analyze@v2
+ uses: github/codeql-action/analyze@v3
with:
category: "/language:${{matrix.language}}"
diff --git a/Directory.Packages.props b/Directory.Packages.props
index 462f3d2d23..19086b92d6 100644
--- a/Directory.Packages.props
+++ b/Directory.Packages.props
@@ -29,7 +29,7 @@
-
+
diff --git a/src/VirtualClient/VirtualClient.Actions.UnitTests/Sysbench/SysbenchConfigurationTests.cs b/src/VirtualClient/VirtualClient.Actions.UnitTests/Sysbench/SysbenchConfigurationTests.cs
index f7ae18a06d..666829b907 100644
--- a/src/VirtualClient/VirtualClient.Actions.UnitTests/Sysbench/SysbenchConfigurationTests.cs
+++ b/src/VirtualClient/VirtualClient.Actions.UnitTests/Sysbench/SysbenchConfigurationTests.cs
@@ -21,6 +21,7 @@ namespace VirtualClient.Actions
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
+ using VirtualClient.Common;
using VirtualClient.Common.Contracts;
using VirtualClient.Common.Telemetry;
using VirtualClient.Contracts;
@@ -117,6 +118,50 @@ public async Task SysbenchConfigurationSkipsSysbenchInitialization()
}
}
+ [Test]
+ public async Task SysbenchConfigurationWaitsForServerDependenciesBeforeRemotePopulation()
+ {
+ this.fixture.StateManager.OnGetState().ReturnsAsync(JObject.FromObject(new SysbenchExecutor.SysbenchState()
+ {
+ SysbenchInitialized = true
+ }));
+
+ bool serverHeartbeatConfirmed = false;
+ this.fixture.ApiClient.OnGetHeartbeat().ReturnsAsync(() =>
+ {
+ serverHeartbeatConfirmed = true;
+ return this.fixture.CreateHttpResponse(HttpStatusCode.OK);
+ });
+
+ this.fixture.ProcessManager.OnCreateProcess = (exe, arguments, workingDir) =>
+ {
+ Assert.IsTrue(serverHeartbeatConfirmed);
+
+ return new InMemoryProcess
+ {
+ StartInfo = new ProcessStartInfo
+ {
+ FileName = exe,
+ Arguments = arguments
+ },
+ ExitCode = 0,
+ OnStart = () => true,
+ OnHasExited = () => true
+ };
+ };
+
+ using (TestSysbenchConfiguration sysbenchConfiguration = new TestSysbenchConfiguration(this.fixture.Dependencies, this.fixture.Parameters))
+ {
+ await sysbenchConfiguration.ExecuteAsync(CancellationToken.None);
+ }
+
+ this.fixture.ApiClient.Verify(
+ client => client.GetHeartbeatAsync(
+ It.IsAny(),
+ It.IsAny>()),
+ Times.Once);
+ }
+
[Test]
public async Task SysbenchConfigurationPreparesDatabase()
{
@@ -163,6 +208,40 @@ public async Task SysbenchConfigurationPreparesDatabase()
}
}
+ [Test]
+ public void SysbenchConfigurationThrowsWhenPopulationReportsFatalError()
+ {
+ this.fixture.StateManager.OnGetState().ReturnsAsync(JObject.FromObject(new SysbenchExecutor.SysbenchState()
+ {
+ SysbenchInitialized = true
+ }));
+
+ this.fixture.ProcessManager.OnCreateProcess = (exe, arguments, workingDir) =>
+ {
+ return new InMemoryProcess
+ {
+ StartInfo = new ProcessStartInfo
+ {
+ FileName = exe,
+ Arguments = arguments
+ },
+ ExitCode = 0,
+ OnStart = () => true,
+ OnHasExited = () => true,
+ StandardOutput = new ConcurrentBuffer(new StringBuilder(
+ "FATAL: error 1130: Host '10.0.1.0' is not allowed to connect to this MySQL server"))
+ };
+ };
+
+ using (TestSysbenchConfiguration sysbenchConfiguration = new TestSysbenchConfiguration(this.fixture.Dependencies, this.fixture.Parameters))
+ {
+ WorkloadException error = Assert.ThrowsAsync(
+ () => sysbenchConfiguration.ExecuteAsync(CancellationToken.None));
+
+ Assert.AreEqual(ErrorReason.WorkloadUnexpectedAnomaly, error.Reason);
+ }
+ }
+
[Test]
public async Task SysbenchConfigurationUsesDefinedParametersWhenRunningTheWorkload()
{
diff --git a/src/VirtualClient/VirtualClient.Actions/Sysbench/SysbenchConfiguration.cs b/src/VirtualClient/VirtualClient.Actions/Sysbench/SysbenchConfiguration.cs
index 5ebaa198b5..c7eda1471c 100644
--- a/src/VirtualClient/VirtualClient.Actions/Sysbench/SysbenchConfiguration.cs
+++ b/src/VirtualClient/VirtualClient.Actions/Sysbench/SysbenchConfiguration.cs
@@ -31,6 +31,7 @@ public SysbenchConfiguration(IServiceCollection dependencies, IDictionary();
+ this.PollingTimeout = TimeSpan.FromMinutes(10);
}
///
@@ -45,6 +46,11 @@ public string Action
}
}
+ ///
+ /// The amount of time to wait for the server dependencies to complete.
+ ///
+ protected TimeSpan PollingTimeout { get; set; }
+
///
/// Executes the workload.
///
@@ -110,6 +116,14 @@ private async Task PopulateDatabase(EventContext telemetryContext, CancellationT
if (!state.DatabasePopulated)
{
+ if (this.IsMultiRoleLayout() && this.IsInRole(ClientRole.Client))
+ {
+ this.Logger.LogTraceMessage("Synchronization: Poll server API for heartbeat before database population...");
+
+ await this.ServerApiClient.PollForHeartbeatAsync(this.PollingTimeout, cancellationToken)
+ .ConfigureAwait(false);
+ }
+
await this.Logger.LogMessageAsync($"{this.TypeName}.PopulateDatabase", telemetryContext.Clone(), async () =>
{
string serverIp = (this.IsMultiRoleLayout() && this.IsInRole(ClientRole.Client)) ? this.ServerIpAddress : "localhost";
@@ -131,6 +145,14 @@ await this.Logger.LogMessageAsync($"{this.TypeName}.PopulateDatabase", telemetry
await this.LogProcessDetailsAsync(process, telemetryContext, "Sysbench", logToFile: true);
process.ThrowIfErrored(process.StandardError.ToString(), ErrorReason.WorkloadUnexpectedAnomaly);
+ if (process.StandardOutput.ToString().Contains("FATAL:", StringComparison.OrdinalIgnoreCase)
+ || process.StandardError.ToString().Contains("FATAL:", StringComparison.OrdinalIgnoreCase))
+ {
+ throw new WorkloadException(
+ "Sysbench reported a fatal error while populating the database.",
+ ErrorReason.WorkloadUnexpectedAnomaly);
+ }
+
this.AddPopulationDurationMetric(sysbenchLoggingArguments, process, telemetryContext, cancellationToken);
state.DatabasePopulated = true;
diff --git a/src/VirtualClient/VirtualClient.Core.UnitTests/SshClientProxyTests.cs b/src/VirtualClient/VirtualClient.Core.UnitTests/SshClientProxyTests.cs
index 159a55f5a6..4a45157334 100644
--- a/src/VirtualClient/VirtualClient.Core.UnitTests/SshClientProxyTests.cs
+++ b/src/VirtualClient/VirtualClient.Core.UnitTests/SshClientProxyTests.cs
@@ -77,6 +77,7 @@ public void SshClientProxyConstructorsSetPropertiesToExpectedValues()
Assert.IsTrue(object.ReferenceEquals(expectedInfo, client.ConnectionInfo));
Assert.IsTrue(object.ReferenceEquals(expectedInfo, client.SessionClient.ConnectionInfo));
Assert.IsTrue(object.ReferenceEquals(expectedInfo, client.SessionScpClient.ConnectionInfo));
+ Assert.IsTrue(object.ReferenceEquals(RemotePathTransformation.ShellQuote, client.SessionScpClient.RemotePathTransformation));
}
}
diff --git a/src/VirtualClient/VirtualClient.Core/SshClientProxy.cs b/src/VirtualClient/VirtualClient.Core/SshClientProxy.cs
index 17a6d637cf..7ffeabc92d 100644
--- a/src/VirtualClient/VirtualClient.Core/SshClientProxy.cs
+++ b/src/VirtualClient/VirtualClient.Core/SshClientProxy.cs
@@ -34,7 +34,7 @@ public SshClientProxy(ConnectionInfo connectionInfo)
{
connectionInfo.ThrowIfNull(nameof(connectionInfo));
this.SessionClient = new SshClient(connectionInfo);
- this.SessionScpClient = new ScpClient(connectionInfo);
+ this.SessionScpClient = new ScpClient(connectionInfo, RemotePathTransformation.ShellQuote);
}
///
diff --git a/src/VirtualClient/VirtualClient.Main/profiles/PERF-MYSQL-SYSBENCH-OLTP.json b/src/VirtualClient/VirtualClient.Main/profiles/PERF-MYSQL-SYSBENCH-OLTP.json
index 27cd86e1df..80891e175a 100644
--- a/src/VirtualClient/VirtualClient.Main/profiles/PERF-MYSQL-SYSBENCH-OLTP.json
+++ b/src/VirtualClient/VirtualClient.Main/profiles/PERF-MYSQL-SYSBENCH-OLTP.json
@@ -182,7 +182,7 @@
"Parameters": {
"Scenario": "DownloadMySqlServerPackage",
"BlobContainer": "packages",
- "BlobName": "mysql-server-8.0.36-v5.zip",
+ "BlobName": "mysql-server-8.0.46-v1.zip",
"PackageName": "mysql-server",
"Extract": true,
"Role": "Server"
diff --git a/src/VirtualClient/VirtualClient.Main/profiles/PERF-MYSQL-SYSBENCH-TPCC.json b/src/VirtualClient/VirtualClient.Main/profiles/PERF-MYSQL-SYSBENCH-TPCC.json
index b23b59b725..d83d03843c 100644
--- a/src/VirtualClient/VirtualClient.Main/profiles/PERF-MYSQL-SYSBENCH-TPCC.json
+++ b/src/VirtualClient/VirtualClient.Main/profiles/PERF-MYSQL-SYSBENCH-TPCC.json
@@ -70,7 +70,7 @@
"Parameters": {
"Scenario": "DownloadMySqlServerPackage",
"BlobContainer": "packages",
- "BlobName": "mysql-server-8.0.36-v5.zip",
+ "BlobName": "mysql-server-8.0.46-v1.zip",
"PackageName": "mysql-server",
"Extract": true,
"Role": "Server"