Skip to content

Commit 3733d33

Browse files
authored
[CI] Move pipelines to new setup for PROD (#225)
* deploy-storage-proxy.ps1: misc improvements * remove un-needed script * Remove hardcoded values in cleanup-old-containers script. And don't fail .. if an old container cannot be removed - it does not need to block a new deployment. * Add error handling when accessing blob storage * AzureBlobFileSystem - use AZURE_CLIENT_ID instead of ARM_CLIENT_ID * Add /health, /health/alive, /health/detailed endpoints * fixup msbuild targets to work without any V1 repos * azure-pipelines.yml: Enable publishing to the new prod setup * disable health endpoints
1 parent 6fcc245 commit 3733d33

File tree

11 files changed

+428
-120
lines changed

11 files changed

+428
-120
lines changed

azure-pipelines.yml

Lines changed: 105 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
schedules:
22
- cron: 0 10 * * *
3-
displayName: Every day at 10:00 UTC
3+
displayName: 🟣Every day at 10:00 UTC
44
branches:
55
include:
66
- main
@@ -13,12 +13,52 @@ resources:
1313
name: 1ESPipelineTemplates/1ESPipelineTemplates
1414
ref: refs/tags/release
1515

16+
variables:
17+
- name: system.debug
18+
value: true
19+
- name: azureSubscriptionForStage1Download
20+
value: 'SourceDotNet Stage1 Publish'
21+
- name: webAppName
22+
value: 'netsourceindexprod'
23+
- name: resourceGroupName
24+
value: 'source.dot.net'
25+
26+
# Note: the subscription name variables need to be at the pipeline level to be used in the AzureCLI tasks.
27+
# that's because the tasks get looked at very early in the pipeline processing.
28+
# Also, make sure to use the template expression syntax ${{ }}
29+
# Issue: https://github.com/microsoft/azure-pipelines-tasks/issues/14365#issuecomment-2286398867
30+
31+
- ${{ if and(ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest'), eq(variables['Build.SourceBranch'], 'refs/heads/main')) }}:
32+
- name: poolName
33+
value: 'NetSourceIndexProd-Pool'
34+
- name: azureSubscriptionForStorageAndWebAppSlot
35+
value: 'NetSourceIndex-Prod'
36+
- name: isOfficialBuild
37+
value: True
38+
- name: temporaryDeploymentSlot
39+
value: 'staging'
40+
- name: storageAccountName
41+
value: 'netsourceindexprod'
42+
- name: stagingHost
43+
value: 'staging.source.dot.net'
44+
- ${{ else }}:
45+
- name: poolName
46+
value: 'NetSourceIndexValid-Pool'
47+
- name: azureSubscriptionForStorageAndWebAppSlot
48+
value: 'NetSourceIndex-Validation-Prod'
49+
- name: isOfficialBuild
50+
value: False
51+
- name: temporaryDeploymentSlot
52+
value: 'validation'
53+
- name: storageAccountName
54+
value: 'netsourceindexvalidprod'
55+
1656
extends:
1757
template: v1/1ES.Official.PipelineTemplate.yml@1ESPipelineTemplates
1858
parameters:
1959
pool:
20-
name: NetCore1ESPool-Internal-XL
21-
image: 1es-windows-2022
60+
name: ${{ variables.poolName }}
61+
image: 1es-pt-agent-image
2262
os: windows
2363
customBuildTags:
2464
- ES365AIMigrationTooling
@@ -29,25 +69,6 @@ extends:
2969
displayName: Build Source Index
3070
timeoutInMinutes: 360
3171

32-
variables:
33-
- name: system.debug
34-
value: true
35-
- ${{ if and(ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest'), eq(variables['Build.SourceBranch'], 'refs/heads/main')) }}:
36-
- name: isOfficialBuild
37-
value: True
38-
- name: deploymentSlot
39-
value: staging
40-
- name: storageAccount
41-
value: netsourceindex
42-
- ${{ else }}:
43-
- name: isOfficialBuild
44-
value: False
45-
- name: deploymentSlot
46-
value: validation
47-
- name: storageAccount
48-
value: netsourceindexvalidation
49-
- group: source-dot-net stage1 variables
50-
5172
templateContext:
5273
outputs:
5374
- output: nuget
@@ -67,167 +88,177 @@ extends:
6788
submodules: true
6889

6990
- task: DeleteFiles@1
70-
displayName: Delete files from bin
91+
displayName: 🟣Delete files from bin
7192
inputs:
7293
SourceFolder: bin
7394
Contents: '**/*'
7495

7596
- task: UseDotNet@2
76-
displayName: Install .NET Sdk
97+
displayName: 🟣Install .NET Sdk
7798
inputs:
7899
useGlobalJson: true
79100

80101
- task: DotNetCoreCLI@2
81-
displayName: dotnet restore
102+
displayName: 🟣dotnet restore
82103
inputs:
83104
command: custom
84105
custom: restore
85106
projects: |
86107
**\*.sln
87108
88109
- task: DotNetCoreCLI@2
89-
displayName: dotnet build
110+
displayName: 🟣dotnet build
90111
inputs:
91112
command: 'build'
92113
projects: |
93114
src\source-indexer.sln
94115
src\SourceBrowser\SourceBrowser.sln
95-
arguments: '/p:PackageOutputPath=$(Build.ArtifactStagingDirectory)/packages'
116+
arguments: '/p:PackageOutputPath=$(Build.ArtifactStagingDirectory)/packages /p:EnableDebugLogging=true'
96117

97118
- task: AzureCLI@2
98-
displayName: Log in to Azure and clone data
119+
displayName: 🟣Clone Stage1 data
99120
inputs:
100-
azureSubscription: 'SourceDotNet Stage1 Publish'
121+
azureSubscription: ${{ variables.azureSubscriptionForStage1Download }}
101122
addSpnToEnvironment: true
102123
scriptType: 'ps'
103124
scriptLocation: 'inlineScript'
104125
inlineScript: |
105126
dotnet build build.proj /t:Clone /v:n /bl:$(Build.ArtifactStagingDirectory)/logs/clone.binlog /p:Stage1StorageAccount=netsourceindexstage1 /p:Stage1StorageContainer=stage1
106127
107128
- task: DotNetCoreCLI@2
108-
displayName: Prepare All Repositories
129+
displayName: 🟣Prepare All Repositories
109130
inputs:
110131
command: 'build'
111132
projects: 'build.proj'
112133
arguments: '/t:Prepare /v:n /bl:$(Build.ArtifactStagingDirectory)/logs/prepare.binlog'
113134

114135
- task: DotNetCoreCLI@2
115-
displayName: Build source index
136+
displayName: 🟣Build source index
116137
inputs:
117138
command: 'build'
118139
projects: 'build.proj'
119140
arguments: '/t:BuildIndex /v:n /bl:$(Build.ArtifactStagingDirectory)/logs/build.binlog'
120141

121142
- task: CopyFiles@2
143+
displayName: 🟣Copy webapp files
122144
inputs:
123145
sourceFolder: bin/index/
124146
contents: |
125147
**
126148
!index/**
127-
targetFolder: bin/index-stage/
149+
targetFolder: bin/webapp-stage/
150+
128151
cleanTargetFolder: true
129152

153+
- pwsh: New-Item -ItemType File -Force -Path bin/index/index/.health
154+
displayName: 🟣Create .health file
155+
130156
- powershell: deployment/normalize-case.ps1 -Root bin/index/index/
131-
displayName: Normalize Case Of Index Files
157+
displayName: 🟣Normalize Case Of Index Files
132158

133159
- task: AzureCLI@2
134-
displayName: Create new storage container
160+
displayName: 🟣Create new storage container
135161
inputs:
136-
azureSubscription: SourceDotNet-Deployment-ARM
162+
azureSubscription: ${{ variables.azureSubscriptionForStorageAndWebAppSlot }}
137163
scriptLocation: inlineScript
138164
scriptType: ps
139-
inlineScript: >
140-
deployment/upload-index-to-container.ps1
141-
-StorageAccountName $(storageAccount)
142-
-OutFile bin/index.url
165+
inlineScript: deployment/create-container.ps1 -StorageAccountName $(storageAccountName)
166+
workingDirectory: $(Build.SourcesDirectory)
143167

144168
- task: AzureFileCopy@6
145-
displayName: Upload index to Azure Storage
169+
displayName: 🟣Upload index to Azure Storage
146170
inputs:
147-
azureSubscription: SourceDotNet-Deployment-ARM
171+
azureSubscription: ${{ variables.azureSubscriptionForStorageAndWebAppSlot }}
148172
SourcePath: "bin/index/index/*"
149173
Destination: AzureBlob
150-
storage: $(storageAccount)
174+
storage: $(storageAccountName)
151175
ContainerName: $(NEW_CONTAINER_NAME)
152176

153177
- task: AzureRmWebAppDeployment@4
154-
displayName: 'Azure App Service Deploy: netsourceindex'
178+
displayName: '🟣Azure App Service Deploy: $(temporaryDeploymentSlot) slot'
155179
inputs:
156180
ConnectionType: AzureRM
157-
azureSubscription: SourceDotNet-Deployment-ARM
181+
azureSubscription: ${{ variables.azureSubscriptionForStorageAndWebAppSlot }}
158182
appType: webApp
159-
WebAppName: netsourceindex
160-
ResourceGroupName: source.dot.net
183+
WebAppName: ${{ variables.webAppName }}
184+
ResourceGroupName: $(resourceGroupName)
161185
deployToSlotOrASE: true
162-
SlotName: $(deploymentSlot)
163-
packageForLinux: bin/index-stage/
186+
SlotName: $(temporaryDeploymentSlot)
187+
packageForLinux: bin/webapp-stage/
164188
enableCustomDeployment: true
165189
DeploymentType: zipDeploy
166190
RemoveAdditionalFilesFlag: true
167191

168192
- task: AzureCLI@2
169-
displayName: Deploy Storage Proxy Url to WebApp
193+
displayName: 🟣Deploy Storage Proxy Url to WebApp
170194
inputs:
171-
azureSubscription: SourceDotNet-Deployment-ARM
195+
azureSubscription: ${{ variables.azureSubscriptionForStorageAndWebAppSlot }}
172196
scriptLocation: inlineScript
173197
scriptType: ps
174198
inlineScript: >
175199
deployment/deploy-storage-proxy.ps1
176-
-ProxyUrlFile bin/index.url
177-
-ResourceGroup source.dot.net
178-
-WebappName netsourceindex
179-
-Slot $(deploymentSlot)
200+
-NewContainerName "$(NEW_CONTAINER_NAME)"
201+
-ResourceGroup "$(resourceGroupName)"
202+
-StorageAccountName "$(storageAccountName)"
203+
-WebappName "${{ variables.webAppName }}"
204+
-Slot "$(temporaryDeploymentSlot)"
180205
181206
- task: AzureCLI@2
182-
displayName: Restart WebApp
207+
displayName: 🟣Restart WebApp
183208
inputs:
184-
azureSubscription: SourceDotNet-Deployment-ARM
209+
azureSubscription: ${{ variables.azureSubscriptionForStorageAndWebAppSlot }}
185210
scriptLocation: inlineScript
186211
scriptType: ps
187212
inlineScript: |
188-
az webapp restart --name netsourceindex --slot $(deploymentSlot) --resource-group source.dot.net
213+
az webapp restart --name $(webAppName) --slot $(temporaryDeploymentSlot) --resource-group $(resourceGroupName)
189214
215+
# FIXME: Health endpoints disabled till they can be audited: "https://$(stagingHost)/health", "https://$(stagingHost)/health/alive"
190216
- pwsh: |
191217
Start-Sleep 60
192218
$urls = @(
193-
"https://netsourceindex-$(deploymentSlot).azurewebsites.net",
194-
"https://netsourceindex-$(deploymentSlot).azurewebsites.net/System.Private.CoreLib/src/libraries/System.Private.CoreLib/src/System/String.cs.html"
219+
"https://$(stagingHost)"
220+
"https://$(stagingHost)/System.Private.CoreLib/src/libraries/System.Private.CoreLib/src/System/String.cs.html"
195221
)
196222
foreach ($url in $urls) {
197-
$statusCode = Invoke-WebRequest $url -UseBasicParsing -SkipHttpErrorCheck | select -ExpandProperty StatusCode
198-
if ($statusCode -ne 200) {
199-
Write-Host "##vso[task.logissue type=error;]Deployed website returned undexpected status code $statusCode from url $url"
200-
Write-Host "##vso[task.complete result=Failed;]Deployed website returned undexpected status code $statusCode from url $url"
223+
Write-Host "Testing URL: $url"
224+
try {
225+
$statusCode = Invoke-WebRequest $url -UseBasicParsing -SkipHttpErrorCheck | select -ExpandProperty StatusCode
226+
if ($statusCode -ne 200) {
227+
Write-Error "##vso[task.logissue type=warning;]Deployed staging website returned unexpected status code $statusCode from url $url"
228+
}
229+
} catch {
230+
Write-Error "##vso[task.logissue type=warning;]Failed to test URL $url : $_"
201231
}
202232
}
203-
displayName: Test Deployed WebApp
233+
displayName: 🟣Test Deployed WebApp
234+
condition: and(succeeded(), eq(variables['isOfficialBuild'], 'True'))
204235
205236
- task: AzureCLI@2
206-
displayName: Swap Staging Slot into Production
237+
displayName: 🟣Swap Staging Slot into Production
207238
condition: and(succeeded(), eq(variables['isOfficialBuild'], 'True'))
208239
inputs:
209-
azureSubscription: SourceDotNet-Deployment-ARM
240+
azureSubscription: ${{ variables.azureSubscriptionForStorageAndWebAppSlot }}
210241
scriptLocation: inlineScript
211242
scriptType: ps
212243
inlineScript: >
213244
az webapp deployment slot swap
214-
--resource-group source.dot.net
215-
--name netsourceindex
216-
--slot staging
245+
--resource-group $(resourceGroupName)
246+
--name $(webAppName)
247+
--slot $(temporaryDeploymentSlot)
217248
--target-slot production
218249
219250
- task: AzureCLI@2
220-
displayName: Cleanup Old Storage Containers
251+
displayName: 🟣Cleanup Old Storage Containers
221252
condition: and(succeeded(), eq(variables['isOfficialBuild'], 'True'))
222253
inputs:
223-
azureSubscription: SourceDotNet-Deployment-ARM
254+
azureSubscription: ${{ variables.azureSubscriptionForStorageAndWebAppSlot }}
224255
scriptLocation: inlineScript
225256
scriptType: ps
226257
inlineScript: >
227258
deployment/cleanup-old-containers.ps1
228-
-ResourceGroup source.dot.net
229-
-WebappName netsourceindex
230-
-StorageAccountName $(storageAccount)
259+
-ResourceGroup $(resourceGroupName)
260+
-WebappName $(webAppName)
261+
-StorageAccountName $(storageAccountName)
231262
232263
- task: CopyFiles@2
233264
displayName: Copy binlogs for upload

deployment/cleanup-old-containers.ps1

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ $allContainers = New-Object System.Collections.Generic.HashSet[string]
1515

1616
Write-Host "Finding containers..."
1717
{
18-
az storage container list --account-name netsourceindex --auth-mode login --query '[*].name' | ConvertFrom-Json | Write-Output | %{
18+
az storage container list --account-name $StorageAccountName --auth-mode login --query '[*].name' | ConvertFrom-Json | Write-Output | %{
1919
$allContainers.Add($_)
2020
} | Out-Null
2121
} | Check-Failure
@@ -60,7 +60,7 @@ $toDelete = New-Object System.Collections.Generic.HashSet[string] -ArgumentList
6060
$usedContainers | %{
6161
if (-not $toDelete.Remove($_))
6262
{
63-
throw "Used container $_ not found, aborting."
63+
Write-Warning "Used container $_ not found, ignoring"
6464
}
6565
}
6666

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
param(
2-
[string]$ProxyUrlFile,
2+
[string]$NewContainerName,
33
[string]$ResourceGroup,
4+
[string]$StorageAccountName,
45
[string]$WebappName,
56
[string]$Slot
67
)
@@ -10,8 +11,27 @@ param(
1011
$ErrorActionPreference = "Stop"
1112
Import-Module $PSScriptRoot/util.ps1
1213

13-
$proxyUrl = Get-Content -Raw $ProxyUrlFile
14+
# validate arguments
15+
if ([string]::IsNullOrEmpty($NewContainerName)) {
16+
throw "NewContainerName is null or empty"
17+
}
18+
if ([string]::IsNullOrEmpty($ResourceGroup)) {
19+
throw "ResourceGroup is null or empty"
20+
}
21+
if ([string]::IsNullOrEmpty($StorageAccountName)) {
22+
throw "StorageAccountName is null or empty"
23+
}
24+
if ([string]::IsNullOrEmpty($WebappName)) {
25+
throw "WebappName is null or empty"
26+
}
27+
if ([string]::IsNullOrEmpty($Slot)) {
28+
throw "Slot is null or empty"
29+
}
30+
31+
$proxyUrl = "https://$StorageAccountName.blob.core.windows.net/$NewContainerName"
32+
33+
Write-Host "Setting SOURCE_BROWSER_INDEX_PROXY_URL to: '$proxyUrl'"
1434

1535
{
1636
az webapp config appsettings set --resource-group $ResourceGroup --name $WebappName --slot $Slot --settings "SOURCE_BROWSER_INDEX_PROXY_URL=$proxyUrl"
17-
} | Check-Failure
37+
} | Check-Failure

deployment/upload-index-to-container.ps1

Lines changed: 0 additions & 18 deletions
This file was deleted.

0 commit comments

Comments
 (0)