Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add infrastructure to enable 2-machine network testing on 1ES Azure pools. #4364

Merged
merged 34 commits into from
Jun 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
82f554c
secnetperf script for 1es azure pools
ProjectsByJackHe May 15, 2024
ee79eab
more debug logging
ProjectsByJackHe May 16, 2024
00bece4
fix infinite loop issue
ProjectsByJackHe May 17, 2024
223df33
dumb syntax issue
ProjectsByJackHe May 17, 2024
07d9aa5
remove C:\ remove
ProjectsByJackHe May 17, 2024
58ec4dd
wip
ProjectsByJackHe May 18, 2024
223b828
use config pwsh 7
ProjectsByJackHe May 18, 2024
1021118
skip preparing machine for now
ProjectsByJackHe May 18, 2024
e8bc2b9
add support for starting stopping server passively
ProjectsByJackHe May 20, 2024
8d122c4
fix syntax issue
ProjectsByJackHe May 20, 2024
541fe8b
create the file
ProjectsByJackHe May 20, 2024
472561d
more logging
ProjectsByJackHe May 20, 2024
677e82a
remove ps1 extension
ProjectsByJackHe May 20, 2024
0068066
fix ps1 issue
ProjectsByJackHe May 20, 2024
d9b0a7f
get rid of 30s timeout
ProjectsByJackHe May 20, 2024
afd65d5
NULL in case of Az linux
ProjectsByJackHe May 29, 2024
b5d778c
wip
ProjectsByJackHe Jun 3, 2024
248d626
GOAL: Get a successful secnetperf run for linux
ProjectsByJackHe Jun 9, 2024
8e99a40
lets get some data
ProjectsByJackHe Jun 10, 2024
847a708
add stop server logic
ProjectsByJackHe Jun 10, 2024
08c35a2
p2p module remove
ProjectsByJackHe Jun 10, 2024
7665ceb
ensure we stop using remote pwsh if it's not supported
ProjectsByJackHe Jun 11, 2024
494ca53
get some answers
ProjectsByJackHe Jun 11, 2024
0add96a
print more logs
ProjectsByJackHe Jun 11, 2024
e6167b6
&& does not exist lmao
ProjectsByJackHe Jun 11, 2024
d7dfa74
collect me some data
ProjectsByJackHe Jun 11, 2024
d8439ee
add run id and stuff
ProjectsByJackHe Jun 11, 2024
2324724
wrap in a try catch
ProjectsByJackHe Jun 12, 2024
2525317
wip
ProjectsByJackHe Jun 12, 2024
e8b7e3e
wip
ProjectsByJackHe Jun 12, 2024
de8ca1f
get some stdout
ProjectsByJackHe Jun 14, 2024
405e643
forget about core dumps in 1es
ProjectsByJackHe Jun 14, 2024
aae2a05
revert 1es change
ProjectsByJackHe Jun 14, 2024
3565cf3
Merge branch 'main' into jackhe/1es-azure-pools
ProjectsByJackHe Jun 20, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
190 changes: 182 additions & 8 deletions scripts/secnetperf-helpers.psm1
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,71 @@ function Start-RemoteServer {
throw "Server failed to start!"
}

# Passively starts the server on the remote machine by queuing up a new script to execute.
function Start-RemoteServerPassive {
param ($Session, $Command, $RemoteStateDir, $RunId, $SyncerSecret)
if ($Session -eq "NOT_SUPPORTED") {
Write-Host "Command to start server: $Command"
$headers = @{
"secret" = "$SyncerSecret"
}
$url = "https://netperfapiwebapp.azurewebsites.net"
try {
$Response = Invoke-WebRequest -Uri "$url/getkeyvalue?key=$RunId" -Headers $headers
} catch {
Write-Host "Unable to fetch state. Creating a new one now."
$state = [pscustomobject]@{
value=[pscustomobject]@{
"SeqNum" = 0
"Commands" = @($Command)
}}
$StateJson = $state | ConvertTo-Json
$Response = Invoke-WebRequest -Uri "$url/setkeyvalue?key=$RunId" -Headers $headers -Method Post -Body $StateJson -ContentType "application/json"
if ($Response.StatusCode -ne 200) {
Write-GHError "[Start-Remote-Passive] Failed to set the key value!"
throw "Failed to set the key value!"
}
return
}
$CurrState = $Response.Content | ConvertFrom-Json
$CurrState.Commands += $Command
$CurrState = [pscustomobject]@{
value=$CurrState
}
$StateJson = $CurrState | ConvertTo-Json
$Response = Invoke-WebRequest -Uri "$url/setkeyvalue?key=$RunId" -Headers $headers -Method Post -Body $StateJson -ContentType "application/json"
if ($Response.StatusCode -ne 200) {
Write-GHError "[Start-Remote-Passive] Failed to set the key value!"
throw "Failed to set the key value!"
}
return
}

Invoke-Command -Session $Session -ScriptBlock {
if (!(Test-Path $Using:RemoteStateDir)) {
New-Item -ItemType Directory $Using:RemoteStateDir | Out-Null
}
# Fetch all files names inside the directory
$files = Get-ChildItem $Using:RemoteStateDir
# Find the highest lexicographically sorted file name
$max = 0
foreach ($file in $files) {
# Remove .ps1 extension from file.Name
$filename = $file.Name.split(".")[0]
$num = [int]($filename -replace "[^0-9]", "")
if ($num -gt $max) {
$max = $num
}
}
$newmax = $max + 1
# Create a new file with the next number
Write-Host "Creating new file execute_$newmax.ps1"
New-Item -ItemType File (Join-Path $Using:RemoteStateDir ("execute_$newmax.ps1")) | Out-Null
$newFile = Join-Path $Using:RemoteStateDir ("execute_$newmax.ps1")
Set-Content -Path $newFile -Value $Using:Command
}
}

# Sends a special UDP packet to tell the remote secnetperf to shutdown, and then
# waits for the job to complete. Finally, it returns the console output of the
# job.
Expand All @@ -306,6 +371,83 @@ function Stop-RemoteServer {
return $RemoteResult -join "`n"
}

function Stop-RemoteServerAsyncAwait {
param ($Session, $RemoteStateDir, $RemoteAddress, $RunId, $SyncerSecret)
# Ping side-channel socket on 9999 to tell the app to die
$Socket = New-Object System.Net.Sockets.UDPClient
$BytesToSend = @(
0x57, 0xe6, 0x15, 0xff, 0x26, 0x4f, 0x0e, 0x57,
0x88, 0xab, 0x07, 0x96, 0xb2, 0x58, 0xd1, 0x1c
)
if ($Session -eq "NOT_SUPPORTED") {
for ($i = 0; $i -lt 30; $i++) {
$Socket.Send($BytesToSend, $BytesToSend.Length, $RemoteAddress, 9999) | Out-Null
Start-Sleep -Seconds 8 | Out-Null
$headers = @{
"secret" = "$SyncerSecret"
}
$url = "https://netperfapiwebapp.azurewebsites.net"
$Response = Invoke-WebRequest -Uri "$url/getkeyvalue?key=$RunId" -Headers $headers
if (!($Response.StatusCode -eq 200)) {
Write-GHError "[Stop-Remote-Passive] Failed to get the key value!"
throw "Failed to get the key value!"
}
$CurrState = $Response.Content | ConvertFrom-Json
if ($CurrState.SeqNum -eq $CurrState.Commands.Count) {
return
}
}
Write-GHError "[Stop-Remote-Passive] SeqNum less than Commands Count!"
throw "Unable to stop the remote server in time!"
}
$done = $false
$MaxSeqNum = 0
for ($i = 0; $i -lt 30; $i++) {
$Socket.Send($BytesToSend, $BytesToSend.Length, $RemoteAddress, 9999) | Out-Null
Start-Sleep -Seconds 5 | Out-Null
$files = Invoke-Command -Session $Session -ScriptBlock { Get-ChildItem $Using:RemoteStateDir }
foreach ($file in $files) {
$filename = $file.Name.split(".")[0]
$num = [int]($filename -replace "[^0-9]", "")
if ($num -gt $MaxSeqNum) {
$MaxSeqNum = $num
}
}
# Check if completed_<MaxSeqNum>.txt exists
foreach ($file in $files) {
if ($file.Name -eq "completed_$MaxSeqNum.txt") {
$done = $true
break
}
}
if ($done) {
break
}
}
if (!$done) {
Write-GHError "[Stop-Remote-Passive] Unable to find a corresponding 'completed_$MaxSeqNum' file!"
throw "Unable to stop the remote server in time!"
}
}

function Wait-StartRemoteServerPassive {
param ($FullPath, $RemoteName, $OutputDir)

for ($i = 0; $i -lt 30; $i++) {
Start-Sleep -Seconds 5 | Out-Null
Write-Host "Attempt $i to start the remote server, command: $FullPath -target:$RemoteName"
$Process = Start-LocalTest $FullPath "-target:$RemoteName" $OutputDir
$ConsoleOutput = Wait-LocalTest $Process $OutputDir $false 30000 $true
Write-Host "Wait-StartRemoteServerPassive: $ConsoleOutput"
$DidMatch = $ConsoleOutput -match "Completed" # Look for the special string to indicate success.
if ($DidMatch) {
return
}
}

throw "Unable to start the remote server in time!"
}

# Creates a new local process to asynchronously run the test.
function Start-LocalTest {
param ($FullPath, $FullArgs, $OutputDir, $UseSudo)
Expand Down Expand Up @@ -337,7 +479,7 @@ function Start-LocalTest {

# Waits for a local test process to complete, and then returns the console output.
function Wait-LocalTest {
param ($Process, $OutputDir, $testKernel, $TimeoutMs)
param ($Process, $OutputDir, $testKernel, $TimeoutMs, $Silent = $false)
$StdOut = $Process.StandardOutput.ReadToEndAsync()
$StdError = $Process.StandardError.ReadToEndAsync()
# Wait for the process to exit.
Expand All @@ -351,6 +493,10 @@ function Wait-LocalTest {
$Out = $StdOut.Result.Trim()
if ($Out.Length -ne 0) { Write-Host $Out }
} catch {}
if ($Silent) {
Write-Host "Silently ignoring Client timeout!"
return ""
}
throw "secnetperf: Client timed out!"
}
# Verify the process cleanly exitted.
Expand All @@ -360,15 +506,27 @@ function Wait-LocalTest {
$Out = $StdOut.Result.Trim()
if ($Out.Length -ne 0) { Write-Host $Out }
} catch {}
if ($Silent) {
Write-Host "Silently ignoring Client exit code: $($Process.ExitCode)"
return ""
}
throw "secnetperf: Nonzero exit code: $($Process.ExitCode)"
}
# Wait for the output streams to flush.
[System.Threading.Tasks.Task]::WaitAll(@($StdOut, $StdError))
$consoleTxt = $StdOut.Result.Trim()
if ($consoleTxt.Length -eq 0) {
if ($Silent) {
Write-Host "Silently ignoring Client no console output!"
return ""
}
throw "secnetperf: No console output (possibly crashed)!"
}
if ($consoleTxt.Contains("Error")) {
if ($Silent) {
Write-Host "Silently ignoring Client error: $($consoleTxt)"
return ""
}
throw "secnetperf: $($consoleTxt.Substring(7))" # Skip over the "Error: " prefix
}
return $consoleTxt
Expand Down Expand Up @@ -460,7 +618,7 @@ function Get-LatencyOutput {

# Invokes secnetperf with the given arguments for both TCP and QUIC.
function Invoke-Secnetperf {
param ($Session, $RemoteName, $RemoteDir, $UserName, $SecNetPerfPath, $LogProfile, $TestId, $ExeArgs, $io, $Filter)
param ($Session, $RemoteName, $RemoteDir, $UserName, $SecNetPerfPath, $LogProfile, $TestId, $ExeArgs, $io, $Filter, $Environment, $RunId, $SyncerSecret)

$values = @(@(), @())
$latency = $null
Expand All @@ -485,7 +643,7 @@ function Invoke-Secnetperf {
$execMode = $ExeArgs.Substring(0, $ExeArgs.IndexOf(" ")) # First arg is the exec mode
$clientPath = Repo-Path $SecNetPerfPath
$serverArgs = "$execMode -io:$io"
$clientArgs = "-target:netperf-peer $ExeArgs -tcp:$tcp -trimout -watchdog:25000"
$clientArgs = "-target:$RemoteName $ExeArgs -tcp:$tcp -trimout -watchdog:25000"
if ($io -eq "xdp" -or $io -eq "qtip") {
$serverArgs += " -pollidle:10000"
$clientArgs += " -pollidle:10000"
Expand Down Expand Up @@ -524,15 +682,17 @@ function Invoke-Secnetperf {
$artifactDir = Repo-Path "artifacts/logs/$artifactName"
$remoteArtifactDir = "$RemoteDir/artifacts/logs/$artifactName"
New-Item -ItemType Directory $artifactDir -ErrorAction Ignore | Out-Null
Invoke-Command -Session $Session -ScriptBlock {
New-Item -ItemType Directory $Using:remoteArtifactDir -ErrorAction Ignore | Out-Null
if (!($Session -eq "NOT_SUPPORTED")) {
Invoke-Command -Session $Session -ScriptBlock {
New-Item -ItemType Directory $Using:remoteArtifactDir -ErrorAction Ignore | Out-Null
}
}

$clientOut = (Join-Path $artifactDir "client.console.log")
$serverOut = (Join-Path $artifactDir "server.console.log")

# Start logging on both sides, if configured.
if ($LogProfile -ne "" -and $LogProfile -ne "NULL") {
if ($LogProfile -ne "" -and $LogProfile -ne "NULL" -and !($Session -eq "NOT_SUPPORTED")) {
Invoke-Command -Session $Session -ScriptBlock {
try { & "$Using:RemoteDir/scripts/log.ps1" -Cancel } catch {} # Cancel any previous logging
& "$Using:RemoteDir/scripts/log.ps1" -Start -Profile $Using:LogProfile -ProfileInScriptDirectory
Expand All @@ -547,7 +707,17 @@ function Invoke-Secnetperf {

# Start the server running.
"> secnetperf $serverArgs" | Add-Content $serverOut
$job = Start-RemoteServer $Session "$RemoteDir/$SecNetPerfPath" $serverArgs $useSudo

$StateDir = "C:/_state"
if (!$IsWindows) {
$StateDir = "/etc/_state"
}
if ($Environment -eq "azure") {
Start-RemoteServerPassive $Session "$sudo$RemoteDir/$SecNetPerfPath $serverArgs" $StateDir $RunId $SyncerSecret
Wait-StartRemoteServerPassive "$sudo$clientPath" $RemoteName $artifactDir
} else {
$job = Start-RemoteServer $Session "$RemoteDir/$SecNetPerfPath" $serverArgs $useSudo
}

# Run the test multiple times, failing (for now) only if all tries fail.
# TODO: Once all failures have been fixed, consider all errors fatal.
Expand Down Expand Up @@ -586,7 +756,11 @@ function Invoke-Secnetperf {
$testFailures = $true
} finally {
# Stop the server.
try { Stop-RemoteServer $job $RemoteName | Add-Content $serverOut } catch { }
if ($Environment -eq "azure") {
Stop-RemoteServerAsyncAwait $Session $StateDir $RemoteName $RunId $SyncerSecret
} else {
try { Stop-RemoteServer $job $RemoteName | Add-Content $serverOut } catch { }
}

# Stop any logging and copy the logs to the artifacts folder.
if ($LogProfile -ne "" -and $LogProfile -ne "NULL") {
Expand Down
Loading
Loading