...

Text file src/github.com/Azure/azure-sdk-for-go/eng/common/scripts/stress-testing/stress-test-deployment-lib.ps1

Documentation: github.com/Azure/azure-sdk-for-go/eng/common/scripts/stress-testing

     1$ErrorActionPreference = 'Stop'
     2
     3. $PSScriptRoot/find-all-stress-packages.ps1
     4$FailedCommands = New-Object Collections.Generic.List[hashtable]
     5
     6. (Join-Path $PSScriptRoot "../Helpers" PSModule-Helpers.ps1)
     7
     8# Powershell does not (at time of writing) treat exit codes from external binaries
     9# as cause for stopping execution, so do this via a wrapper function.
    10# See https://github.com/PowerShell/PowerShell-RFC/pull/277
    11function Run()
    12{
    13    Write-Host "`n==> $args`n" -ForegroundColor Green
    14    $command, $arguments = $args
    15    & $command $arguments
    16    if ($LASTEXITCODE) {
    17        Write-Error "Command '$args' failed with code: $LASTEXITCODE" -ErrorAction 'Continue'
    18        $FailedCommands.Add(@{ command = "$args"; code = $LASTEXITCODE })
    19    }
    20}
    21
    22function RunOrExitOnFailure()
    23{
    24    run @args
    25    if ($LASTEXITCODE) {
    26        exit $LASTEXITCODE
    27    }
    28}
    29
    30function Login([string]$subscription, [string]$clusterGroup, [switch]$pushImages)
    31{
    32    Write-Host "Logging in to subscription, cluster and container registry"
    33    az account show *> $null
    34    if ($LASTEXITCODE) {
    35        RunOrExitOnFailure az login --allow-no-subscriptions
    36    }
    37
    38    # Discover cluster name, only one cluster per group is expected
    39    Write-Host "Listing AKS cluster in $subscription/$clusterGroup"
    40    $cluster = RunOrExitOnFailure az aks list -g $clusterGroup --subscription $subscription -o json
    41    $clusterName = ($cluster | ConvertFrom-Json).name
    42
    43    $kubeContext = (RunOrExitOnFailure kubectl config view -o json) | ConvertFrom-Json
    44    $defaultNamespace = $kubeContext.contexts.Where({ $_.name -eq $clusterName }).context.namespace
    45
    46    RunOrExitOnFailure az aks get-credentials `
    47        -n "$clusterName" `
    48        -g "$clusterGroup" `
    49        --subscription "$subscription" `
    50        --overwrite-existing
    51
    52    if ($defaultNamespace) {
    53        RunOrExitOnFailure kubectl config set-context $clusterName --namespace $defaultNamespace
    54    }
    55
    56    if ($pushImages) {
    57        $registry = RunOrExitOnFailure az acr list -g $clusterGroup --subscription $subscription -o json
    58        $registryName = ($registry | ConvertFrom-Json).name
    59        RunOrExitOnFailure az acr login -n $registryName
    60    }
    61}
    62
    63function DeployStressTests(
    64    [string]$searchDirectory = '.',
    65    [hashtable]$filters = @{},
    66    [string]$environment = 'test',
    67    [string]$repository = '',
    68    [switch]$pushImages,
    69    [string]$clusterGroup = '',
    70    [string]$deployId = 'local',
    71    [switch]$login,
    72    [string]$subscription = '',
    73    [switch]$CI,
    74    [string]$Namespace
    75) {
    76    if ($environment -eq 'test') {
    77        if ($clusterGroup -or $subscription) {
    78            Write-Warning "Overriding cluster group and subscription with defaults for 'test' environment."
    79        }
    80        $clusterGroup = 'rg-stress-cluster-test'
    81        $subscription = 'Azure SDK Developer Playground'
    82    } elseif ($environment -eq 'prod') {
    83        if ($clusterGroup -or $subscription) {
    84            Write-Warning "Overriding cluster group and subscription with defaults for 'prod' environment."
    85        }
    86        $clusterGroup = 'rg-stress-cluster-prod'
    87        $subscription = 'Azure SDK Test Resources'
    88    }
    89
    90    if ($login) {
    91        if (!$clusterGroup -or !$subscription) {
    92            throw "clusterGroup and subscription parameters must be specified when logging into an environment that is not test or prod."
    93        }
    94        Login -subscription $subscription -clusterGroup $clusterGroup -pushImages:$pushImages
    95    }
    96
    97    RunOrExitOnFailure helm repo add stress-test-charts https://stresstestcharts.blob.core.windows.net/helm/
    98    Run helm repo update
    99    if ($LASTEXITCODE) { return $LASTEXITCODE }
   100
   101    $pkgs = FindStressPackages -directory $searchDirectory -filters $filters -CI:$CI -namespaceOverride $Namespace
   102    Write-Host "" "Found $($pkgs.Length) stress test packages:"
   103    Write-Host $pkgs.Directory ""
   104    foreach ($pkg in $pkgs) {
   105        Write-Host "Deploying stress test at '$($pkg.Directory)'"
   106        DeployStressPackage `
   107            -pkg $pkg `
   108            -deployId $deployId `
   109            -environment $environment `
   110            -repositoryBase $repository `
   111            -pushImages:$pushImages `
   112            -login:$login
   113    }
   114
   115    Write-Host "Releases deployed by $deployId"
   116    Run helm list --all-namespaces -l deployId=$deployId
   117
   118    if ($FailedCommands) {
   119        Write-Warning "The following commands failed:"
   120        foreach ($cmd in $FailedCommands) {
   121            Write-Error "'$($cmd.command)' failed with code $($cmd.code)" -ErrorAction 'Continue'
   122        }
   123        exit 1
   124    }
   125
   126    Write-Host "`nStress test telemetry links (dashboard, fileshare, etc.): https://aka.ms/azsdk/stress/dashboard"
   127}
   128
   129function DeployStressPackage(
   130    [object]$pkg,
   131    [string]$deployId,
   132    [string]$environment,
   133    [string]$repositoryBase,
   134    [switch]$pushImages,
   135    [switch]$login
   136) {
   137    $registry = RunOrExitOnFailure az acr list -g $clusterGroup --subscription $subscription -o json
   138    $registryName = ($registry | ConvertFrom-Json).name
   139
   140    Run helm dependency update $pkg.Directory
   141    if ($LASTEXITCODE) { return }
   142
   143    if (Test-Path "$($pkg.Directory)/stress-test-resources.bicep") {
   144        Run az bicep build -f "$($pkg.Directory)/stress-test-resources.bicep"
   145        if ($LASTEXITCODE) { return }
   146    }
   147
   148    $imageTag = "${registryName}.azurecr.io"
   149    if ($repositoryBase) {
   150        $imageTag += "/$repositoryBase"
   151    }
   152    $imageTag += "/$($pkg.Namespace)/$($pkg.ReleaseName):${deployId}"
   153
   154    $dockerFilePath = if ($pkg.Dockerfile) {
   155        Join-Path $pkg.Directory $pkg.Dockerfile
   156    } else {
   157        "$($pkg.Directory)/Dockerfile"
   158    }
   159    $dockerFilePath = [System.IO.Path]::GetFullPath($dockerFilePath)
   160
   161    if ($pushImages -and (Test-Path $dockerFilePath)) {
   162        Write-Host "Building and pushing stress test docker image '$imageTag'"
   163        $dockerFile = Get-ChildItem $dockerFilePath
   164        $dockerBuildFolder = if ($pkg.DockerBuildDir) {
   165            Join-Path $pkg.Directory $pkg.DockerBuildDir
   166        } else {
   167            $dockerFile.DirectoryName
   168        }
   169        $dockerBuildFolder = [System.IO.Path]::GetFullPath($dockerBuildFolder).Trim()
   170
   171        Run docker build -t $imageTag -f $dockerFile $dockerBuildFolder
   172        if ($LASTEXITCODE) { return }
   173
   174        Write-Host "`nContainer image '$imageTag' successfully built. To run commands on the container locally:" -ForegroundColor Blue
   175        Write-Host "  docker run -it $imageTag" -ForegroundColor DarkBlue
   176        Write-Host "  docker run -it $imageTag <shell, e.g. 'bash' 'pwsh' 'sh'>" -ForegroundColor DarkBlue
   177        Write-Host "To show installed container images:" -ForegroundColor Blue
   178        Write-Host "  docker image ls" -ForegroundColor DarkBlue
   179        Write-Host "To show running containers:" -ForegroundColor Blue
   180        Write-Host "  docker ps" -ForegroundColor DarkBlue
   181
   182        Run docker push $imageTag
   183        if ($LASTEXITCODE) {
   184            if ($login) {
   185                Write-Warning "If docker push is failing due to authentication issues, try calling this script with '-Login'"
   186            }
   187            return
   188        }
   189    }
   190
   191    Write-Host "Creating namespace $($pkg.Namespace) if it does not exist..."
   192    kubectl create namespace $pkg.Namespace --dry-run=client -o yaml | kubectl apply -f -
   193    if ($LASTEXITCODE) {exit $LASTEXITCODE}
   194
   195    Write-Host "Installing or upgrading stress test $($pkg.ReleaseName) from $($pkg.Directory)"
   196    Run helm upgrade $pkg.ReleaseName $pkg.Directory `
   197        -n $pkg.Namespace `
   198        --install `
   199        --set image=$imageTag `
   200        --set stress-test-addons.env=$environment
   201    if ($LASTEXITCODE) {
   202        # Issues like 'UPGRADE FAILED: another operation (install/upgrade/rollback) is in progress'
   203        # can be the result of cancelled `upgrade` operations (e.g. ctrl-c).
   204        # See https://github.com/helm/helm/issues/4558
   205        Write-Warning "The issue may be fixable by first running 'helm rollback -n $($pkg.Namespace) $($pkg.ReleaseName)'"
   206        return
   207    }
   208
   209    # Helm 3 stores release information in kubernetes secrets. The only way to add extra labels around
   210    # specific releases (thereby enabling filtering on `helm list`) is to label the underlying secret resources.
   211    # There is not currently support for setting these labels via the helm cli.
   212    $helmReleaseConfig = kubectl get secrets `
   213        -n $pkg.Namespace `
   214        -l status=deployed,name=$($pkg.ReleaseName) `
   215        -o jsonpath='{.items[0].metadata.name}'
   216
   217    Run kubectl label secret -n $pkg.Namespace --overwrite $helmReleaseConfig deployId=$deployId
   218}
   219
   220function CheckDependencies()
   221{
   222    $deps = @(
   223        @{
   224            Command = "docker";
   225            Help = "Docker must be installed: https://docs.docker.com/get-docker/";
   226        }
   227        @{
   228            Command = "kubectl";
   229            Help = "kubectl must be installed: https://kubernetes.io/docs/tasks/tools/#kubectl";
   230        },
   231        @{
   232            Command = "helm";
   233            Help = "helm must be installed: https://helm.sh/docs/intro/install/";
   234        },
   235        @{
   236            Command = "az";
   237            Help = "Azure CLI must be installed: https://docs.microsoft.com/en-us/cli/azure/install-azure-cli";
   238        }
   239    )
   240
   241    Install-ModuleIfNotInstalled "powershell-yaml" "0.4.1" | Import-Module
   242
   243    $shouldError = $false
   244    foreach ($dep in $deps) {
   245        if (!(Get-Command $dep.Command -ErrorAction SilentlyContinue)) {
   246            $shouldError = $true
   247            Write-Error $dep.Help
   248        }
   249    }
   250
   251    if ($shouldError) {
   252        exit 1
   253    }
   254
   255}

View as plain text