Skip to content

Commit da1f338

Browse files
azure-sdkbenbp
andauthored
Move stress testing scripts to eng/common (#22954)
Co-authored-by: Ben Broderick Phillips <bebroder@microsoft.com>
1 parent 9c8e213 commit da1f338

File tree

2 files changed

+227
-0
lines changed

2 files changed

+227
-0
lines changed
Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
[CmdletBinding(DefaultParameterSetName = 'Default')]
2+
param(
3+
[string]$SearchDirectory,
4+
[hashtable]$Filters,
5+
[string]$Environment,
6+
[string]$Repository,
7+
[switch]$PushImages,
8+
[string]$ClusterGroup,
9+
[string]$DeployId,
10+
11+
[Parameter(ParameterSetName = 'DoLogin', Mandatory = $true)]
12+
[switch]$Login,
13+
14+
[Parameter(ParameterSetName = 'DoLogin')]
15+
[string]$Subscription
16+
)
17+
18+
$ErrorActionPreference = 'Stop'
19+
20+
. $PSScriptRoot/find-all-stress-packages.ps1
21+
$FailedCommands = New-Object Collections.Generic.List[hashtable]
22+
23+
if (!(Get-Module powershell-yaml)) {
24+
Install-Module -Name powershell-yaml -RequiredVersion 0.4.1 -Force -Scope CurrentUser
25+
}
26+
27+
# Powershell does not (at time of writing) treat exit codes from external binaries
28+
# as cause for stopping execution, so do this via a wrapper function.
29+
# See https://github.com/PowerShell/PowerShell-RFC/pull/277
30+
function Run() {
31+
Write-Host "`n==> $args`n" -ForegroundColor Green
32+
$command, $arguments = $args
33+
& $command $arguments
34+
if ($LASTEXITCODE) {
35+
Write-Error "Command '$args' failed with code: $LASTEXITCODE" -ErrorAction 'Continue'
36+
$FailedCommands.Add(@{ command = "$args"; code = $LASTEXITCODE })
37+
}
38+
}
39+
40+
function RunOrExitOnFailure() {
41+
run @args
42+
if ($LASTEXITCODE) {
43+
exit $LASTEXITCODE
44+
}
45+
}
46+
47+
function Login([string]$subscription, [string]$clusterGroup, [boolean]$pushImages) {
48+
Write-Host "Logging in to subscription, cluster and container registry"
49+
az account show *> $null
50+
if ($LASTEXITCODE) {
51+
RunOrExitOnFailure az login --allow-no-subscriptions
52+
}
53+
54+
$clusterName = (az aks list -g $clusterGroup -o json| ConvertFrom-Json).name
55+
56+
RunOrExitOnFailure az aks get-credentials `
57+
-n "$clusterName" `
58+
-g "$clusterGroup" `
59+
--subscription "$subscription" `
60+
--overwrite-existing
61+
62+
if ($pushImages) {
63+
$registry = (az acr list -g $clusterGroup -o json | ConvertFrom-Json).name
64+
RunOrExitOnFailure az acr login -n $registry
65+
}
66+
}
67+
68+
function DeployStressTests(
69+
[string]$searchDirectory = '.',
70+
[hashtable]$filters = @{},
71+
[string]$environment = 'test',
72+
[string]$repository = 'images',
73+
[boolean]$pushImages = $false,
74+
[string]$clusterGroup = 'rg-stress-test-cluster-',
75+
[string]$deployId = 'local',
76+
[string]$subscription = 'Azure SDK Test Resources'
77+
) {
78+
if ($PSCmdlet.ParameterSetName -eq 'DoLogin') {
79+
Login $subscription $clusterGroup $pushImages
80+
}
81+
82+
RunOrExitOnFailure helm repo add stress-test-charts https://stresstestcharts.blob.core.windows.net/helm/
83+
Run helm repo update
84+
if ($LASTEXITCODE) { return $LASTEXITCODE }
85+
86+
$pkgs = FindStressPackages $searchDirectory $filters
87+
Write-Host "" "Found $($pkgs.Length) stress test packages:"
88+
Write-Host $pkgs.Directory ""
89+
foreach ($pkg in $pkgs) {
90+
Write-Host "Deploying stress test at '$($pkg.Directory)'"
91+
DeployStressPackage $pkg $deployId $environment $repository $pushImages
92+
}
93+
94+
Write-Host "Releases deployed by $deployId"
95+
Run helm list --all-namespaces -l deployId=$deployId
96+
97+
if ($FailedCommands) {
98+
Write-Warning "The following commands failed:"
99+
foreach ($cmd in $FailedCommands) {
100+
Write-Error "'$($cmd.command)' failed with code $($cmd.code)" -ErrorAction 'Continue'
101+
}
102+
exit 1
103+
}
104+
}
105+
106+
function DeployStressPackage(
107+
[object]$pkg,
108+
[string]$deployId,
109+
[string]$environment,
110+
[string]$repository,
111+
[boolean]$pushImages
112+
) {
113+
$registry = (az acr list -g $clusterGroup -o json | ConvertFrom-Json).name
114+
if (!$registry) {
115+
Write-Host "Could not find container registry in resource group $clusterGroup"
116+
exit 1
117+
}
118+
119+
if ($pushImages) {
120+
Run helm dependency update $pkg.Directory
121+
if ($LASTEXITCODE) { return $LASTEXITCODE }
122+
123+
$dockerFiles = Get-ChildItem "$($pkg.Directory)/Dockerfile*"
124+
foreach ($dockerFile in $dockerFiles) {
125+
# Infer docker image name from parent directory name, if file is named `Dockerfile`
126+
# or from suffix, is file is named like `Dockerfile.myimage` (for multiple dockerfiles).
127+
$prefix, $imageName = $dockerFile.Name.Split(".")
128+
if (!$imageName) {
129+
$imageName = $dockerFile.Directory.Name
130+
}
131+
$imageTag = "${registry}.azurecr.io/$($repository.ToLower())/$($imageName):$deployId"
132+
Write-Host "Building and pushing stress test docker image '$imageTag'"
133+
Run docker build -t $imageTag -f $dockerFile.FullName $dockerFile.DirectoryName
134+
if ($LASTEXITCODE) { return $LASTEXITCODE }
135+
Run docker push $imageTag
136+
if ($LASTEXITCODE) {
137+
if ($PSCmdlet.ParameterSetName -ne 'DoLogin') {
138+
Write-Warning "If docker push is failing due to authentication issues, try calling this script with '-Login'"
139+
}
140+
return $LASTEXITCODE
141+
}
142+
}
143+
}
144+
145+
Write-Host "Creating namespace $($pkg.Namespace) if it does not exist..."
146+
kubectl create namespace $pkg.Namespace --dry-run=client -o yaml | kubectl apply -f -
147+
148+
Write-Host "Installing or upgrading stress test $($pkg.ReleaseName) from $($pkg.Directory)"
149+
Run helm upgrade $pkg.ReleaseName $pkg.Directory `
150+
-n $pkg.Namespace `
151+
--install `
152+
--set repository=$registry.azurecr.io/$repository `
153+
--set tag=$deployId `
154+
--set stress-test-addons.env=$environment
155+
if ($LASTEXITCODE) {
156+
# Issues like 'UPGRADE FAILED: another operation (install/upgrade/rollback) is in progress'
157+
# can be the result of cancelled `upgrade` operations (e.g. ctrl-c).
158+
# See https://github.com/helm/helm/issues/4558
159+
Write-Warning "The issue may be fixable by first running 'helm rollback -n $($pkg.Namespace) $($pkg.ReleaseName)'"
160+
return $LASTEXITCODE
161+
}
162+
163+
# Helm 3 stores release information in kubernetes secrets. The only way to add extra labels around
164+
# specific releases (thereby enabling filtering on `helm list`) is to label the underlying secret resources.
165+
# There is not currently support for setting these labels via the helm cli.
166+
$helmReleaseConfig = kubectl get secrets `
167+
-n $pkg.Namespace `
168+
-l status=deployed,name=$($pkg.ReleaseName) `
169+
-o jsonpath='{.items[0].metadata.name}'
170+
171+
Run kubectl label secret -n $pkg.Namespace --overwrite $helmReleaseConfig deployId=$deployId
172+
}
173+
174+
DeployStressTests @PSBoundParameters
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
param(
2+
[string]$searchDirectory = '.',
3+
[hashtable]$filters = @{}
4+
)
5+
6+
class StressTestPackageInfo {
7+
[string]$Namespace
8+
[string]$Directory
9+
[string]$ReleaseName
10+
}
11+
12+
function FindStressPackages([string]$directory, [hashtable]$filters = @{}) {
13+
# Bare minimum filter for stress tests
14+
$filters['stressTest'] = 'true'
15+
16+
$packages = @()
17+
$chartFiles = Get-ChildItem -Recurse -Filter 'Chart.yaml' $directory
18+
foreach ($chartFile in $chartFiles) {
19+
$chart = ParseChart $chartFile
20+
if (matchesAnnotations $chart $filters) {
21+
$packages += NewStressTestPackageInfo $chart $chartFile
22+
}
23+
}
24+
25+
return $packages
26+
}
27+
28+
function ParseChart([string]$chartFile) {
29+
return ConvertFrom-Yaml (Get-Content -Raw $chartFile)
30+
}
31+
32+
function MatchesAnnotations([hashtable]$chart, [hashtable]$filters) {
33+
foreach ($filter in $filters.GetEnumerator()) {
34+
if (!$chart.annotations -or $chart.annotations[$filter.Key] -ne $filter.Value) {
35+
return $false
36+
}
37+
}
38+
39+
return $true
40+
}
41+
42+
function NewStressTestPackageInfo([hashtable]$chart, [System.IO.FileInfo]$chartFile) {
43+
return [StressTestPackageInfo]@{
44+
Namespace = $chart.annotations.namespace
45+
Directory = $chartFile.DirectoryName
46+
ReleaseName = $chart.name
47+
}
48+
}
49+
50+
# Don't call functions when the script is being dot sourced
51+
if ($MyInvocation.InvocationName -ne ".") {
52+
FindStressPackages $searchDirectory $filters
53+
}

0 commit comments

Comments
 (0)