-
Notifications
You must be signed in to change notification settings - Fork 14
/
Copy pathazure-pipelines.yml
487 lines (441 loc) · 17.5 KB
/
azure-pipelines.yml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
# CI/CD Azure DevOps deployment pipeline.
# The following variables can be optionally set for each pipeline run:
# - RUN_FLAG_TERRAFORM: Set to 1 to have `terraform apply`. By default
# `terraform apply` only runs on the main branch.
# - RUN_FLAG_PROMOTE: Set to 1 to promote the Docker image to `<supported_kibana_version>_latest` tag if
# tests are successful. By default this is only done on the main branch.
# - RUN_SET_NAMESPACE: Set to a string to deploy to the given AKS namespace,
# and not delete the namespace after the build. By default the build deploys to
# the `main` AKS namespace if run on the main branch, and otherwise to a
# temporary AKS namespace that is deleted at the end of the build.
# - RUN_CREATE_DEMO_KUSTO: Set to 1 to cause the ADX db creation. this is for
# just for the demo ADX db and should be set only once after a deletion of
# that DB (which shouldn't normally happen)
stages:
- stage: build
displayName: Build
jobs:
- job: security_analysis
displayName: Security Analysis
condition: not(variables['IS_DEMO_PIPELINE'])
pool:
# CredScan only runs on Windows
vmImage: 'windows-latest'
steps:
- task: CredScan@2
displayName: 'Find credentials in source code'
inputs:
toolMajorVersion: 'V2'
- task: SdtReport@1
displayName: 'Security analysis report'
inputs:
AllTools: false
APIScan: false
BinSkim: false
CodesignValidation: false
CredScan: true
FortifySCA: false
FxCop: false
ModernCop: false
MSRD: false
PoliCheck: false
RoslynAnalyzers: false
SDLNativeRules: false
Semmle: false
TSLint: false
ToolLogsNotFoundAction: 'Standard'
- task: PublishSecurityAnalysisLogs@2
displayName: 'Publish security analysis logs'
inputs:
ArtifactName: 'CodeAnalysisLogs'
ArtifactType: 'Container'
AllTools: false
AntiMalware: false
APIScan: false
BinSkim: false
CodesignValidation: false
CredScan: true
FortifySCA: false
FxCop: false
ModernCop: false
MSRD: false
PoliCheck: false
RoslynAnalyzers: false
SDLNativeRules: false
Semmle: false
TSLint: false
WebScout: false
ToolLogsNotFoundAction: 'Standard'
- task: PostAnalysis@1
displayName: 'Post security analysis'
inputs:
AllTools: false
APIScan: false
BinSkim: false
CodesignValidation: false
CredScan: true
FortifySCA: false
FxCop: false
ModernCop: false
PoliCheck: false
RoslynAnalyzers: false
SDLNativeRules: false
Semmle: false
TSLint: false
VstsConsole: false
ToolLogsNotFoundAction: 'Standard'
- task: ComponentGovernanceComponentDetection@0
inputs:
scanType: 'Register'
verbosity: 'Verbose'
alertWarningLevel: 'Medium'
failOnAlert: true
- job: build_and_unittest
displayName: Build with UnitTests
condition: not(variables['IS_DEMO_PIPELINE'])
steps:
- bash: |
set -eux # fail on error
# Only build first stage of Dockerfile (build and unit test)
docker build --target build --build-arg VersionPrefix="$(SEMANTIC_VERSION)" -t k2bridge-build .
# Temporarily create container in order to extract test results file
id=$(docker create k2bridge-build)
docker cp $id:/app/TestResult.xml .
docker cp $id:/app/K2Bridge.Tests.UnitTests/coverage.cobertura.xml .
docker rm $id
displayName: Docker build & test
- task: PublishTestResults@2
displayName: Publish test results
condition: succeededOrFailed()
inputs:
testRunner: VSTest
testResultsFiles: 'TestResult.xml'
failTaskOnFailedTests: true
testRunTitle: 'Unit Tests'
# Publish the code coverage result (summary and web site)
# The summary allows to view the coverage percentage in the summary tab
# The web site allows to view which lines are covered directly in Azure Pipeline
- task: PublishCodeCoverageResults@1
displayName: 'Publish code coverage'
inputs:
codeCoverageTool: 'Cobertura'
summaryFileLocation: 'coverage.cobertura.xml'
pathToSources: '$(Build.SourcesDirectory)/K2Bridge/'
failIfCoverageEmpty: true
- task: AzureCLI@1
displayName: Login to ACR
inputs:
azureSubscription: $(ACR_PUSH_SERVICE_CONNECTION)
scriptLocation: inlineScript
inlineScript: |
set -eux # fail on error
az configure --defaults acr="$ACR_NAME"
az acr login
- bash: |
set -eux # fail on error
# Build runtime Docker image
# Reuses the cached build stage from the previous docker build task
docker build --build-arg VersionPrefix="$SEMANTIC_VERSION" \
-t "$ACR_NAME.azurecr.io/k2bridge:$SEMANTIC_VERSION" \
.
displayName: Build Runtime Image
- bash: |
set -eux # fail on error
# Build e2e-test Docker image
docker build --target end2endtest \
--build-arg VersionPrefix="$SEMANTIC_VERSION" \
-t "$ACR_NAME.azurecr.io/k2bridge-test:$SEMANTIC_VERSION" \
.
displayName: Build E2E-Test Image
- task: AzureCLI@1
displayName: Push Images
inputs:
azureSubscription: $(ACR_PUSH_SERVICE_CONNECTION)
scriptLocation: inlineScript
inlineScript: |
set -eux # fail on error
# Push Docker image
docker push "$ACR_NAME.azurecr.io/k2bridge:$SEMANTIC_VERSION"
docker push "$ACR_NAME.azurecr.io/k2bridge-test:$SEMANTIC_VERSION"
- job: push_helm_charts
displayName: Prepare and push helm charts
steps:
- task: AzureCLI@1
displayName: Login to ACR
inputs:
azureSubscription: $(ACR_PUSH_SERVICE_CONNECTION)
scriptLocation: inlineScript
inlineScript: |
set -eux # fail on error
az configure --defaults acr="$ACR_NAME"
az acr login
- task: HelmInstaller@1
displayName: Helm installer
inputs:
helmVersionToInstall: $(HELM_VERSION)
- task: AzureCLI@1
displayName: Push Helm Charts to ACR
inputs:
azureSubscription: $(ACR_PUSH_SERVICE_CONNECTION)
scriptLocation: inlineScript
inlineScript: |
# Push Helm chart
helm repo add elastic https://helm.elastic.co
helm repo update
helm dependency update charts/k2bridge
empty_dir="$(Build.StagingDirectory)/charts_out"
echo $SEMANTIC_VERSION
helm package --version "$SEMANTIC_VERSION" charts/k2bridge -d $empty_dir
az acr helm push --force "$(ls $empty_dir/*)"
- stage: terraform
displayName: Prepare Test Env
dependsOn: []
jobs:
- job: Terraform
steps:
# - task: AzureCLI@1
# inputs:
# azureSubscription: $(ACR_PULL_SERVICE_CONNECTION)
# scriptLocation: inlineScript
# inlineScript: |
# set -eux
# az login --service-principal --username $(AKS_SP_CLIENT_ID) --password "$password" --tenant $(TENANT_ID)
# az aks get-versions --location westeurope
# echo "1 - " $(AKS_SP_CLIENT_ID)
# echo $(az ad sp show --id $(AKS_SP_CLIENT_ID) --query objectId -o tsv 2>&1)
# echo "2 - " $(az ad sp show --id $(AKS_SP_CLIENT_ID) --query objectId 2>&1)
# oid=$(az ad sp show --id $(AKS_SP_CLIENT_ID) --query objectId -o tsv)
# echo "3 - " $(az ad sp show --id 87c08231-4e69-495c-bd3f-02999f44281e 2>&1)
# echo oid=$oid
# echo "4"
# echo "##vso[task.setvariable variable=AKS_SP_OBJECT_ID]$oid"
# displayName: Get AKS SP object ID
# env:
# password: $(AKS_SP_CLIENT_SECRET)
- template: infrastructure/terraform-tasks-template.yml
parameters:
TerraformArguments: >-
-var resource_group=$(RESOURCE_GROUP)
-var vnet_name=$(VNET_NAME)
-var aks_name=$(AKS_NAME)
-var aks_version=$(AKS_VERSION)
-var aks_sp_client_id=$(AKS_SP_CLIENT_ID)
-var aks_sp_object_id=$(AKS_SP_OBJECT_ID)
-var kusto_name=$(KUSTO_NAME)
-var kusto_admin_sp_object_id=$(AKS_SP_OBJECT_ID)
# For additional security, pass secret through environment instead of command line.
# Terraform recognizes TF_VAR prefixed environment variables.
TerraformEnvVariables:
TF_VAR_aks_sp_client_secret: $(AKS_SP_CLIENT_SECRET)
- stage: deploy_solution
displayName: Deploy Solution
dependsOn:
- build
- terraform
condition: or(succeeded(), and(succeeded('terraform'), variables['IS_DEMO_PIPELINE']))
jobs:
- job: Deploy_K2Bridge
displayName: Deploy K2Bridge
variables:
${{ if ne(variables['Build.SourceBranchName'], 'main') }}:
NOT_MAIN_ES_CONFIG: "--set elasticsearch.replicas=2 --set elasticsearch.minimumMasterNodes=2"
steps:
- template: infrastructure/setup-k8s-clients-template.yml
- task: AzureCLI@1
displayName: Login to ACR
inputs:
azureSubscription: $(ACR_PUSH_SERVICE_CONNECTION)
scriptLocation: inlineScript
inlineScript: |
set -eux # fail on error
az configure --defaults acr="$ACR_NAME"
az acr login
- task: AzureCLI@1
displayName: Add Helm repo to ACR
inputs:
azureSubscription: $(ACR_PULL_SERVICE_CONNECTION)
scriptLocation: inlineScript
inlineScript: |
set -eu # fail on error
az acr helm repo add -n "$(ACR_NAME)"
KUSTO_URI=$(az kusto cluster show -g $(RESOURCE_GROUP) -n $(KUSTO_NAME) --query uri -o tsv)
echo "##vso[task.setvariable variable=KUSTO_URI]$KUSTO_URI"
- bash: |
set -eux # fail on error
helm show chart $(ACR_NAME)/k2bridge
# List charts before deploying (for job log, useful if rerunning job)
helm list
# Deploy chart
helm upgrade --install k2bridge $(ACR_NAME)/k2bridge \
--version "$SEMANTIC_VERSION" \
--wait --timeout 30m \
--set image.repository=$(ACR_NAME).azurecr.io/k2bridge \
--set image.tag=$IMAGE_TAG \
--set replicaCount=2 \
--set settings.adxClusterUrl="$KUSTO_URI" \
--set settings.adxDefaultDatabaseName="$(KUSTO_DB)" \
--set settings.aadClientId="$(AKS_SP_CLIENT_ID)" \
--set settings.aadClientSecret="$secret" \
--set settings.aadTenantId="$TENANT_ID" \
--set settings.collectTelemetry="$COLLECT_TELEMETRY" \
--set settings.instrumentationKey="$TELEMETRY_KEY" \
--set settings.enableQueryLogging=true \
${NOT_MAIN_ES_CONFIG:-} #defaults to an empty string
# List charts after deploying (for job log)
helm list
displayName: Install Helm chart
env:
secret: $(AKS_SP_CLIENT_SECRET)
- bash: |
set -eux
kubectl run --attach --rm --restart=Never --image=curlimages/curl smoke-test-$RANDOM -- \
--max-time 5 --retry 99999 --retry-max-time 1200 http://k2bridge:8080
displayName: Smoke test
- stage: integration_tests
displayName: Integration Tests
condition: and(succeeded(), not(variables['IS_DEMO_PIPELINE']))
dependsOn:
- build
- terraform
- deploy_solution
# Deploy a new Kusto db
# Either if the db name is not set to 'demo' which means it is the Dev CI process
# Or it is the Demo CI process AND the RUN_CREATE_DEMO_KUSTO was set
jobs:
- job: Deploy_Kusto
displayName: Provision a new Kusto database
condition: or(and(succeeded(), not(eq(variables['KUSTO_DB'], 'demo'))), and(succeeded(), eq(variables['KUSTO_DB'], 'demo'), variables['RUN_CREATE_DEMO_KUSTO']))
steps:
- task: AzureCLI@1
displayName: Provision Kusto database
inputs:
azureSubscription: $(ACR_PULL_SERVICE_CONNECTION)
scriptLocation: inlineScript
inlineScript: |
set -eux # fail on error
az kusto database create -g "$(RESOURCE_GROUP)" --cluster-name "$(KUSTO_NAME)" -n "$(KUSTO_DB)"
- job: Deploy_Elasticsearch
displayName: Deploy Elasticsearch
steps:
- template: infrastructure/setup-k8s-clients-template.yml
- bash: |
set -eux # fail on error
helm list
helm repo add elastic https://helm.elastic.co
helm upgrade --install elasticsearchqa elastic/elasticsearch \
--wait --timeout 45m \
--set image=docker.elastic.co/elasticsearch/elasticsearch \
--set imageTag=7.16.2 \
--set clusterName=elasticsearchqa \
--set replicas=1 \
--set persistence.enabled=false \
--set minimumMasterNodes=1 \
--set antiAffinity="soft" \
--set esJavaOpts="-Xmx512m -Xms512m" \
--set resources.requests.cpu="100m" \
--set resources.requests.memory="1024M" \
--set limits.cpu="1000m" \
--set limits.memory="2048M" \
--version 7.5.2
displayName: Deploy Elasticsearch
- job: Test
displayName: Run Tests
dependsOn:
- Deploy_Kusto
- Deploy_Elasticsearch
steps:
- template: infrastructure/setup-k8s-clients-template.yml
- task: AzureCLI@1
displayName: End-to-end test
inputs:
azureSubscription: $(ACR_PULL_SERVICE_CONNECTION)
scriptLocation: inlineScript
inlineScript: |
set -eu # fail on error
podName="e2e-test-$RANDOM"
KUSTO_URI=$(az kusto cluster show -g $(RESOURCE_GROUP) -n $(KUSTO_NAME) --query uri -o tsv)
AAD_TOKEN=$(az account get-access-token --resource "$KUSTO_URI" --query accessToken -o tsv)
kubectl run --restart=Never \
--image=$(ACR_NAME).azurecr.io/k2bridge-test:$SEMANTIC_VERSION \
--env=K2BRIDGE_URL=http://k2bridge:8080 \
--env=ELASTICSEARCH_URL=http://elasticsearchqa-master:9200 \
--env=KUSTO_URI=$KUSTO_URI \
--env=KUSTO_DB=$(KUSTO_DB) \
--env=AAD_TOKEN=$AAD_TOKEN \
"$podName"
set -x # enable verbose mode, without exposing $AAD_TOKEN
kubectl wait --timeout 45m --for=condition=ContainersReady pod "$podName"
# Read test output from FIFO within container
kubectl exec "$podName" cat /test-result-pipe > TestResult.xml
kubectl delete pod "$podName"
- task: PublishTestResults@2
displayName: Publish test results
condition: succeededOrFailed()
inputs:
testRunner: VSTest
testResultsFiles: 'TestResult.xml'
failTaskOnFailedTests: true
testRunTitle: 'E2E Tests'
- stage: cleanup_integration_tests
displayName: Cleanup Tests
dependsOn: integration_tests
# Do not delete AKS namespace:
# - if pipeline was canceled or failed before a Kubernetes namespace was generated
# - if deploying on main branch
# - if namespace was manually set with RUN_SET_NAMESPACE
condition: and(not(variables['RUN_SET_NAMESPACE']), not(variables['IS_DEMO_PIPELINE']))
jobs:
- job: Cleanup
steps:
- template: infrastructure/setup-k8s-clients-template.yml
- task: AzureCLI@1
displayName: Delete AKS namespace and Kusto database
condition: and(variables['KUBERNETES_NAMESPACE'], not(eq(variables['KUBERNETES_NAMESPACE'], 'main')))
inputs:
azureSubscription: $(ACR_PULL_SERVICE_CONNECTION)
scriptLocation: inlineScript
inlineScript: |
set -eux # fail on error
kubectl delete namespace "$KUBERNETES_NAMESPACE"
az kusto database delete -g "$(RESOURCE_GROUP)" --cluster-name "$(KUSTO_NAME)" -n "$(KUSTO_DB)" -y
- stage: release
displayName: Release Artifacts
condition: not(variables['IS_DEMO_PIPELINE'])
dependsOn: integration_tests
jobs:
- job: Promote
displayName: Promote Latest Image
condition: and(succeeded(), or(eq(variables['Build.SourceBranch'], 'refs/heads/main'), eq(variables['Build.SourceBranch'], 'refs/heads/kibana6.8'), variables['RUN_FLAG_PROMOTE']))
steps:
- task: AzureCLI@1
displayName: Tag Docker image as $(K2_TAG)
inputs:
azureSubscription: $(ACR_PUSH_SERVICE_CONNECTION)
scriptLocation: inlineScript
inlineScript: |
set -eux # fail on error
az configure --defaults acr="$ACR_NAME"
az acr login
docker pull "$ACR_NAME.azurecr.io/k2bridge:$SEMANTIC_VERSION"
docker tag \
"$ACR_NAME.azurecr.io/k2bridge:$SEMANTIC_VERSION" \
"$ACR_NAME.azurecr.io/k2bridge:$K2_TAG"
docker push "$ACR_NAME.azurecr.io/k2bridge:$K2_TAG"
- task: AzureCLI@1
displayName: Tag Docker image as $(K2_TAG) for MCR
inputs:
azureSubscription: $(ACR_PUSH_SERVICE_CONNECTION)
scriptLocation: inlineScript
inlineScript: |
set -eux # fail on error
az configure --defaults acr="$ACR_MCR_NAME"
az acr login
docker pull "$ACR_NAME.azurecr.io/k2bridge:$SEMANTIC_VERSION"
docker tag \
"$ACR_NAME.azurecr.io/k2bridge:$SEMANTIC_VERSION" \
"$ACR_MCR_NAME.azurecr.io/public/azuredataexplorer/k2bridge:$K2_TAG"
docker push "$ACR_MCR_NAME.azurecr.io/public/azuredataexplorer/k2bridge:$K2_TAG"
docker tag \
"$ACR_NAME.azurecr.io/k2bridge:$SEMANTIC_VERSION" \
"$ACR_MCR_NAME.azurecr.io/public/azuredataexplorer/k2bridge:$SEMANTIC_VERSION"
docker push "$ACR_MCR_NAME.azurecr.io/public/azuredataexplorer/k2bridge:$SEMANTIC_VERSION"