зеркало из https://github.com/microsoft/K2Bridge.git
488 строки
18 KiB
YAML
488 строки
18 KiB
YAML
# 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"
|