From 6f4d215c2ec344abc74d8096bcd38131abb48815 Mon Sep 17 00:00:00 2001 From: p3rf Team Date: Mon, 25 Sep 2023 17:22:43 -0700 Subject: [PATCH] Workbench using SQL Server cluster based on windows failover cluster with S2D storage. PiperOrigin-RevId: 568367684 --- .../add_sql_server_second_node.ps1 | 46 ++++ .../sqlserver_ha_configs/clean_disks.ps1 | 23 ++ .../grant_witness_access.ps1 | 8 + .../install_cluster_components.ps1 | 15 ++ .../sqlserver_ha_configs/set_dns.ps1 | 13 ++ .../set_dns_join_domain.ps1 | 19 ++ .../setup_domain_controller.ps1 | 50 +++++ .../setup_fci_cluster.ps1 | 22 ++ .../setup_s2d_volumes.ps1 | 54 +++++ .../setup_sql_server_first_node.ps1 | 49 +++++ .../sqlserver_ha_configs/setup_witness.ps1 | 25 +++ .../update_sql_server.ps1 | 7 + perfkitbenchmarker/iaas_relational_db.py | 5 +- perfkitbenchmarker/os_types.py | 4 + .../providers/gcp/gce_network.py | 17 +- .../providers/gcp/gce_virtual_machine.py | 27 +++ .../gcp/gce_windows_virtual_machine.py | 2 + .../sqlserver_iaas_relational_db.py | 201 +++++++++++++++++- perfkitbenchmarker/vm_util.py | 4 +- .../hammerdbcli_benchmark.py | 13 +- perfkitbenchmarker/windows_virtual_machine.py | 1 + tests/providers/aws/aws_relational_db_test.py | 5 +- tests/providers/gcp/gcp_relational_db_test.py | 5 +- 23 files changed, 601 insertions(+), 14 deletions(-) create mode 100644 perfkitbenchmarker/data/relational_db_configs/sqlserver_ha_configs/add_sql_server_second_node.ps1 create mode 100644 perfkitbenchmarker/data/relational_db_configs/sqlserver_ha_configs/clean_disks.ps1 create mode 100644 perfkitbenchmarker/data/relational_db_configs/sqlserver_ha_configs/grant_witness_access.ps1 create mode 100644 perfkitbenchmarker/data/relational_db_configs/sqlserver_ha_configs/install_cluster_components.ps1 create mode 100644 perfkitbenchmarker/data/relational_db_configs/sqlserver_ha_configs/set_dns.ps1 create mode 100644 perfkitbenchmarker/data/relational_db_configs/sqlserver_ha_configs/set_dns_join_domain.ps1 create mode 100644 perfkitbenchmarker/data/relational_db_configs/sqlserver_ha_configs/setup_domain_controller.ps1 create mode 100644 perfkitbenchmarker/data/relational_db_configs/sqlserver_ha_configs/setup_fci_cluster.ps1 create mode 100644 perfkitbenchmarker/data/relational_db_configs/sqlserver_ha_configs/setup_s2d_volumes.ps1 create mode 100644 perfkitbenchmarker/data/relational_db_configs/sqlserver_ha_configs/setup_sql_server_first_node.ps1 create mode 100644 perfkitbenchmarker/data/relational_db_configs/sqlserver_ha_configs/setup_witness.ps1 create mode 100644 perfkitbenchmarker/data/relational_db_configs/sqlserver_ha_configs/update_sql_server.ps1 diff --git a/perfkitbenchmarker/data/relational_db_configs/sqlserver_ha_configs/add_sql_server_second_node.ps1 b/perfkitbenchmarker/data/relational_db_configs/sqlserver_ha_configs/add_sql_server_second_node.ps1 new file mode 100644 index 0000000000..ac62076c6a --- /dev/null +++ b/perfkitbenchmarker/data/relational_db_configs/sqlserver_ha_configs/add_sql_server_second_node.ps1 @@ -0,0 +1,46 @@ + try { + $scriptsFolder = 'c:\scripts' + $domainUser = 'perflab\administrator' + $localServerName = [System.Net.Dns]::GetHostName() + $clearPassword = $args[1] + $taskScriptPath = $scriptsFolder + '\fci-cluster-task.ps1' + $clusterIpAddress = $args[0] + + if (-not (Test-Path $scriptsFolder)) { + New-Item -Path $scriptsFolder -ItemType directory + } + + Write-Host 'Install SQL Server' + # SQL Server 2022 needs /PRODUCTCOVEREDBYSA=False + $sql2022InstallParam = '/PRODUCTCOVEREDBYSA=False' + $sql2022InstallParam = '' + $sqlInstallString = [string]::Format('c:\sql_server_install\Setup.exe /Action=AddNode /UpdateEnabled=True {2} /ENU=True /CONFIRMIPDEPENDENCYCHANGE=false /SQLSVCACCOUNT=''perflab\sql_server'' /SQLSVCPASSWORD=''{0}'' /AGTSVCACCOUNT=''perflab\sql_server'' /AGTSVCPASSWORD=''{0}'' /INSTANCENAME=''MSSQLSERVER'' /FAILOVERCLUSTERNETWORKNAME=''sql'' /FAILOVERCLUSTERIPADDRESSES=''IPv4;{1};Cluster Network 1;255.255.240.0'' /FAILOVERCLUSTERGROUP=''SQL Server (MSSQLSERVER)'' /SQLSVCINSTANTFILEINIT=''False'' /FTSVCACCOUNT=''NT Service\MSSQLFDLauncher'' /IAcceptSQLServerLicenseTerms=1 /INDICATEPROGRESS /Q 2>&1 > c:\scripts\sqlsetuplog.log',$clearPassword,$clusterIpAddress,$sql2022InstallParam) + + Out-File -FilePath $taskScriptPath -InputObject $sqlInstallString + + $currentDateTime = Get-Date + + $taskName = 'Run-Cluster-Tasks' + $taskAction = New-ScheduledTaskAction -Execute 'PowerShell.exe' -Argument $taskScriptPath + $taskTrigger = New-ScheduledTaskTrigger -Once -At $currentDateTime.AddMinutes(120).ToString('HH:mm:sstt') + $scheduledTask = New-ScheduledTask -Action $taskAction -Trigger $taskTrigger + + Register-ScheduledTask -TaskName $taskName -InputObject $scheduledTask -User $domainUser -Password $clearPassword + Start-ScheduledTask -TaskName $taskName + + + Write-Host 'Running task' + Write-Host (Get-ScheduledTask -TaskName $taskName).State + + while ((Get-ScheduledTask -TaskName $taskName).State -ne 'Ready') { + Write-Host -Message 'Waiting on scheduled task...' + Start-Sleep -Seconds 10 + } + Start-Sleep -Seconds 10 + Disable-ScheduledTask -TaskName $taskName + +} +catch { + Write-Host $_.Exception.Message + throw $_.Exception.Message +} diff --git a/perfkitbenchmarker/data/relational_db_configs/sqlserver_ha_configs/clean_disks.ps1 b/perfkitbenchmarker/data/relational_db_configs/sqlserver_ha_configs/clean_disks.ps1 new file mode 100644 index 0000000000..233dc2bf15 --- /dev/null +++ b/perfkitbenchmarker/data/relational_db_configs/sqlserver_ha_configs/clean_disks.ps1 @@ -0,0 +1,23 @@ + try { + $scriptsFolder = 'c:\scripts' + $diskpartCmdFile = $scriptsFolder + '\diskpartcmd.txt' + + if (-not (Test-Path $scriptsFolder)) { + New-Item -Path $scriptsFolder -ItemType directory + } + + $physicalDisks = Get-PhysicalDisk | where-object {$_.CanPool -eq $true} | Select-Object -exp DeviceID + + New-Item -Path $diskpartCmdFile -itemtype file -force | OUT-NULL + + foreach($pd in $physicalDisks) { + Add-Content -path $diskpartCmdFile "select disk $pd" + Add-Content -path $diskpartCmdFile 'clean' + } + + diskpart /s $diskpartCmdFile +} +catch { + Write-Host $_.Exception.Message + throw $_.Exception.Message +} diff --git a/perfkitbenchmarker/data/relational_db_configs/sqlserver_ha_configs/grant_witness_access.ps1 b/perfkitbenchmarker/data/relational_db_configs/sqlserver_ha_configs/grant_witness_access.ps1 new file mode 100644 index 0000000000..194dbbef85 --- /dev/null +++ b/perfkitbenchmarker/data/relational_db_configs/sqlserver_ha_configs/grant_witness_access.ps1 @@ -0,0 +1,8 @@ +try { + icacls C:\QWitness\ /grant 'sql-fci$:(OI)(CI)(M)' + Grant-SmbShareAccess -Name QWitness -AccountName 'sql-fci$' -AccessRight Full -Force +} +catch { + Write-Host $_.Exception.Message + throw $_.Exception.Message +} diff --git a/perfkitbenchmarker/data/relational_db_configs/sqlserver_ha_configs/install_cluster_components.ps1 b/perfkitbenchmarker/data/relational_db_configs/sqlserver_ha_configs/install_cluster_components.ps1 new file mode 100644 index 0000000000..17437df3c9 --- /dev/null +++ b/perfkitbenchmarker/data/relational_db_configs/sqlserver_ha_configs/install_cluster_components.ps1 @@ -0,0 +1,15 @@ +try { + $ErrorActionPreference = 'stop' + Write-Host 'Installing cluster components.' + # Install required Windows features + Install-WindowsFeature Failover-Clustering -IncludeManagementTools + Install-WindowsFeature RSAT-AD-PowerShell + + # Open firewall for WSFC + Set-NetFirewallProfile -Profile Domain, Public, Private -Enabled False + +} +catch { + Write-Host $_.Exception.Message + throw $_.Exception.Message +} diff --git a/perfkitbenchmarker/data/relational_db_configs/sqlserver_ha_configs/set_dns.ps1 b/perfkitbenchmarker/data/relational_db_configs/sqlserver_ha_configs/set_dns.ps1 new file mode 100644 index 0000000000..59179a725b --- /dev/null +++ b/perfkitbenchmarker/data/relational_db_configs/sqlserver_ha_configs/set_dns.ps1 @@ -0,0 +1,13 @@ +$dnsServerIpAddress=$args[0] + +$nic = Get-NetAdapter + +Write-Host "Set DNS Server to $dnsServerIpAddress" + +Set-DnsClientServerAddress -InterfaceIndex $nic[0].ifIndex -ServerAddresses $dnsServerIpAddress + +$dns_server = Get-DnsClientServerAddress -InterfaceIndex $nic[0].ifIndex -AddressFamily IPv4 + +if ($dns_server.ServerAddresses -eq $dnsServerIpAddress) { + Write-Host 'DNS Set completed.' +} diff --git a/perfkitbenchmarker/data/relational_db_configs/sqlserver_ha_configs/set_dns_join_domain.ps1 b/perfkitbenchmarker/data/relational_db_configs/sqlserver_ha_configs/set_dns_join_domain.ps1 new file mode 100644 index 0000000000..11b0c2364e --- /dev/null +++ b/perfkitbenchmarker/data/relational_db_configs/sqlserver_ha_configs/set_dns_join_domain.ps1 @@ -0,0 +1,19 @@ +$domainUser = 'perflab\administrator' +$dnsServerIpAddress=$args[0] + +$passwordSecureString = (ConvertTo-SecureString -AsPlainText $args[1] -Force) +$nic = Get-NetAdapter + +Write-Host "Set DNS Server to $dnsServerIpAddress" + +Set-DnsClientServerAddress -InterfaceIndex $nic[0].ifIndex -ServerAddresses $dnsServerIpAddress + +$dns_server = Get-DnsClientServerAddress -InterfaceIndex $nic[0].ifIndex -AddressFamily IPv4 + +if ($dns_server.ServerAddresses -eq $dnsServerIpAddress) { + Write-Host 'DNS Set. Joining perflab.local Domain' + $credObject = New-Object System.Management.Automation.PSCredential ($domainUser, $passwordSecureString) + + Add-Computer -DomainName perflab.local -credential $credObject + Write-Host 'Done' +} diff --git a/perfkitbenchmarker/data/relational_db_configs/sqlserver_ha_configs/setup_domain_controller.ps1 b/perfkitbenchmarker/data/relational_db_configs/sqlserver_ha_configs/setup_domain_controller.ps1 new file mode 100644 index 0000000000..406e4a8474 --- /dev/null +++ b/perfkitbenchmarker/data/relational_db_configs/sqlserver_ha_configs/setup_domain_controller.ps1 @@ -0,0 +1,50 @@ +$domainName = 'perflab.local' +$netBIOSname = 'perflab' +$mode = 'WinThreshold' + +$scriptsFolder = 'c:\scripts' + + +try { + Write-Host "Pass=$args[0]" + $PasswordSecureString = (ConvertTo-SecureString -AsPlainText $args[0] -Force) + Start-Sleep -Seconds 30 + + New-LocalUser 'adminuser' -Password $PasswordSecureString -FullName 'Admin User' -PasswordNeverExpires + Add-LocalGroupMember -Group 'Administrators' -Member 'adminuser' + + + $AdminUserAccount = Get-LocalUser -Name 'Administrator' + $AdminUserAccount | Set-LocalUser -Password $PasswordSecureString + $AdminUserAccount | Enable-LocalUser + + + + Install-WindowsFeature AD-Domain-Services -IncludeAllSubFeature -IncludeManagementTools + + + + Import-Module ADDSDeployment + + $forestProperties = @{ + + DomainName = $domainName + DomainNetbiosName = $netBIOSname + ForestMode = $mode + DomainMode = $mode + CreateDnsDelegation = $false + InstallDns = $true + DatabasePath = 'C:\Windows\NTDS' + LogPath = 'C:\Windows\NTDS' + SysvolPath = 'C:\Windows\SYSVOL' + NoRebootOnCompletion = $true + SafeModeAdministratorPassword = $PasswordSecureString + Force = $true + } + + Install-ADDSForest @forestProperties + +} +catch { + throw $_.Exception.Message +} diff --git a/perfkitbenchmarker/data/relational_db_configs/sqlserver_ha_configs/setup_fci_cluster.ps1 b/perfkitbenchmarker/data/relational_db_configs/sqlserver_ha_configs/setup_fci_cluster.ps1 new file mode 100644 index 0000000000..f311b07a3e --- /dev/null +++ b/perfkitbenchmarker/data/relational_db_configs/sqlserver_ha_configs/setup_fci_cluster.ps1 @@ -0,0 +1,22 @@ +try { + $domainUser = 'perflab\administrator' + $localServerName = [System.Net.Dns]::GetHostName() + + $passwordSecureString = (ConvertTo-SecureString -AsPlainText $args[2] -Force) + $node1 = $localServerName + '.perflab.local' + $node2 = $args[0] + '.perflab.local' + $fulldcname = $args[1] + '.perflab.local' + + Write-Host $args[2] + + $domainCredential = New-Object System.Management.Automation.PSCredential ($domainUser, $passwordSecureString) + + Write-Host 'Create failover cluster' + Invoke-Command -ComputerName $fulldcname -Credential $domainCredential -ArgumentList $node1,$node2 -ScriptBlock { + New-Cluster -Name sql-fci -Node $args[0],$args[1] -NoStorage -ManagementPointNetworkType Distributed + } +} +catch { + Write-Host $_.Exception.Message + throw $_.Exception.Message +} diff --git a/perfkitbenchmarker/data/relational_db_configs/sqlserver_ha_configs/setup_s2d_volumes.ps1 b/perfkitbenchmarker/data/relational_db_configs/sqlserver_ha_configs/setup_s2d_volumes.ps1 new file mode 100644 index 0000000000..811b4f4f14 --- /dev/null +++ b/perfkitbenchmarker/data/relational_db_configs/sqlserver_ha_configs/setup_s2d_volumes.ps1 @@ -0,0 +1,54 @@ +try { + $domainUser = 'perflab\administrator' + $localServerName = [System.Net.Dns]::GetHostName() + + $passwordSecureString = (ConvertTo-SecureString -AsPlainText $args[0] -Force) + $node1 = $localServerName + '.perflab.local' + + $partVmName = $localServerName.Substring(0, $localServerName.Length - 1) + + $node2 = $partVmName + '2.perflab.local' + $dc = $partVmName + '3.perflab.local' + + $domainCredential = New-Object System.Management.Automation.PSCredential ($domainUser, $passwordSecureString) + + $cacheDiskModel = 'EphemeralDisk' + + $nvme_disks = Get-PhysicalDisk | Where-Object { $_.FriendlyName -like 'nvme_card' } + $scsi_disks = Get-PhysicalDisk | Where-Object { $_.FriendlyName -like 'EphemeralDisk' } + + if ($nvme_disks.count -gt 0) { + $cacheDiskModel = 'nvme_card' + } + if ($scsi_disks.count -gt 0) { + $cacheDiskModel = 'EphemeralDisk' + } + Write-Host $cacheDiskModel + if ([string]::IsNullOrEmpty($cacheDiskModel)) { + Enable-ClusterStorageSpacesDirect -PoolFriendlyName 's2dpool' -Confirm:0; + } + else { + Invoke-Command -ComputerName $node1 -Credential $domainCredential -ArgumentList $cacheDiskModel -ScriptBlock { + Enable-ClusterStorageSpacesDirect -CacheDeviceModel $args[0] -PoolFriendlyName 's2dpool' -Confirm:0; + } + } + Start-Sleep -Seconds 40 + (Get-Cluster).BlockCacheSize = 2048 + + New-Volume -StoragePoolFriendlyName S2D* -FriendlyName 'Data' -FileSystem CSVFS_ReFS ` + -AllocationUnitSize 65536 -ProvisioningType 'Fixed' ` + -UseMaximumSize + + Write-Host 'Test Cluster' + Invoke-Command -ComputerName $dc -Credential $domainCredential -ArgumentList $node1,$node2 -ScriptBlock { + Test-Cluster -Node $args[0],$args[1] -Confirm:0; + } + Write-Host 'Add SQL service account' + Invoke-Command -ComputerName $dc -Credential $domainCredential -ArgumentList $passwordSecureString -ScriptBlock { + New-ADUser -Name 'sql_server' -Description 'SQL Agent and SQL Admin account.' -AccountPassword $args[0] -Enabled $true -PasswordNeverExpires $true + } +} +catch { + Write-Host $_.Exception.Message + throw $_.Exception.Message +} diff --git a/perfkitbenchmarker/data/relational_db_configs/sqlserver_ha_configs/setup_sql_server_first_node.ps1 b/perfkitbenchmarker/data/relational_db_configs/sqlserver_ha_configs/setup_sql_server_first_node.ps1 new file mode 100644 index 0000000000..816219762c --- /dev/null +++ b/perfkitbenchmarker/data/relational_db_configs/sqlserver_ha_configs/setup_sql_server_first_node.ps1 @@ -0,0 +1,49 @@ + try { + $scriptsFolder = 'c:\scripts' + $domainUser = 'perflab\administrator' + $localServerName = [System.Net.Dns]::GetHostName() + $clearPassword = $args[1] + $taskScriptPath = $scriptsFolder + '\fci-cluster-task.ps1' + $clusterIpAddress = $args[0] + + if (-not(Test-Path $scriptsFolder)) { + New-Item -Path $scriptsFolder -ItemType directory +} + + Write-Host 'Install SQL Server' + # SQL Server 2022 needs /PRODUCTCOVEREDBYSA=False + $sql2022InstallParam = '/PRODUCTCOVEREDBYSA=False' + $sql2022InstallParam = '' + $sqlInstallString = [string]::Format('c:\sql_server_install\Setup.exe /Action=InstallFailoverCluster /UpdateEnabled=True {2} /ENU=True /SQLSVCACCOUNT=''perflab\sql_server'' /SQLSVCPASSWORD=''{0}'' /SAPWD=''{0}'' /AGTSVCACCOUNT=''perflab\sql_server'' /AGTSVCPASSWORD=''{0}'' /FEATURES=SQLENGINE,REPLICATION,FULLTEXT,DQ /INSTANCEID=''MSSQLSERVER'' /INSTANCENAME=''MSSQLSERVER'' /INSTALLSHAREDDIR=''C:\Program Files\Microsoft SQL Server'' /INSTANCEDIR=''C:\Program Files\Microsoft SQL Server'' /FAILOVERCLUSTERDISKS=''Cluster Virtual Disk (Data)'' /FAILOVERCLUSTERNETWORKNAME=''sql'' /FAILOVERCLUSTERIPADDRESSES=''IPv4;{1};Cluster Network 1;255.255.240.0'' /FAILOVERCLUSTERGROUP=''SQL Server (MSSQLSERVER)'' /SQLSVCINSTANTFILEINIT=''True'' /SQLSYSADMINACCOUNTS=''perflab\domain admins'' /IACCEPTSQLSERVERLICENSETERMS=1 /INSTALLSQLDATADIR=''C:\ClusterStorage\Data\'' /SQLUSERDBLOGDIR=''C:\ClusterStorage\Data\MSSQL\Log'' /SQLTEMPDBDIR=''C:\ClusterStorage\Data\MSSQL\Temp'' /FTSVCACCOUNT=''NT Service\MSSQLFDLauncher'' /INDICATEPROGRESS /SECURITYMODE=SQL /Q 2>&1 > c:\scripts\sqlsetuplog.log',$clearPassword, $clusterIpAddress,$sql2022InstallParam) + + Out-File -FilePath $taskScriptPath -InputObject $sqlInstallString + Add-Content $taskScriptPath 'Add-ClusterResource -Name fci-dnn -ResourceType ''Distributed Network Name'' -Group ''SQL Server (MSSQLSERVER)''' + Add-Content $taskScriptPath 'Get-ClusterResource -Name fci-dnn | Set-ClusterParameter -Name DnsName -Value fcidnn' + Add-Content $taskScriptPath 'Start-ClusterResource -Name fci-dnn' + + $currentDateTime = Get-Date + + $taskName = 'Run-Cluster-Tasks' + $taskAction = New-ScheduledTaskAction -Execute 'PowerShell.exe' -Argument $taskScriptPath + $taskTrigger = New-ScheduledTaskTrigger -Once -At $currentDateTime.AddMinutes(120).ToString('HH:mm:sstt') + $scheduledTask = New-ScheduledTask -Action $taskAction -Trigger $taskTrigger + + Register-ScheduledTask -TaskName $taskName -InputObject $scheduledTask -User $domainUser -Password $clearPassword + Start-ScheduledTask -TaskName $taskName + + + Write-Host 'Running task' + Write-Host (Get-ScheduledTask -TaskName $taskName).State + + while ((Get-ScheduledTask -TaskName $taskName).State -ne 'Ready') { + Write-Host -Message 'Waiting on scheduled task...' + Start-Sleep -Seconds 10 + } + Start-Sleep -Seconds 25 + Disable-ScheduledTask -TaskName $taskName + +} +catch { + Write-Host $_.Exception.Message + throw $_.Exception.Message +} diff --git a/perfkitbenchmarker/data/relational_db_configs/sqlserver_ha_configs/setup_witness.ps1 b/perfkitbenchmarker/data/relational_db_configs/sqlserver_ha_configs/setup_witness.ps1 new file mode 100644 index 0000000000..8a0da82c5c --- /dev/null +++ b/perfkitbenchmarker/data/relational_db_configs/sqlserver_ha_configs/setup_witness.ps1 @@ -0,0 +1,25 @@ +try { + + Install-WindowsFeature FS-FileServer + + # Open firewall for WSFC + Set-NetFirewallProfile -Profile Domain, Public, Private -Enabled False + + $local_name = [System.Net.Dns]::GetHostName() + $joined_computers = (Get-AdComputer -filter "Name -NotLike '$local_name'" | Select-Object Name) + + New-Item 'C:\QWitness' -type directory + + New-SmbShare -Name QWitness -Path 'C:\QWitness' -Description 'SQL File Share Witness' -FullAccess $env:username + + foreach ($comp in $joined_computers) { + $node = $comp.Name + '$' + Write-Host $node + icacls C:\QWitness\ /grant '$($node):(OI)(CI)(M)' + Grant-SmbShareAccess -Name 'QWitness' -AccountName $node -AccessRight Full -Force + } +} +catch { + Write-Host $_.Exception.Message + throw $_.Exception.Message +} diff --git a/perfkitbenchmarker/data/relational_db_configs/sqlserver_ha_configs/update_sql_server.ps1 b/perfkitbenchmarker/data/relational_db_configs/sqlserver_ha_configs/update_sql_server.ps1 new file mode 100644 index 0000000000..fae3a7ebb8 --- /dev/null +++ b/perfkitbenchmarker/data/relational_db_configs/sqlserver_ha_configs/update_sql_server.ps1 @@ -0,0 +1,7 @@ +$url = 'https://download.microsoft.com/download/6/e/7/6e72dddf-dfa4-4889-bc3d-e5d3a0fd11ce/SQLServer2019-KB5027702-x64.exe' +$dest = 'c:\scripts\SQLServer2019-KB5027702-x64.exe' + +# Download the file +(New-Object System.Net.WebClient).DownloadFile($url, $dest) + +c:\scripts\SQLServer2019-KB5027702-x64.exe /q /IAcceptSQLServerLicenseTerms /Action=Patch /InstanceName=MSSQLSERVER diff --git a/perfkitbenchmarker/iaas_relational_db.py b/perfkitbenchmarker/iaas_relational_db.py index 07e148639b..d7b8197886 100644 --- a/perfkitbenchmarker/iaas_relational_db.py +++ b/perfkitbenchmarker/iaas_relational_db.py @@ -147,9 +147,12 @@ def GetDefaultEngineVersion(engine): def _Create(self): """Setup the underlying resource.""" self._SetupUnmanagedDatabase() - self.endpoint = self.server_vm.internal_ip self.unmanaged_db_exists = True + def _SetEndpoint(self): + """Set the DB endpoint for this instance during _PostCreate.""" + self.endpoint = self.server_vm.internal_ip + def _Delete(self): """Deletes the underlying resource. diff --git a/perfkitbenchmarker/os_types.py b/perfkitbenchmarker/os_types.py index 937b11a05f..5d9c8470a2 100644 --- a/perfkitbenchmarker/os_types.py +++ b/perfkitbenchmarker/os_types.py @@ -69,6 +69,8 @@ WINDOWS2019_SQLSERVER_2019_ENTERPRISE = 'windows2019_desktop_sqlserver_2019_enterprise' WINDOWS2022_SQLSERVER_2019_STANDARD = 'windows2022_desktop_sqlserver_2019_standard' WINDOWS2022_SQLSERVER_2019_ENTERPRISE = 'windows2022_desktop_sqlserver_2019_enterprise' +WINDOWS2022_SQLSERVER_2022_STANDARD = 'windows2022_desktop_sqlserver_2022_standard' +WINDOWS2022_SQLSERVER_2022_ENTERPRISE = 'windows2022_desktop_sqlserver_2022_enterprise' # Base-only OS types DEBIAN = 'debian' @@ -146,6 +148,8 @@ WINDOWS2019_SQLSERVER_2019_ENTERPRISE, WINDOWS2022_SQLSERVER_2019_STANDARD, WINDOWS2022_SQLSERVER_2019_ENTERPRISE, + WINDOWS2022_SQLSERVER_2022_STANDARD, + WINDOWS2022_SQLSERVER_2022_ENTERPRISE ] CENTOS_TYPES = [CENTOS7, CENTOS8, CENTOS_STREAM8, CENTOS_STREAM9] diff --git a/perfkitbenchmarker/providers/gcp/gce_network.py b/perfkitbenchmarker/providers/gcp/gce_network.py index daffbab8da..5649632e32 100644 --- a/perfkitbenchmarker/providers/gcp/gce_network.py +++ b/perfkitbenchmarker/providers/gcp/gce_network.py @@ -326,17 +326,21 @@ def _Delete(self): class GceIPAddress(resource.BaseResource): """Object representing a GCE IP address.""" - def __init__(self, project: str, region: str, name: str): + def __init__(self, project: str, region: str, name: str, + subnet: Optional[str] = None): super(GceIPAddress, self).__init__() self.project = project self.region = region self.name = name + self.subnet = subnet self.ip_address = None def _Create(self): """Allocates a public IP for the VPN gateway.""" cmd = util.GcloudCommand(self, 'compute', 'addresses', 'create', self.name) cmd.flags['region'] = self.region + if self.subnet is not None: + cmd.flags['subnet'] = self.subnet cmd.Issue() def _PostCreate(self): @@ -733,6 +737,17 @@ def __init__(self, name: str, network_name: str, region: str, addr_range: str, self.addr_range = addr_range self.project = project + def UpdateProperties(self) -> None: + """Updates the properties of the subnet resource.""" + cmd = util.GcloudCommand( + self, 'compute', 'networks', 'subnets', 'describe', self.name + ) + cmd.flags['region'] = self.region + stdout, _, _ = cmd.Issue() + json_details = json.loads(stdout) + self.network_name = json_details['network'].split('/')[-1] + self.addr_range = json_details['ipCidrRange'] + def _Create(self): cmd = util.GcloudCommand(self, 'compute', 'networks', 'subnets', 'create', self.name) diff --git a/perfkitbenchmarker/providers/gcp/gce_virtual_machine.py b/perfkitbenchmarker/providers/gcp/gce_virtual_machine.py index bc1b065239..673fd887bd 100644 --- a/perfkitbenchmarker/providers/gcp/gce_virtual_machine.py +++ b/perfkitbenchmarker/providers/gcp/gce_virtual_machine.py @@ -1164,6 +1164,33 @@ def CreateScratchDisk(self, disk_spec_id, disk_spec): self.UpdateDevicePath(scratch_disk, remote_nvme_devices) self._PrepareScratchDisk(scratch_disk, disk_spec) + def CreateIpReservation(self, + ip_address_name: str) -> gce_network.GceIPAddress: + """Creates an IP reservation. + + Args: + ip_address_name: name of the IP reservation to be created. + + Returns: + Reserved IP address. + """ + reserved_ip_address = gce_network.GceIPAddress( + self.project, util.GetRegionFromZone(self.zone), + ip_address_name, self.network.primary_subnet_name) + reserved_ip_address.Create() + return reserved_ip_address + + def ReleaseIpReservation(self, ip_address_name: str) -> None: + """Releases existing IP reservation. + + Args: + ip_address_name: name of the IP reservation to be released. + """ + reserv_ip_address = gce_network.GceIPAddress( + self.project, util.GetRegionFromZone(self.zone), + ip_address_name, self.network.primary_subnet_name) + reserv_ip_address.Delete() + def FindRemoteNVMEDevices(self, _, nvme_devices): """Find the paths for all remote NVME devices inside the VM.""" remote_nvme_devices = [ diff --git a/perfkitbenchmarker/providers/gcp/gce_windows_virtual_machine.py b/perfkitbenchmarker/providers/gcp/gce_windows_virtual_machine.py index 7ddc860d1c..7beeb5ab87 100644 --- a/perfkitbenchmarker/providers/gcp/gce_windows_virtual_machine.py +++ b/perfkitbenchmarker/providers/gcp/gce_windows_virtual_machine.py @@ -322,6 +322,8 @@ class WindowsGceSqlServerVirtualMachine(WindowsGceVirtualMachine): os_types.WINDOWS2019_SQLSERVER_2019_ENTERPRISE: 'sql-ent-2019-win-2019', os_types.WINDOWS2022_SQLSERVER_2019_STANDARD: 'sql-std-2019-win-2022', os_types.WINDOWS2022_SQLSERVER_2019_ENTERPRISE: 'sql-ent-2019-win-2022', + os_types.WINDOWS2022_SQLSERVER_2022_ENTERPRISE: 'sql-ent-2022-win-2022', + os_types.WINDOWS2022_SQLSERVER_2022_STANDARD: 'sql-std-2022-win-2022', } OS_TYPE = os_types.WINDOWS_SQLSERVER_OS_TYPES diff --git a/perfkitbenchmarker/sqlserver_iaas_relational_db.py b/perfkitbenchmarker/sqlserver_iaas_relational_db.py index 7f9110f390..7e797027db 100644 --- a/perfkitbenchmarker/sqlserver_iaas_relational_db.py +++ b/perfkitbenchmarker/sqlserver_iaas_relational_db.py @@ -17,13 +17,28 @@ database. """ +import ntpath +import os +from typing import Optional + from absl import flags +from perfkitbenchmarker import data from perfkitbenchmarker import db_util from perfkitbenchmarker import iaas_relational_db from perfkitbenchmarker import os_types +from perfkitbenchmarker import relational_db from perfkitbenchmarker import sql_engine_utils +from perfkitbenchmarker import virtual_machine from perfkitbenchmarker import vm_util +CONTROLLER_SCRIPT_PATH = ( + "relational_db_configs/sqlserver_ha_configs/controller.ps1" +) + +FCI_CLUSTER_SCRIPT_PATH = ( + "relational_db_configs/sqlserver_ha_configs/fci_cluster.ps1" +) + FLAGS = flags.FLAGS IS_READY_TIMEOUT = 600 # 10 minutes @@ -37,15 +52,77 @@ class SQLServerIAASRelationalDb(iaas_relational_db.IAASRelationalDb): ENGINE = sql_engine_utils.SQLSERVER + @property + def replica_vms(self): + """Server VM of replicas for hosting a managed database. + + Raises: + RelationalDbPropertyNotSetError: if the server_vm is missing. + + Returns: + The replica vms. + """ + if not hasattr(self, "_replica_vms"): + raise relational_db.RelationalDbPropertyNotSetError( + "replica_vms is not set" + ) + return self._replica_vms + + @replica_vms.setter + def replica_vms(self, replica_vms): + self._replica_vms = replica_vms + + @property + def controller_vm(self): + """Server VM of replicas for hosting a managed database. + + Raises: + RelationalDbPropertyNotSetError: if the server_vm is missing. + + Returns: + The replica vms. + """ + if not hasattr(self, "_controller_vm"): + raise relational_db.RelationalDbPropertyNotSetError( + "controller_vm is not set" + ) + return self._controller_vm + + @controller_vm.setter + def controller_vm(self, controller_vm): + self._controller_vm = controller_vm + + def SetVms(self, vm_groups): + super().SetVms(vm_groups) + if "servers" in vm_groups: + self.server_vm = vm_groups["servers"][0] + + if self.spec.high_availability: + assert len(vm_groups["servers"]) >= 3 + self.controller_vm = vm_groups["servers"][-1] + self.replica_vms = vm_groups["servers"][1:-1] + def _SetupWindowsUnamangedDatabase(self): self.spec.database_username = "sa" self.spec.database_password = db_util.GenerateRandomDbPassword() - ConfigureSQLServer( - self.server_vm, - self.spec.database_username, - self.spec.database_password, - ) - self.MoveSQLServerTempDb() + + if self.spec.high_availability: + self.ConfigureSQLServerHa() + else: + ConfigureSQLServer( + self.server_vm, + self.spec.database_username, + self.spec.database_password, + ) + self.MoveSQLServerTempDb() + + def _SetEndpoint(self): + """Set the DB endpoint for this instance during _PostCreate.""" + super()._SetEndpoint() + if self.spec.high_availability: + self.endpoint = "fcidnn.perflab.local" + else: + self.endpoint = self.server_vm.internal_ip def _SetupLinuxUnmanagedDatabase(self): if self.spec.engine_version == "2022": @@ -109,6 +186,118 @@ def GetDefaultEngineVersion(engine): """ return DEFAULT_ENGINE_VERSION + def ConfigureSQLServerHa(self): + """Create SQL server HA deployment for performance testing.""" + server_vm = self.server_vm + client_vm = self.client_vm + controller_vm = self.controller_vm + replica_vms = self.replica_vms + win_password = vm_util.GenerateRandomWindowsPassword( + vm_util.PASSWORD_LENGTH, "*!@#%^+=") + ip_name = "fci-ip-{}".format(FLAGS.run_uri) + reserved_ip = server_vm.CreateIpReservation(ip_name) + # Install and configure AD components. + self.PushAndRunPowershellScript(controller_vm, + "setup_domain_controller.ps1", + [win_password]) + controller_vm.Reboot() + + # Remove volumes and partitions created on the attached disks. + # Disks will be initialized by S2D. + self.PushAndRunPowershellScript(server_vm, "clean_disks.ps1") + + self.PushAndRunPowershellScript(server_vm, "set_dns_join_domain.ps1", + [controller_vm.internal_ip, win_password]) + server_vm.Reboot() + + self.PushAndRunPowershellScript(replica_vms[0], "clean_disks.ps1") + self.PushAndRunPowershellScript(replica_vms[0], "set_dns_join_domain.ps1", + [controller_vm.internal_ip, win_password]) + replica_vms[0].Reboot() + + self.PushAndRunPowershellScript(client_vm, "set_dns.ps1", + [controller_vm.internal_ip]) + + # Install all components needed to create and configure failover cluster. + self.PushAndRunPowershellScript(controller_vm, + "install_cluster_components.ps1") + controller_vm.Reboot() + self.PushAndRunPowershellScript(server_vm, "install_cluster_components.ps1") + server_vm.Reboot() + self.PushAndRunPowershellScript(replica_vms[0], + "install_cluster_components.ps1") + replica_vms[0].Reboot() + + # Setup cluster witness. + self.PushAndRunPowershellScript(controller_vm, "setup_witness.ps1") + self.PushAndRunPowershellScript(server_vm, "setup_fci_cluster.ps1", + [replica_vms[0].name, controller_vm.name, + win_password]) + + # Ensure all nodes in the cluster have access to the witness share + self.PushAndRunPowershellScript(controller_vm, "grant_witness_access.ps1") + + # Uninstall existing SQL server. + # FCI cluster requires different installation to what comes with the image. + server_vm.RemoteCommand("C:\\sql_server_install\\Setup.exe " + "/Action=Uninstall /FEATURES=SQL,AS,IS,RS " + "/INSTANCENAME=MSSQLSERVER /Q") + server_vm.Reboot() + replica_vms[0].RemoteCommand("C:\\sql_server_install\\Setup.exe " + "/Action=Uninstall /FEATURES=SQL,AS,IS,RS " + "/INSTANCENAME=MSSQLSERVER /Q") + replica_vms[0].Reboot() + + # Configure S2D pool and volumes. + # All available storage (both PD and local SSD) will be used + self.PushAndRunPowershellScript(server_vm, "setup_s2d_volumes.ps1", + [win_password]) + # install SQL server into newly created cluster + self.PushAndRunPowershellScript(server_vm, + "setup_sql_server_first_node.ps1", + [reserved_ip.ip_address, win_password]) + self.PushAndRunPowershellScript(replica_vms[0], + "add_sql_server_second_node.ps1", + [reserved_ip.ip_address, win_password]) + + # Install SQL server updates. + # Installation media present on the system is very outdated and it + # does not support DNN connection for SQL. + self.PushAndRunPowershellScript(server_vm, "update_sql_server.ps1") + self.PushAndRunPowershellScript(replica_vms[0], "update_sql_server.ps1") + + # Update variables user for connection to SQL server. + self.spec.database_password = win_password + self.spec.endpoint = "fcidnn.perflab.local" + + def PushAndRunPowershellScript( + self, + vm: virtual_machine.VirtualMachine, + script_name: str, + cmd_parameters: Optional[list[str]] = None, + source_path: str = "relational_db_configs/sqlserver_ha_configs/" + ) -> tuple[str, str]: + """Pushes a powershell script to VM and run it. + + Args: + vm: vm where script will be uploaded and executed + script_name: name of the script to upload and execute + cmd_parameters: optional command parameters + source_path: script source location + + Returns: + command execution output. + """ + if cmd_parameters is None: + cmd_parameters = [] + script_path_on_vm = ntpath.join(vm.temp_dir, script_name) + script_path = data.ResourcePath(os.path.join(source_path, script_name)) + vm.PushFile(script_path, script_path_on_vm) + + return vm.RemoteCommand("powershell {} {}" + .format(script_path_on_vm, + " ".join(cmd_parameters))) + def ConfigureSQLServer(vm, username: str, password: str): """Update the username and password on a SQL Server.""" diff --git a/perfkitbenchmarker/vm_util.py b/perfkitbenchmarker/vm_util.py index 1933f27011..1121ff5821 100644 --- a/perfkitbenchmarker/vm_util.py +++ b/perfkitbenchmarker/vm_util.py @@ -683,13 +683,13 @@ def ExecutableOnPath(executable_name): return True -def GenerateRandomWindowsPassword(password_length=PASSWORD_LENGTH): +def GenerateRandomWindowsPassword(password_length=PASSWORD_LENGTH, + special_chars='*!@#$+'): """Generates a password that meets Windows complexity requirements.""" # The special characters have to be recognized by the Azure CLI as # special characters. This greatly limits the set of characters # that we can safely use. See # https://github.com/Azure/azure-xplat-cli/blob/master/lib/commands/arm/vm/vmOsProfile._js#L145 - special_chars = '*!@#$+' # Ensure that the password contains at least one of each 4 required # character types starting with letters to avoid starting with chars which # are problematic on the command line e.g. @. diff --git a/perfkitbenchmarker/windows_benchmarks/hammerdbcli_benchmark.py b/perfkitbenchmarker/windows_benchmarks/hammerdbcli_benchmark.py index ade8ca074b..8273ee8edc 100644 --- a/perfkitbenchmarker/windows_benchmarks/hammerdbcli_benchmark.py +++ b/perfkitbenchmarker/windows_benchmarks/hammerdbcli_benchmark.py @@ -138,7 +138,14 @@ def GetConfig(user_config): Returns: loaded benchmark configuration """ - return configs.LoadConfig(BENCHMARK_CONFIG, user_config, BENCHMARK_NAME) + config = configs.LoadConfig(BENCHMARK_CONFIG, user_config, BENCHMARK_NAME) + if FLAGS.db_high_availability: + # We need two additional vms for sql ha deployment. + # First vm to act as the second node in sql cluster + # and additional vm to act as a domain controller. + config['relational_db']['vm_groups']['servers']['vm_count'] = 3 + + return config def CheckPrerequisites(_): @@ -149,7 +156,8 @@ def CheckPrerequisites(_): ]: raise errors.Setup.InvalidFlagConfigurationError( 'Non-optimized hammerdbcli_optimized_server_configuration' - ' is not implemented.') + ' is not implemented.' + ) def Prepare(benchmark_spec): @@ -163,6 +171,7 @@ def Prepare(benchmark_spec): relational_db = benchmark_spec.relational_db vm = relational_db.client_vm vm.Install('hammerdb') + is_azure = FLAGS.cloud == 'Azure' and FLAGS.use_managed_db if is_azure and hammerdb.HAMMERDB_SCRIPT.value == 'tpc_c': # Create the database first only Azure requires creating the database. diff --git a/perfkitbenchmarker/windows_virtual_machine.py b/perfkitbenchmarker/windows_virtual_machine.py index 8aebbedcfe..a57302dd2f 100644 --- a/perfkitbenchmarker/windows_virtual_machine.py +++ b/perfkitbenchmarker/windows_virtual_machine.py @@ -60,6 +60,7 @@ Set-MpPreference -DisableRealtimeMonitoring $true Set-MpPreference -DisableBehaviorMonitoring $true Set-MpPreference -DisableBlockAtFirstSeen $true +Set-ExecutionPolicy RemoteSigned Enable-PSRemoting -Force $cert = New-SelfSignedCertificate -DnsName hostname -CertStoreLocation ` Cert:\\LocalMachine\\My\\ diff --git a/tests/providers/aws/aws_relational_db_test.py b/tests/providers/aws/aws_relational_db_test.py index 8f3173d5c5..aad4ca0a14 100644 --- a/tests/providers/aws/aws_relational_db_test.py +++ b/tests/providers/aws/aws_relational_db_test.py @@ -133,6 +133,7 @@ def CreateMockSpec(self, additional_spec_items=None): 'enable_freeze_restore': False, 'create_on_restore_error': False, 'delete_on_freeze_error': False, + 'db_flags': '', } if additional_spec_items: spec_dict.update(additional_spec_items) @@ -372,15 +373,17 @@ def testCreateUnmanagedDb(self): FLAGS['mysql_bin_log'].parse(False) FLAGS['ip_addresses'].parse('REACHABLE') FLAGS['postgres_shared_buffer_size'].parse(100) + FLAGS['db_flags'].parse('') with self._PatchCriticalObjects() as issue_command: db = self.CreateIAASDbFromSpec() self.CreateMockServerVM(db) db._Create() self.assertTrue(db._Exists()) - self.assertEqual(db.endpoint, db.server_vm.internal_ip) self.assertEqual(db.spec.database_username, 'root') self.assertEqual(db.spec.database_password, 'perfkitbenchmarker') self.assertIsNone(issue_command.call_args) + db._PostCreate() + self.assertEqual(db.endpoint, db.server_vm.internal_ip) def testUpdateClusterClass(self): fake_describe_output = textwrap.dedent(""" diff --git a/tests/providers/gcp/gcp_relational_db_test.py b/tests/providers/gcp/gcp_relational_db_test.py index 313b1233a3..e878acfcc2 100644 --- a/tests/providers/gcp/gcp_relational_db_test.py +++ b/tests/providers/gcp/gcp_relational_db_test.py @@ -148,6 +148,7 @@ def createMySQLSpecDict(self): 'enable_freeze_restore': False, 'create_on_restore_error': False, 'delete_on_freeze_error': False, + 'db_flags': '', } def setUp(self): @@ -273,14 +274,16 @@ def testParseEndpoint(self): def testCreateUnmanagedDb(self): FLAGS['use_managed_db'].parse(False) FLAGS['project'].parse('test') + FLAGS['db_flags'].parse('') with PatchCriticalObjects() as issue_command: db = CreateIAASDbFromSpec(self.createMySQLSpecDict()) db._Create() self.assertTrue(db._Exists()) - self.assertEqual(db.endpoint, db.server_vm.internal_ip) self.assertEqual(db.spec.database_username, 'root') self.assertEqual(db.spec.database_password, 'perfkitbenchmarker') self.assertIsNone(issue_command.call_args) + db._PostCreate() + self.assertEqual(db.endpoint, db.server_vm.internal_ip) class GcpPostgresRelationlDbTestCase(pkb_common_test_case.PkbCommonTestCase):