# BEFORE READING:
#
# 1. We are now running agents on 1ES, all the notes about VMSS can be safely ignored.
# 2. Many actions can be done on both cloud shell and web portal. Choose whichever you prefer.

steps:
- script: |
    curl -sL https://aka.ms/InstallAzureCLIDeb | sudo bash
  displayName: Install azcli

# Update 2022/7 (running on Microsoft-hosted agents / 1ES agents).
# Use a service principal. This service principal must be assigned contributor access to the resource group.
#
# Alternative option: managed identity.
# Follow tutorial of [image builder](https://docs.microsoft.com/en-us/azure/virtual-machines/image-builder-overview).
#
# Either way, the identity / service principal must be assigned contributor access to the resource group.
# We also added the following role (but I'm not sure whether it's necessary):
#
# {
#   "properties": {
#     "roleName": "ImageBuilderRole",
#     "description": "Image Builder access to create resources for the image build, you should delete or split out as appropriate",
#     "assignableScopes": [
#       "/subscriptions/<subscription_id>/resourceGroups/<resource_group>"
#     ],
#     "permissions": [
#       {
#         "actions": [
#           "Microsoft.Compute/galleries/read",
#           "Microsoft.Compute/galleries/images/read",
#           "Microsoft.Compute/galleries/images/versions/read",
#           "Microsoft.Compute/galleries/images/versions/write",
#           "Microsoft.Compute/images/write",
#           "Microsoft.Compute/images/read",
#           "Microsoft.Compute/images/delete",
#           "Microsoft.VirtualMachineImages/imageTemplates/write",
#           "Microsoft.VirtualMachineImages/imageTemplates/read",
#           "Microsoft.VirtualMachineImages/imageTemplates/delete"
#         ],
#         "notActions": [],
#         "dataActions": [],
#         "notDataActions": []
#       }
#     ]
#   }
# }
#
- script: |
    az login --service-principal -u $(client_id) -p $(client_secret) --tenant $(tenant_id)
  displayName: Login to Azure

# Make sure all these are registered.
# If not, might need az provider register -n xxx
# Need subscription-write access.

- script: |
    set -e
    az provider show -n Microsoft.VirtualMachineImages -o json
    az provider show -n Microsoft.KeyVault -o json
    az provider show -n Microsoft.Compute -o json
    az provider show -n Microsoft.Storage -o json
    az provider show -n Microsoft.Network -o json
  displayName: Register features

# Need to create an image gallery before this.
# Only need to create once (can be done on web portal).
# az sig create --resource-group <resource_group> --gallery-name <sig_name>
#
# NOTE: Remember to add READER access to the image gallery for "1ES Resource Management".
#
# Add a image definition (also only once).
# az sig image-definition create -g <resource_group> \
#   --gallery-name <sig_name> \
#   --gallery-image-definition <image_def>
#
# For example,
# az sig image-definition create -g nni --gallery-name nniImageGallery \
#   --gallery-image-definition nniLinuxImage \
#   --publisher NNI \
#   --offer ubuntu \
#   --sku 20_04-nni \
#   --os-type Linux \
#   --hyper-v-generation V2
#
# This can be done on web portal, remember to choose V2 for Hyper-V generation.

- script: |
    set -e
    set -x
    az image list -g $(resource_group)
    if az image list -g $(resource_group) --query [].'name' | grep -q $(managed_image_name); then
      az image delete -n $(managed_image_name) -g $(resource_group)
    fi
  displayName: List existing images (and delete)

- script: |
    set -e
    curl -fsSL https://apt.releases.hashicorp.com/gpg | sudo apt-key add -
    sudo apt-add-repository "deb [arch=amd64] https://apt.releases.hashicorp.com $(lsb_release -cs) main"
    sudo apt-get update && sudo apt-get install packer
  displayName: Install packer

- script: |
    set -e
    cd test/vso_tools/build_vm
    export IP_ADDRESS=$(curl -s ifconfig.me)
    export VERSION=$(date "+%Y").$(date "+%m%d").$(date "+%H%M%S")
    export CONFIG_PATH=$(packer_config).json
    sed -i -e "s/<client_id>/$(client_id)/g" $CONFIG_PATH
    sed -i -e "s/<client_secret>/$(client_secret)/g" $CONFIG_PATH
    sed -i -e "s/<subscription_id>/$(subscription_id)/g" $CONFIG_PATH
    sed -i -e "s/<managed_image_name>/$(managed_image_name)/g" $CONFIG_PATH
    sed -i -e "s/<resource_group>/$(resource_group)/g" $CONFIG_PATH
    sed -i -e "s/<network_security_group>/$(network_security_group)/g" $CONFIG_PATH
    sed -i -e "s/<gallery_name>/$(gallery_name)/g" $CONFIG_PATH
    sed -i -e "s/<image_name>/$(image_definition_name)/g" $CONFIG_PATH
    sed -i -e "s/<image_version>/${VERSION}/g" $CONFIG_PATH
    sed -i -e "s/<ip_address>/${IP_ADDRESS}/g" $CONFIG_PATH
    cat $CONFIG_PATH
    echo "##vso[task.logissue type=warning]During packer build, please avoid cancelling this task. Otherwise, created resources might need manual cleanup."
  displayName: Prepare configuration

# Microsoft has a security group for VM created under their subscriptions, that,
# based on my observations (though I had no clearance to see it myself):
# 1. A low priority deny all that denies all unintended incoming traffic.
# 2. A medium-high priority denial for all traffic coming from small ports (lower than 8000 probably).
# 3. A high priority allowance for traffics from Microsoft-internal IPs.
#
# We can only insert new rules below medium. Therefore,
# 1. For Linux, we change the ssh port to 10022. This is done at provisioning by injecting user / custom data.
# 2. For Windows, they can't execute the user data script: https://stackoverflow.com/questions/62888359/custom-data-with-azure-windows-vm-run-powersell-script
#    We can't use custom script extensions either because it's not supported in packer.
#    We also can't use shell-local provisioner to invoke command, because when the VM is ready, packer always try to connect to WinRM.
#    The workaround here is to use a monitor to detect the machine ready signal and change its WinRM port.
- script: |
    cd test/vso_tools/build_vm
    python3 packer_build_windows.py $(packer_config).json $(resource_group)
  displayName: (Windows) Packer build
  condition: and(succeeded(), contains(variables['packer_config'], 'windows'))

- script: |
    cd test/vso_tools/build_vm
    PACKER_LOG=1 packer build $(packer_config).json
  displayName: (Linux) Packer build
  condition: and(succeeded(), contains(variables['packer_config'], 'linux'))

# TODO: Should delete the managed image after build is done.
# Image gallery alone is enough. Keeping it for now for debugging purposes.

# No further actions are needed here. VM images are already set to latest. They should be auto-updated.
# In case you want to do it on your own:
#
# To deploy the image on VMSS, run this in Cloud Shell:
# az vmss update --resource-group nni --name nni-windows-it \
#   --set virtualMachineProfile.storageProfile.imageReference.id=/subscriptions/{subscriptionId}/resourceGroups/nni/providers/Microsoft.Compute/galleries/nniImageGallery/images/nniWindowsImage/versions/Latest
#
# To deploy the image on 1ES, similar actions need to be performed on the web portal of 1ES managed images.
#
# Probably need to enlarge the disk size, in case it's too small:
# az vmss update -n nni-it -g nni --set virtualMachineProfile.storageProfile.osDisk.diskSizeGb=50
