twas-nd CICD #47
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Copyright (c) IBM Corporation. | |
# Copyright (c) Microsoft Corporation. | |
name: twas-nd CICD | |
# Controls when the action will run. | |
on: | |
# Allows you to run this workflow manually from the Actions tab | |
workflow_dispatch: | |
inputs: | |
imageVersionNumber: | |
description: 'Provide image version number' | |
required: false | |
# Allows you to run this workflow using GitHub APIs | |
# PERSONAL_ACCESS_TOKEN=<GITHUB_PERSONAL_ACCESS_TOKEN> | |
# REPO_NAME=WASdev/azure.websphere-traditional.image | |
# curl --verbose -X POST -u "WASdev:${PERSONAL_ACCESS_TOKEN}" -H "Accept: application/vnd.github.everest-preview+json" -H "Content-Type: application/json" https://api.github.com/repos/${REPO_NAME}/actions/workflows/twas-ndBuild.yml/dispatches --data '{"ref": "main", "inputs": {"imageVersionNumber": "9.0.20230428"}}' | |
repository_dispatch: | |
types: [integration-test-twasnd, integration-test-all] | |
# sample request | |
# PERSONAL_ACCESS_TOKEN=<GITHUB_PERSONAL_ACCESS_TOKEN> | |
# REPO_NAME=WASdev/azure.websphere-traditional.image | |
# curl --verbose -X POST https://api.github.com/repos/${REPO_NAME}/dispatches -H "Accept: application/vnd.github.everest-preview+json" -H "Authorization: token ${PERSONAL_ACCESS_TOKEN}" --data '{"event_type": "integration-test-twasnd", "client_payload": {"imageVersionNumber": "9.0.20230428"}}' | |
# The integration-test-all event is used to run all integration tests (twas-base, twas-nd & ihs) in the repository with the same image version number. | |
# curl --verbose -X POST https://api.github.com/repos/${REPO_NAME}/dispatches -H "Accept: application/vnd.github.everest-preview+json" -H "Authorization: token ${PERSONAL_ACCESS_TOKEN}" --data '{"event_type": "integration-test-all", "client_payload": {"imageVersionNumber": "9.0.20230428"}}' | |
env: | |
repoName: azure.websphere-traditional.image | |
userName: ${{ secrets.USER_NAME }} | |
azureCredentials: ${{ secrets.AZURE_CREDENTIALS }} | |
entitledIbmUserId: ${{ secrets.ENTITLED_IBM_USER_ID }} | |
entitledIbmPassword: ${{ secrets.ENTITLED_IBM_USER_PWD }} | |
unEntitledIbmUserId: ${{ secrets.UNENTITLED_IBM_USER_ID }} | |
unEntitledIbmPassword: ${{ secrets.UNENTITLED_IBM_USER_PWD }} | |
vmAdminId: ${{ secrets.VM_ADMIN_ID }} | |
vmAdminPassword: ${{ secrets.VM_ADMIN_PASSWORD }} | |
testResourceGroup: imageTest-${{ github.repository_owner }}-${{ github.run_id }}-${{ github.run_number }}-twasND | |
vmName: vm-${{ github.run_id }}-${{ github.run_number }} | |
vhdStorageAccountName: storage${{ github.run_id }}${{ github.run_number }} | |
location: eastus | |
scriptLocation: https://raw.githubusercontent.com/${{ secrets.USER_NAME }}/azure.websphere-traditional.image/$GITHUB_REF_NAME/twas-nd/test/ | |
utilitiesLocation: https://raw.githubusercontent.com/${{ secrets.USER_NAME }}/azure.websphere-traditional.image/$GITHUB_REF_NAME/utilities/ | |
accessToken: ${{ secrets.PERSONAL_ACCESS_TOKEN }} | |
twasClusterRepo: ${{ secrets.USER_NAME }}/azure.websphere-traditional.cluster | |
offerId: "2023-03-27-twas-cluster-base-image" | |
planId: "2023-03-27-twas-cluster-base-image" | |
offerType: "vm_image_offer" | |
clientId: ${{ secrets.CLIENT_ID }} | |
secretValue: ${{ secrets.SECRET_VALUE }} | |
tenantId: ${{ secrets.TENANT_ID }} | |
imageType: "x64Gen1" | |
operatingSystemFamily: "linux" | |
operatingSystemType: "redHat" | |
# A workflow run is made up of one or more jobs that can run sequentially or in parallel | |
jobs: | |
build: | |
# The type of runner that the job will run on | |
runs-on: ubuntu-latest | |
outputs: | |
imageVersionNumber: ${{ steps.setup-env-variables-based-on-dispatch-event.outputs.imageVersionNumber }} | |
# Steps represent a sequence of tasks that will be executed as part of the job | |
steps: | |
- name: Get versions of external dependencies | |
run: | | |
curl -Lo external-deps-versions.properties https://raw.githubusercontent.com/Azure/azure-javaee-iaas/main/external-deps-versions.properties | |
source external-deps-versions.properties | |
echo "azCliVersion=${AZ_CLI_VERSION}" >> $GITHUB_ENV | |
echo "refArmttk=${ARM_TTK_REFERENCE}" >> $GITHUB_ENV | |
echo "refJavaee=${AZURE_JAVAEE_IAAS_REFERENCE}" >> $GITHUB_ENV | |
- name: Setup environment variables | |
id: setup-env-variables-based-on-dispatch-event | |
run: | | |
if [ ${{ github.event_name }} == 'workflow_dispatch' ]; then | |
imageVersionNumber=${{ github.event.inputs.imageVersionNumber }} | |
else | |
imageVersionNumber=${{ github.event.client_payload.imageVersionNumber }} | |
fi | |
echo "##[set-output name=imageVersionNumber;]${imageVersionNumber}" | |
- name: Set up JDK 11 | |
uses: actions/setup-java@v2 | |
with: | |
distribution: 'microsoft' | |
java-version: '11' | |
- name: Checkout azure-javaee-iaas | |
uses: actions/checkout@v3 | |
with: | |
repository: Azure/azure-javaee-iaas | |
path: azure-javaee-iaas | |
ref: ${{ env.refJavaee }} | |
- name: Checkout arm-ttk | |
uses: actions/checkout@v3 | |
with: | |
repository: Azure/arm-ttk | |
path: arm-ttk | |
ref: ${{ env.refArmttk }} | |
- name: Checkout ${{ env.repoName }} | |
uses: actions/checkout@v3 | |
with: | |
path: ${{ env.repoName }} | |
ref: ${{ github.event.inputs.ref }} | |
- name: Build azure-javaee-iaas | |
run: mvn -DskipTests clean install --file azure-javaee-iaas/pom.xml | |
- name: Azure login | |
uses: azure/login@v1 | |
with: | |
creds: ${{ env.azureCredentials }} | |
- name: Build ${{ env.repoName }} | |
run: | | |
echo "Branch name is $GITHUB_REF_NAME" | |
mvn -Dgit.repo=${{ env.userName }} -Dgit.tag=$GITHUB_REF_NAME \ | |
-DibmUserId=${{ env.entitledIbmUserId }} -DibmUserPwd=${{ env.entitledIbmPassword }} \ | |
-DstorageAccount=${{ env.vhdStorageAccountName }} -DvmName=${{ env.vmName }} \ | |
-DvmAdminId=${{ env.vmAdminId }} -DvmAdminPwd=${{ env.vmAdminPassword }} \ | |
-Dtest.args="-Test All" -Ptemplate-validation-tests -Dtemplate.validation.tests.directory=../../arm-ttk/arm-ttk \ | |
clean install --file ${{ env.repoName }}/twas-nd/pom.xml | |
- name: Deploy a RHEL 9.x VM and install twas ND server | |
run: | | |
cd ${{ env.repoName }}/twas-nd/target/cli | |
chmod a+x deploy.azcli | |
./deploy.azcli -n testDeployment -g ${{ env.testResourceGroup }} -l ${{ env.location }} | |
- name: Query public IP of VM | |
uses: azure/CLI@v1 | |
with: | |
azcliversion: ${{ env.azCliVersion }} | |
inlineScript: | | |
echo "query public ip" | |
publicIP=$(az vm show \ | |
--resource-group ${{ env.testResourceGroup }} \ | |
--name ${{ env.vmName }} -d \ | |
--query publicIps -o tsv) | |
echo "publicIP=${publicIP}" >> $GITHUB_ENV | |
- name: Output installation log | |
run: | | |
sudo apt-get install -y sshpass | |
timeout 1m sh -c 'until nc -zv $0 $1; do echo "nc rc: $?"; sleep 5; done' ${publicIP} 22 | |
echo "Output stdout:" | |
result=$(sshpass -p ${{ env.vmAdminPassword }} -v ssh -p 22 -o StrictHostKeyChecking=no -o TCPKeepAlive=yes -o ServerAliveCountMax=20 -o ServerAliveInterval=15 -o ConnectTimeout=100 -v -tt ${{ env.vmAdminId }}@${publicIP} 'echo "${{ env.vmAdminPassword }}" | sudo -S cat /var/lib/waagent/custom-script/download/0/stdout') | |
echo "$result" | |
- name: Update the packages | |
run: | | |
sudo apt-get install -y sshpass | |
timeout 1m sh -c 'until nc -zv $0 $1; do echo "nc rc: $?"; sleep 5; done' ${publicIP} 22 | |
sshpass -p ${{ env.vmAdminPassword }} -v ssh -p 22 -o StrictHostKeyChecking=no -o TCPKeepAlive=yes -o ServerAliveCountMax=20 -o ServerAliveInterval=15 -o ConnectTimeout=100 -v -tt ${{ env.vmAdminId }}@${publicIP} 'echo "${{ env.vmAdminPassword }}" | sudo -S yum update -y' | |
- name: Harden the VM using OpenSCAP tool | |
run: | | |
az vm extension set --name CustomScript \ | |
--extension-instance-name apply-oscap-rules \ | |
--resource-group ${{ env.testResourceGroup }} --vm-name ${{ env.vmName }} \ | |
--publisher Microsoft.Azure.Extensions --version 2.0 \ | |
--settings "{\"fileUris\": [\"${{ env.utilitiesLocation }}oscap.sh\"]}" \ | |
--protected-settings "{\"commandToExecute\":\"bash oscap.sh ${{ env.vmAdminId }}\"}" | |
- name: Copy openscap scanning reports | |
run: | | |
sudo apt-get install -y sshpass | |
timeout 1m sh -c 'until nc -zv $0 $1; do echo "nc rc: $?"; sleep 5; done' ${publicIP} 22 | |
sshpass -p ${vmAdminPassword} scp ${vmAdminId}@${publicIP}:/home/${vmAdminId}/scan_report_* . | |
- name: Upload openscap scanning report before remidation | |
uses: actions/upload-artifact@v3 | |
with: | |
name: scan-report-before | |
path: scan_report_before.html | |
- name: Upload openscap scanning report after remidation | |
uses: actions/upload-artifact@v3 | |
with: | |
name: scan-report-after | |
path: scan_report_after.html | |
- name: Deprovision the VM | |
run: | | |
sudo apt-get install -y sshpass | |
timeout 1m sh -c 'until nc -zv $0 $1; do echo "nc rc: $?"; sleep 5; done' ${publicIP} 22 | |
sshpass -p ${{ env.vmAdminPassword }} -v ssh -p 22 -o StrictHostKeyChecking=no -o TCPKeepAlive=yes -o ServerAliveCountMax=20 -o ServerAliveInterval=15 -o ConnectTimeout=100 -v -tt ${{ env.vmAdminId }}@${publicIP} 'echo "${{ env.vmAdminPassword }}" | sudo -S waagent -deprovision+user -force' | |
- name: Generate the image | |
run: | | |
az vm deallocate --resource-group ${{ env.testResourceGroup }} --name ${{ env.vmName }} | |
az vm generalize --resource-group ${{ env.testResourceGroup }} --name ${{ env.vmName }} | |
az image create --resource-group ${{ env.testResourceGroup }} --name ${{ env.vmName }} --source ${{ env.vmName }} | |
verify_the_image: | |
needs: build | |
runs-on: ubuntu-latest | |
steps: | |
- name: Checkout ${{ env.repoName }} | |
uses: actions/checkout@v3 | |
with: | |
path: ${{ env.repoName }} | |
ref: ${{ github.event.inputs.ref }} | |
- name: Azure login | |
uses: azure/login@v1 | |
with: | |
creds: ${{ env.azureCredentials }} | |
- name: Verify the image | |
run: | | |
imageResourceId=$(az image show --name ${{ env.vmName }} --resource-group ${{ env.testResourceGroup }} --query id -o tsv) | |
echo "ndImageResourceId=${imageResourceId}" >> $GITHUB_ENV | |
echo "ihsImageResourceId=" >> $GITHUB_ENV | |
# Deploy VMs using different IBMids and verify installation | |
vmGroups=( ${{ env.testResourceGroup }}-entitled ${{ env.testResourceGroup }}-unentitled ${{ env.testResourceGroup }}-evaluation ) | |
deploymentModes=( Entitled Unentitled Evaluation ) | |
ibmUserIds=( ${{ env.entitledIbmUserId }} ${{ env.unEntitledIbmUserId }} "" ) | |
ibmUserPwds=( ${{ env.entitledIbmPassword }} ${{ env.unEntitledIbmPassword }} "" ) | |
for (( i=0; i<${#vmGroups[@]}; i++ )); do | |
rgName=${vmGroups[$i]} | |
az group create -n $rgName -l ${{ env.location }} | |
az deployment group create --resource-group $rgName --name testDeployment \ | |
--template-file ${{ env.repoName }}/utilities/verifyTemplate.json \ | |
--parameters deploymentMode=${deploymentModes[$i]} ibmUserId=${ibmUserIds[$i]} ibmUserPwd=${ibmUserPwds[$i]} \ | |
imageResourceId=$imageResourceId vmAdminId=${{ env.vmAdminId }} vmAdminPwd=${{ env.vmAdminPassword }} \ | |
scriptLocation=${{ env.scriptLocation }} | |
az group delete -n $rgName --yes --no-wait | |
done | |
- name: Verify the image with twas-cluster integration-test pipeline | |
run: | | |
# Trigger the workflow run | |
requestData={\"ref\":\"${GITHUB_REF_NAME}\",\"inputs\":{\"databaseType\":\"none\",\"ndImageResourceId\":\"${ndImageResourceId}\",\"ihsImageResourceId\":\"${ihsImageResourceId}\"}} | |
curl --verbose -L -X POST \ | |
-H "Accept: application/vnd.github+json" \ | |
-H "Authorization: Bearer ${accessToken}"\ | |
-H "X-GitHub-Api-Version: 2022-11-28" \ | |
https://api.github.com/repos/${{ env.twasClusterRepo }}/actions/workflows/integration-test.yaml/dispatches \ | |
-d $(echo $requestData | jq -c) | |
# Wait until the workflow run starts | |
idAndStatus=$(curl -L \ | |
-H "Accept: application/vnd.github+json" \ | |
-H "Authorization: Bearer ${accessToken}"\ | |
-H "X-GitHub-Api-Version: 2022-11-28" \ | |
https://api.github.com/repos/${{ env.twasClusterRepo }}/actions/workflows/integration-test.yaml/runs \ | |
| jq -r '.workflow_runs[0] | {id, status}') | |
status=$(echo $idAndStatus | jq -r '.status') | |
while [[ $status != queued ]] | |
do | |
echo "Wait until the workflow run starts..." | |
idAndStatus=$(curl -L \ | |
-H "Accept: application/vnd.github+json" \ | |
-H "Authorization: Bearer ${accessToken}"\ | |
-H "X-GitHub-Api-Version: 2022-11-28" \ | |
https://api.github.com/repos/${{ env.twasClusterRepo }}/actions/workflows/integration-test.yaml/runs \ | |
| jq -r '.workflow_runs[0] | {id, status}') | |
status=$(echo $idAndStatus | jq -r '.status') | |
echo "The latest workflow run is ${idAndStatus}" | |
done | |
workflowRunId=$(echo $idAndStatus | jq '.id') | |
# Wait until the workflow run completes | |
status=$(curl -L \ | |
-H "Accept: application/vnd.github+json" \ | |
-H "Authorization: Bearer ${accessToken}"\ | |
-H "X-GitHub-Api-Version: 2022-11-28" \ | |
https://api.github.com/repos/${{ env.twasClusterRepo }}/actions/runs/$workflowRunId \ | |
| jq -r '.status') | |
while [[ $status != completed ]] | |
do | |
sleep 60 | |
echo "Wait until the workflow run ${workflowRunId} completes..." | |
status=$(curl -L \ | |
-H "Accept: application/vnd.github+json" \ | |
-H "Authorization: Bearer ${accessToken}"\ | |
-H "X-GitHub-Api-Version: 2022-11-28" \ | |
https://api.github.com/repos/${{ env.twasClusterRepo }}/actions/runs/$workflowRunId \ | |
| jq -r '.status') | |
echo "Workflow run ${workflowRunId} is ${status}" | |
done | |
# Verify the workflow run result | |
jobs=$(curl -L \ | |
-H "Accept: application/vnd.github+json" \ | |
-H "Authorization: Bearer ${accessToken}"\ | |
-H "X-GitHub-Api-Version: 2022-11-28" \ | |
https://api.github.com/repos/${{ env.twasClusterRepo }}/actions/runs/$workflowRunId/jobs) | |
successIntegTestJobCnt=$(echo $jobs | jq 'select(.jobs != null) | .jobs | map(select(.name=="integration-test" and .conclusion=="success")) | length') | |
if [[ $successIntegTestJobCnt != 1 ]]; then | |
echo "twas-cluster integration test workflow run ${workflowRunId} failed." | |
exit 1 | |
else | |
echo "twas-cluster integration test workflow run ${workflowRunId} succeeded." | |
fi | |
update_sas_url: | |
needs: [ build, verify_the_image ] | |
runs-on: ubuntu-latest | |
steps: | |
- name: Azure login | |
uses: azure/login@v1 | |
with: | |
creds: ${{ env.azureCredentials }} | |
- name: Generate SAS url | |
id: sas_url | |
run: | | |
# Get a minus-24-hour date and a plus-30-day date for the SAS token | |
minus24HoursUtc=$(date -u --date "$dte -24 hour" +%Y-%m-%dT%H:%MZ) | |
plus30DaysUtc=$(date -u --date "$dte 30 day" +%Y-%m-%dT%H:%MZ) | |
vhdStorageAccountAccessKey=$(az storage account keys list --account-name ${{ env.vhdStorageAccountName }} --query "[?keyName=='key1'].value" -o tsv) | |
sasToken=$(az storage container generate-sas \ | |
--connection-string "DefaultEndpointsProtocol=https;AccountName=${{ env.vhdStorageAccountName }};AccountKey=${vhdStorageAccountAccessKey};EndpointSuffix=core.windows.net" \ | |
--name vhds --permissions rl --start "${minus24HoursUtc}" --expiry "${plus30DaysUtc}" -o tsv) | |
blobStorageEndpoint=$( az storage account show -n ${{ env.vhdStorageAccountName }} -g ${{ env.testResourceGroup }} -o json | jq -r '.primaryEndpoints.blob' ) | |
osDiskSasUrl=${blobStorageEndpoint}vhds/${{ env.vmName }}.vhd?$sasToken | |
dataDiskSasUrl=${blobStorageEndpoint}vhds/${{ env.vmName }}datadisk1.vhd?$sasToken | |
echo "osDiskSasUrl: ${osDiskSasUrl}, dataDiskSasUrl: ${dataDiskSasUrl}" > sas-url-twasnd.txt | |
echo "##[set-output name=osDiskSasUrl;]${osDiskSasUrl}" | |
echo "##[set-output name=dataDiskSasUrl;]${dataDiskSasUrl}" | |
- name: Upload SAS url | |
uses: actions/upload-artifact@v3 | |
with: | |
name: sasurl-twasnd | |
path: sas-url-twasnd.txt | |
- name: Update offer sas url and version | |
uses: microsoft/[email protected] | |
if: ${{ needs.build.outputs.imageVersionNumber != '' }} | |
with: | |
offerId: ${{ env.offerId }} | |
planId: ${{ env.planId }} | |
offerType: ${{ env.offerType }} | |
clientId: ${{ env.clientId }} | |
tenantId: ${{ env.tenantId }} | |
secretValue: ${{ env.secretValue }} | |
imageType: ${{ env.imageType }} | |
imageVersionNumber: ${{ needs.build.outputs.imageVersionNumber }} | |
operatingSystemFamily: ${{ env.operatingSystemFamily }} | |
operatingSystemType: ${{ env.operatingSystemType }} | |
osDiskSasUrl: ${{steps.sas_url.outputs.osDiskSasUrl}} | |
dataDiskSasUrl: ${{steps.sas_url.outputs.dataDiskSasUrl}} | |
verbose: "false" | |
summary: | |
needs: [build, verify_the_image, update_sas_url] | |
runs-on: ubuntu-latest | |
steps: | |
- name: Output inputs from workflow_dispatch | |
run: echo "${{ toJSON(github.event.inputs) }}" | |
- name: Output client_payload from repository_dispatch | |
run: echo "${{ toJSON(github.event.client_payload) }}" | |
delete_resource: | |
needs: [ build, verify_the_image, update_sas_url,summary ] | |
runs-on: ubuntu-latest | |
if: always() | |
steps: | |
- name: Azure login | |
uses: azure/login@v1 | |
with: | |
creds: ${{ env.azureCredentials }} | |
- name: Clean up all resources except for vhd storage account | |
continue-on-error: true | |
run: | | |
az image delete --ids \ | |
$(az image show -g ${{ env.testResourceGroup }} -n ${{ env.vmName }} --query id -o tsv) | |
az vm delete --yes --ids \ | |
$(az vm show -g ${{ env.testResourceGroup }} -n ${{ env.vmName }} --query id -o tsv) | |
az network nic delete --ids \ | |
$(az network nic list -g ${{ env.testResourceGroup }} --query [0].id -o tsv) | |
az network vnet delete --ids \ | |
$(az network vnet list -g ${{ env.testResourceGroup }} --query [0].id -o tsv) | |
az network public-ip delete --ids \ | |
$(az network public-ip list -g ${{ env.testResourceGroup }} --query [0].id -o tsv) | |
az network nsg delete --ids \ | |
$(az network nsg list -g ${{ env.testResourceGroup }} --query [0].id -o tsv) | |
- name: Delete resource groups during verification | |
continue-on-error: true | |
run: | | |
vmGroups=( ${{ env.testResourceGroup }}-entitled ${{ env.testResourceGroup }}-unentitled ${{ env.testResourceGroup }}-evaluation ) | |
for (( i=0; i<${#vmGroups[@]}; i++ )); do | |
rgName=${vmGroups[$i]} | |
if $(az group exists --name $rgName); then | |
echo "Resource group $rgName exists. Deleting..." | |
az group delete --name $rgName --yes --no-wait | |
echo "Resource group $rgName has been scheduled for deletion." | |
else | |
echo "Resource group $rgName does not exist." | |
fi | |
done | |
- name: Delete testResourceGroup | |
if: ${{ needs.verify_the_image.result != 'success' }} | |
run: | | |
echo "The verify_the_image result is ${{ needs.verify_the_image.result }}, delete the testResourceGroup." | |
az group delete -n ${{ env.testResourceGroup }} --yes --no-wait |