190 lines
7.8 KiB
PowerShell
190 lines
7.8 KiB
PowerShell
|
function Invoke-Endpoint {
|
|||
|
<#
|
|||
|
.SYNOPSIS
|
|||
|
Invokes a website and returns the response of the URL
|
|||
|
|
|||
|
.DESCRIPTION
|
|||
|
Wraps Invoke-WebRequest with retry logic
|
|||
|
|
|||
|
.PARAMETER Uri
|
|||
|
URI of the website to invoke
|
|||
|
|
|||
|
.PARAMETER Method
|
|||
|
HTTP method, Get, Post, etc.
|
|||
|
|
|||
|
.PARAMETER Baseuri
|
|||
|
Optional parameter taking the base Uri and concatinating with Uri. "$Baseuri$Uri".
|
|||
|
Helper to avoid having to concatinate before invoking site.
|
|||
|
|
|||
|
.PARAMETER retryStatusCodes
|
|||
|
[System.Net.HttpStatusCode][] objects that are eligible for retry logic.
|
|||
|
[System.Net.HttpStatusCode]::ServiceUnavailable is default.
|
|||
|
|
|||
|
.PARAMETER RetryDelay
|
|||
|
Seconds to wait between retries. Defaults to 5. Is exponential backoff.
|
|||
|
|
|||
|
.PARAMETER RetryCount
|
|||
|
Total number of retry attempts before failing.
|
|||
|
|
|||
|
.PARAMETER Body
|
|||
|
Used for POST Method
|
|||
|
|
|||
|
.PARAMETER Headers
|
|||
|
String of Http headers to pass to the request.
|
|||
|
|
|||
|
.PARAMETER WebSession
|
|||
|
Shared session to use for subsequent requests
|
|||
|
|
|||
|
.PARAMETER UseNewSession
|
|||
|
Bool to determine if a new blank session will be used and returned instead of the passed-in WebSession.
|
|||
|
|
|||
|
.PARAMETER TimeoutSeconds
|
|||
|
Int in seconds for the web timeout.
|
|||
|
|
|||
|
.EXAMPLE
|
|||
|
$r = Invoke-Endpoint -Uri http://google.com
|
|||
|
#>
|
|||
|
[cmdletbinding()]
|
|||
|
param(
|
|||
|
[Parameter(Mandatory, ValueFromPipeline)]
|
|||
|
$Uri,
|
|||
|
[Parameter(Mandatory = $false)]
|
|||
|
$Method = 'GET',
|
|||
|
[Parameter(Mandatory = $false)]
|
|||
|
$Baseuri = '',
|
|||
|
[Parameter(Mandatory=$false)]
|
|||
|
[System.Net.HttpStatusCode[]] $retryStatusCodes,
|
|||
|
[Parameter(Mandatory=$false)]
|
|||
|
$RetryDelay = 5,
|
|||
|
[Parameter(Mandatory=$false)]
|
|||
|
$RetryCount = 3,
|
|||
|
[Parameter(Mandatory=$false)]
|
|||
|
$Body = $null,
|
|||
|
[Parameter(Mandatory=$false)]
|
|||
|
$Headers = $null,
|
|||
|
[Parameter(Mandatory=$false)]
|
|||
|
$WebSession = $null,
|
|||
|
[Parameter(Mandatory=$false)]
|
|||
|
[bool]$UseNewSession = $false,
|
|||
|
[Parameter(Mandatory=$false)]
|
|||
|
[int]$TimeoutSeconds = 120
|
|||
|
)
|
|||
|
begin {
|
|||
|
$auldProgressPreference = $ProgressPreference
|
|||
|
$ProgressPreference = 'silentlycontinue'
|
|||
|
}
|
|||
|
process {
|
|||
|
$logLead = (Get-LogLeadName)
|
|||
|
$logFilePath = (Get-WebTestLogPath -BankUrl "$Baseuri$Uri")
|
|||
|
|
|||
|
$retryCounter = 0
|
|||
|
|
|||
|
$totalRuntime = 0
|
|||
|
$errorsArray = @()
|
|||
|
$runtimeArray = @()
|
|||
|
$result = $null
|
|||
|
|
|||
|
if($null -eq $retryStatusCodes) {
|
|||
|
$retryStatusCodes = @(
|
|||
|
[System.Net.HttpStatusCode]::BadGateway,
|
|||
|
[System.Net.HttpStatusCode]::BadRequest,
|
|||
|
[System.Net.HttpStatusCode]::GatewayTimeout,
|
|||
|
[System.Net.HttpStatusCode]::InternalServerError,
|
|||
|
[System.Net.HttpStatusCode]::ServiceUnavailable
|
|||
|
)
|
|||
|
}
|
|||
|
|
|||
|
do {
|
|||
|
$StopWatch = [System.Diagnostics.StopWatch]::StartNew()
|
|||
|
try {
|
|||
|
"$logLead : Performing web request to $($baseuri)$($uri)" | Tee-OutFile -Append -FilePath $logFilePath | Write-Verbose
|
|||
|
if($UseNewSession) {
|
|||
|
$result = Invoke-WebRequest "$Baseuri$Uri" -Method $Method -Body $Body -Headers $Headers -SessionVariable NewWebSession -UseBasicParsing -TimeoutSec $TimeoutSeconds -DisableKeepAlive -UserAgent "SRE Web Test"
|
|||
|
$WebSession = $NewWebSession
|
|||
|
} else {
|
|||
|
$result = Invoke-WebRequest "$Baseuri$Uri" -Method $Method -Body $Body -Headers $Headers -WebSession $WebSession -UseBasicParsing -TimeoutSec $TimeoutSeconds -DisableKeepAlive -UserAgent "SRE Web Test"
|
|||
|
}
|
|||
|
# On success, stop executing
|
|||
|
break
|
|||
|
}
|
|||
|
catch [System.Net.WebException] {
|
|||
|
"$logLead : Exception: $_" | Tee-OutFile -Append -FilePath $logFilePath | Write-Verbose
|
|||
|
$errorsArray += $_.Exception.Message
|
|||
|
if ($null -eq $_.Exception.Response -and $_.Exception.Message -eq "The operation has timed out.") {
|
|||
|
"$logLead : No response object found. Request timed out." | Tee-OutFile -Append -FilePath $logFilePath | Write-Verbose
|
|||
|
$retryCounter += 1
|
|||
|
$hasRetriedEnough = $retryCounter -gt ($retryCount)
|
|||
|
if ($hasRetriedEnough) {
|
|||
|
"$logLead : Returning response object" | Tee-OutFile -Append -FilePath $logFilePath | Write-Verbose
|
|||
|
break
|
|||
|
} else {
|
|||
|
$sleepTime = $retryDelay*$retryCounter
|
|||
|
"$logLead : Sleeping for $sleepTime seconds" | Tee-OutFile -Append -FilePath $logFilePath | Write-Verbose
|
|||
|
Start-Sleep -Seconds $sleepTime
|
|||
|
$resp = $null
|
|||
|
}
|
|||
|
} else {
|
|||
|
$resp = $_.Exception.Response
|
|||
|
"$logLead : Response code: $($resp.StatusCode)" | Tee-OutFile -Append -FilePath $logFilePath | Write-Verbose
|
|||
|
$retryCounter += 1
|
|||
|
$isARetryCode = $retryStatusCodes -contains $resp.StatusCode
|
|||
|
"$logLead : Is retry code: $isARetryCode" | Tee-OutFile -Append -FilePath $logFilePath | Write-Verbose
|
|||
|
$hasRetriedEnough = $retryCounter -gt ($retryCount)
|
|||
|
"$logLead : Has retried enough: $hasRetriedEnough" | Tee-OutFile -Append -FilePath $logFilePath | Write-Verbose
|
|||
|
if ($hasRetriedEnough -or(-not($isARetryCode))) {
|
|||
|
"$logLead : Returning response object" | Tee-OutFile -Append -FilePath $logFilePath | Write-Verbose
|
|||
|
break
|
|||
|
} else {
|
|||
|
$sleepTime = $retryDelay*$retryCounter
|
|||
|
"$logLead : Sleeping for $sleepTime seconds" | Tee-OutFile -Append -FilePath $logFilePath | Write-Verbose
|
|||
|
Start-Sleep -Seconds $sleepTime
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
catch {
|
|||
|
$errorsArray += $_.Exception.Message
|
|||
|
"$logLead : Got a generic exception. Quitting immediately" | Tee-OutFile -Append -FilePath $logFilePath | Write-Verbose
|
|||
|
break
|
|||
|
} finally {
|
|||
|
$StopWatch.Stop()
|
|||
|
$totalRuntime += $StopWatch.ElapsedMilliseconds
|
|||
|
$runtimeArray += $StopWatch.Elapsed.ToString("ss\.fffffff")
|
|||
|
|
|||
|
$isSuccess = $true
|
|||
|
|
|||
|
if($result.StatusCode -ne 200){
|
|||
|
if($null -eq $resp){
|
|||
|
# If we got a timeout, send a null result
|
|||
|
Write-Verbose "$logLead : Request timed out."
|
|||
|
$result = $null
|
|||
|
} else {
|
|||
|
# If we got a failure response, map the most recent exception's data onto the result and give that back.
|
|||
|
Write-Verbose "$logLead : Got a $($resp.StatusCode)"
|
|||
|
$result = $resp
|
|||
|
}
|
|||
|
|
|||
|
$isSuccess = $false
|
|||
|
}
|
|||
|
|
|||
|
$responseObject = @{
|
|||
|
ErrorResults = $errorsArray;
|
|||
|
LastError = $errorsArray[-1];
|
|||
|
HasErrors = $errorsArray.Count -gt 0;
|
|||
|
Result = $result;
|
|||
|
Success = $isSuccess;
|
|||
|
StatusCode = $result.StatusCode;
|
|||
|
WebSession = $WebSession;
|
|||
|
Runtimes = $runtimeArray;
|
|||
|
LastRuntime = $runtimeArray[-1];
|
|||
|
TotalRuntime = [System.TimeSpan]::FromMilliseconds($totalRuntime).ToString()
|
|||
|
}
|
|||
|
$result = $null
|
|||
|
}
|
|||
|
} while ($true)
|
|||
|
|
|||
|
return $responseObject
|
|||
|
}
|
|||
|
end {
|
|||
|
$ProgressPreference = $auldProgressPreference
|
|||
|
}
|
|||
|
}
|