diff --git a/src/VirtualClient/VirtualClient.Contracts/DiskExtensions.cs b/src/VirtualClient/VirtualClient.Contracts/DiskExtensions.cs index 24046551b3..91f671db75 100644 --- a/src/VirtualClient/VirtualClient.Contracts/DiskExtensions.cs +++ b/src/VirtualClient/VirtualClient.Contracts/DiskExtensions.cs @@ -11,7 +11,7 @@ namespace VirtualClient.Contracts using System.Text.RegularExpressions; /// - /// + /// /// public static class DiskExtensions { @@ -42,11 +42,10 @@ public static string GetPreferredAccessPath(this Disk disk, PlatformID platform) path = "/"; } - else if (platform == PlatformID.Unix && disk.IsOperatingSystem()) + else if (platform == PlatformID.Win32NT && disk.IsOperatingSystem()) { // If it is OS disk, test on OS partition path = disk.Volumes.Where(v => v.IsOperatingSystem()).FirstOrDefault().AccessPaths.FirstOrDefault(); - } else { @@ -178,7 +177,7 @@ public static long SizeInBytes(this Disk disk, PlatformID platform) else { result = disk.Volumes.Sum(v => v.SizeInBytes(platform)); - } + } } return result; diff --git a/src/VirtualClient/VirtualClient.Core/DependencyFactory.cs b/src/VirtualClient/VirtualClient.Core/DependencyFactory.cs index 2cbcd0a741..f9004aef06 100644 --- a/src/VirtualClient/VirtualClient.Core/DependencyFactory.cs +++ b/src/VirtualClient/VirtualClient.Core/DependencyFactory.cs @@ -84,7 +84,13 @@ public static IBlobManager CreateBlobManager(DependencyStore dependencyStore) /// A logger for capturing disk management telemetry. public static DiskManager CreateDiskManager(PlatformID platform, Microsoft.Extensions.Logging.ILogger logger = null) { + if (PlatformSpecifics.IsRunningInContainer()) + { + return new DummyDiskManager(platform, logger); + } + DiskManager manager = null; + switch (platform) { case PlatformID.Win32NT: @@ -326,8 +332,8 @@ public static IEnumerable CreateFileLoggerProviders(string logF // Metrics/Results ILoggerProvider metricsLoggerProvider = DependencyFactory.CreateFileLoggerProvider( - Path.Combine(logFileDirectory, settings.MetricsFileName), - TimeSpan.FromSeconds(3), + Path.Combine(logFileDirectory, settings.MetricsFileName), + TimeSpan.FromSeconds(3), LogLevel.Trace, new SerilogJsonTextFormatter(propertiesToExcludeForMetrics)).HandleMetrics(); @@ -336,7 +342,7 @@ public static IEnumerable CreateFileLoggerProviders(string logF // Metrics/Results in CSV Format ILoggerProvider metricsCsvLoggerProvider = DependencyFactory.CreateCsvFileLoggerProvider( - Path.Combine(logFileDirectory, + Path.Combine(logFileDirectory, settings.MetricsCsvFileName)).HandleMetrics(); VirtualClientRuntime.CleanupTasks.Add(new Action_(() => metricsCsvLoggerProvider.Dispose())); @@ -344,8 +350,8 @@ public static IEnumerable CreateFileLoggerProviders(string logF // System Events ILoggerProvider eventsLoggerProvider = DependencyFactory.CreateFileLoggerProvider( - Path.Combine(logFileDirectory, settings.EventsFileName), - TimeSpan.FromSeconds(5), + Path.Combine(logFileDirectory, settings.EventsFileName), + TimeSpan.FromSeconds(5), LogLevel.Trace, new SerilogJsonTextFormatter(propertiesToExcludeForEvents)).HandleSystemEvents(); @@ -670,7 +676,7 @@ public static VirtualClientProxyApiClient CreateVirtualClientProxyApiClient(Uri public static void FlushTelemetry(TimeSpan? timeout = null) { Parallel.ForEach(DependencyFactory.telemetryChannels, channel => channel.Flush(timeout)); - } + } /// /// Applies a filter to the logger generated by the provider that will handle the logging @@ -708,4 +714,4 @@ internal static ILoggerProvider HandleTraces(this ILoggerProvider loggerProvider return loggerProvider.WithFilter((eventId, logLevel, state) => (LogType)eventId.Id <= LogType.Error); } } -} \ No newline at end of file +} diff --git a/src/VirtualClient/VirtualClient.Core/DummyDiskManager.cs b/src/VirtualClient/VirtualClient.Core/DummyDiskManager.cs new file mode 100644 index 0000000000..daca372184 --- /dev/null +++ b/src/VirtualClient/VirtualClient.Core/DummyDiskManager.cs @@ -0,0 +1,97 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +namespace VirtualClient +{ + using System; + using System.Collections.Generic; + using System.Linq; + using System.Threading; + using System.Threading.Tasks; + using Microsoft.Extensions.Logging; + using Polly; + using VirtualClient.Common; + using VirtualClient.Common.Extensions; + using VirtualClient.Common.Telemetry; + using VirtualClient.Contracts; + + /// + /// A DiskManager that simply presents a OS disk, and does not try to do any + /// discovery. Useful in containers. + /// + public class DummyDiskManager : DiskManager + { + private readonly DiskVolume volume; + private readonly Disk disk; + + /// + /// Create a new instance. + /// + /// + /// + public DummyDiskManager(PlatformID platform, ILogger logger = null) + : base(logger) + { + string defaultMountPath = platform == PlatformID.Win32NT ? "C:\\" : "/"; + string devicePath = platform == PlatformID.Win32NT ? "C:\\" : "/dev/sda"; + + var volumeProps = new Dictionary(); + + // TODO: determine size with `df` or whatever on Windows + + if (platform == PlatformID.Win32NT) + { + volumeProps.Add(Disk.WindowsDiskProperties.Info, "Boot"); + volumeProps.Add(Disk.WindowsDiskProperties.Size, 1ul << 30); + } + else + { + volumeProps.Add(Disk.UnixDiskProperties.Size, 1ul << 30); + } + + this.volume = new DiskVolume(0, devicePath, new[] { defaultMountPath }, volumeProps); + this.disk = new Disk(0, devicePath, new[] { this.volume }); + } + + /// + /// Get the set of disks. + /// + /// + /// + public override Task> GetDisksAsync(CancellationToken cancellationToken) + { + return Task.FromResult>(new[] { this.disk }); + } + + /// + /// No-op + /// + /// + /// + /// + /// + /// + public override Task FormatDiskAsync(Disk disk, PartitionType partitionType, FileSystemType fileSystemType, CancellationToken cancellationToken) + { + return Task.CompletedTask; + } + + /// + /// No-op + /// + /// + /// + /// + /// + /// + public override Task CreateMountPointAsync(DiskVolume volume, string mountPoint, CancellationToken cancellationToken) + { + if (volume != this.volume) + { + throw new ArgumentException("Invalid volume provided to DummyDiskManager::CreateMountPointAsync"); + } + + return Task.CompletedTask; + } + } +} diff --git a/src/VirtualClient/VirtualClient.Core/UnixFirewallManager.cs b/src/VirtualClient/VirtualClient.Core/UnixFirewallManager.cs index c04782a600..c2888c7788 100644 --- a/src/VirtualClient/VirtualClient.Core/UnixFirewallManager.cs +++ b/src/VirtualClient/VirtualClient.Core/UnixFirewallManager.cs @@ -11,6 +11,7 @@ namespace VirtualClient using VirtualClient.Common; using VirtualClient.Common.Extensions; using VirtualClient.Common.Platform; + using VirtualClient.Contracts; /// /// Provides methods for managing Unix/Linux system/OS firewall operations. @@ -45,6 +46,13 @@ public override Task EnableInboundAppAsync(FirewallEntry firewallEntry, Cancella public async override Task EnableInboundConnectionAsync(FirewallEntry firewallEntry, CancellationToken cancellationToken) { firewallEntry.ThrowIfNull(nameof(firewallEntry)); + + if (PlatformSpecifics.IsRunningInContainer()) + { + // Can't set iptables from within a container. + return; + } + if (!cancellationToken.IsCancellationRequested) { string ports = null; diff --git a/src/VirtualClient/VirtualClient.Dependencies/PostgreSQLServer/PostgreSQLServerConfiguration.cs b/src/VirtualClient/VirtualClient.Dependencies/PostgreSQLServer/PostgreSQLServerConfiguration.cs index 876f7d8ca3..8416d799e4 100644 --- a/src/VirtualClient/VirtualClient.Dependencies/PostgreSQLServer/PostgreSQLServerConfiguration.cs +++ b/src/VirtualClient/VirtualClient.Dependencies/PostgreSQLServer/PostgreSQLServerConfiguration.cs @@ -5,6 +5,7 @@ namespace VirtualClient.Dependencies { using System; using System.Collections.Generic; + using System.IO; using System.Linq; using System.Net; using System.Security.Cryptography; @@ -78,6 +79,17 @@ public string DiskFilter } } + /// + /// Directory for the PostgreSQL database within the disk. + /// + public string DataDirectory + { + get + { + return this.Parameters.GetValue(nameof(this.DataDirectory), string.Empty); + } + } + /// /// Database Name to create and utilize /// @@ -108,8 +120,15 @@ public string SuperUserPassword { get { - byte[] hashBytes = SHA256.HashData(Encoding.UTF8.GetBytes(this.ExperimentId)); - return Convert.ToBase64String(hashBytes); + if (this.Parameters.ContainsKey(nameof(this.SuperUserPassword))) + { + return this.Parameters.GetValue(nameof(this.SuperUserPassword)); + } + else + { + byte[] hashBytes = SHA256.HashData(Encoding.UTF8.GetBytes(this.ExperimentId)); + return Convert.ToBase64String(hashBytes); + } } } @@ -267,7 +286,18 @@ private async Task GetPostgreSQLInnodbDirectoriesAsync(CancellationToken foreach (Disk disk in disksToTest) { - diskPaths += $"{disk.GetPreferredAccessPath(this.Platform)};"; + string path = disk.GetPreferredAccessPath(this.Platform); + + if (!string.IsNullOrEmpty(this.DataDirectory)) + { + path = Path.Join(path, this.DataDirectory); + if (!Directory.Exists(path)) + { + Directory.CreateDirectory(path); + } + } + + diskPaths += $"{path};"; } } diff --git a/src/VirtualClient/VirtualClient.Main/profiles/PERF-POSTGRESQL-HAMMERDB-TPCC.json b/src/VirtualClient/VirtualClient.Main/profiles/PERF-POSTGRESQL-HAMMERDB-TPCC.json index b3600e54bd..40a6b5d036 100644 --- a/src/VirtualClient/VirtualClient.Main/profiles/PERF-POSTGRESQL-HAMMERDB-TPCC.json +++ b/src/VirtualClient/VirtualClient.Main/profiles/PERF-POSTGRESQL-HAMMERDB-TPCC.json @@ -9,6 +9,7 @@ "Parameters": { "DatabaseName": "hammerdb_tpcc", "DiskFilter": "osdisk:false&sizegreaterthan:256g", + "DataDirectory": "", "Port": "5432", "VirtualUsers": "{calculate({LogicalCoreCount})}", "WarehouseCount": "{calculate({SystemMemoryMegabytes} * 15 / 800)}", @@ -49,14 +50,16 @@ "Type": "FormatDisks", "Parameters": { "Scenario": "FormatDisks", - "Role": "Server" + "Role": "Server", + "DiskFilter": "$.Parameters.DiskFilter" } }, { "Type": "MountDisks", "Parameters": { "Scenario": "CreateMountPoints", - "Role": "Server" + "Role": "Server", + "DiskFilter": "$.Parameters.DiskFilter" } }, { @@ -129,7 +132,8 @@ "DiskFilter": "$.Parameters.DiskFilter", "PackageName": "postgresql", "Port": "$.Parameters.Port", - "Role": "Server" + "Role": "Server", + "DataDirectory": "$.Parameters.DataDirectory" } }, { @@ -154,4 +158,4 @@ } } ] -} \ No newline at end of file +} diff --git a/src/VirtualClient/VirtualClient.Main/profiles/PERF-POSTGRESQL-SYSBENCH-OLTP.json b/src/VirtualClient/VirtualClient.Main/profiles/PERF-POSTGRESQL-SYSBENCH-OLTP.json index b884e450b5..c65ca9bd0d 100644 --- a/src/VirtualClient/VirtualClient.Main/profiles/PERF-POSTGRESQL-SYSBENCH-OLTP.json +++ b/src/VirtualClient/VirtualClient.Main/profiles/PERF-POSTGRESQL-SYSBENCH-OLTP.json @@ -9,6 +9,7 @@ "Parameters": { "DatabaseName": "sbtest", "DiskFilter": "osdisk:false&sizegreaterthan:256g", + "DataDirectory": "", "Port": "5432", "SharedMemoryBuffer": "{calculate({SystemMemoryMegabytes} * 85 / 100)}", "DatabaseScenario": "Balanced", @@ -155,7 +156,8 @@ "Type": "FormatDisks", "Parameters": { "Scenario": "FormatDisks", - "Role": "Server" + "Role": "Server", + "DiskFilter": "$.Parameters.DiskFilter" } }, { @@ -163,7 +165,8 @@ "Parameters": { "Scenario": "CreateMountPoints", "MountLocation": "Root", - "Role": "Server" + "Role": "Server", + "DiskFilter": "$.Parameters.DiskFilter" } }, { @@ -249,7 +252,8 @@ "DiskFilter": "$.Parameters.DiskFilter", "PackageName": "postgresql", "Port": "$.Parameters.Port", - "Role": "Server" + "Role": "Server", + "DataDirectory": "$.Parameters.DataDirectory" } }, { @@ -272,4 +276,4 @@ } } ] -} \ No newline at end of file +} diff --git a/src/VirtualClient/VirtualClient.Main/profiles/PERF-POSTGRESQL-SYSBENCH-TPCC.json b/src/VirtualClient/VirtualClient.Main/profiles/PERF-POSTGRESQL-SYSBENCH-TPCC.json index 9b25fe91d4..9b9ec76678 100644 --- a/src/VirtualClient/VirtualClient.Main/profiles/PERF-POSTGRESQL-SYSBENCH-TPCC.json +++ b/src/VirtualClient/VirtualClient.Main/profiles/PERF-POSTGRESQL-SYSBENCH-TPCC.json @@ -1,5 +1,5 @@ { - "Description": "Sysbench TPCC MySQL Database Server Performance Workload", + "Description": "Sysbench TPCC PostgreSQL Database Server Performance Workload", "MinimumExecutionInterval": "00:01:00", "Metadata": { "RecommendedMinimumExecutionTime": "04:00:00", @@ -9,6 +9,7 @@ "Parameters": { "DatabaseName": "sbtest", "DiskFilter": "osdisk:false&sizegreaterthan:256g", + "DataDirectory": "", "Port": "5432", "SharedMemoryBuffer": "{calculate({SystemMemoryMegabytes} * 85 / 100)}", "DatabaseScenario": "Balanced", @@ -43,7 +44,8 @@ "Type": "FormatDisks", "Parameters": { "Scenario": "FormatDisks", - "Role": "Server" + "Role": "Server", + "DiskFilter": "$.Parameters.DiskFilter" } }, { @@ -51,7 +53,8 @@ "Parameters": { "Scenario": "CreateMountPoints", "MountLocation": "Root", - "Role": "Server" + "Role": "Server", + "DiskFilter": "$.Parameters.DiskFilter" } }, { @@ -137,7 +140,8 @@ "DiskFilter": "$.Parameters.DiskFilter", "PackageName": "postgresql", "Port": "$.Parameters.Port", - "Role": "Server" + "Role": "Server", + "DataDirectory": "$.Parameters.DataDirectory" } }, { @@ -160,4 +164,4 @@ } } ] -} \ No newline at end of file +}