diff --git a/.pipelines/swiftv2-long-running/pipeline.yaml b/.pipelines/swiftv2-long-running/pipeline.yaml new file mode 100644 index 0000000000..b6d085901d --- /dev/null +++ b/.pipelines/swiftv2-long-running/pipeline.yaml @@ -0,0 +1,42 @@ +trigger: none + +parameters: + - name: subscriptionId + displayName: "Azure Subscription ID" + type: string + default: "37deca37-c375-4a14-b90a-043849bd2bf1" + + - name: location + displayName: "Deployment Region" + type: string + default: "centraluseuap" + + - name: resourceGroupName + displayName: "Resource Group Name" + type: string + default: "long-run-$(Build.BuildId)" + + - name: vmSkuDefault + displayName: "VM SKU for Default Node Pool" + type: string + default: "Standard_D2s_v3" + + - name: vmSkuHighNIC + displayName: "VM SKU for High NIC Node Pool" + type: string + default: "Standard_D16s_v3" + + - name: serviceConnection + displayName: "Azure Service Connection" + type: string + default: "Azure Container Networking - Standalone Test Service Connection" + +extends: + template: template/long-running-pipeline-template.yaml + parameters: + subscriptionId: ${{ parameters.subscriptionId }} + location: ${{ parameters.location }} + resourceGroupName: ${{ parameters.resourceGroupName }} + vmSkuDefault: ${{ parameters.vmSkuDefault }} + vmSkuHighNIC: ${{ parameters.vmSkuHighNIC }} + serviceConnection: ${{ parameters.serviceConnection }} diff --git a/.pipelines/swiftv2-long-running/scripts/create_aks.sh b/.pipelines/swiftv2-long-running/scripts/create_aks.sh new file mode 100644 index 0000000000..f051f994a6 --- /dev/null +++ b/.pipelines/swiftv2-long-running/scripts/create_aks.sh @@ -0,0 +1,47 @@ +#!/usr/bin/env bash +set -e +trap 'echo "[ERROR] Failed during Resource group or AKS cluster creation." >&2' ERR + +SUBSCRIPTION_ID=$1 +LOCATION=$2 +RG=$3 +VM_SKU_DEFAULT=$4 +VM_SKU_HIGHNIC=$5 + +echo "Subscription id: $SUBSCRIPTION_ID" +echo "Resource group: $RG" +echo "Location: $LOCATION" +echo "VM SKU (default): $VM_SKU_DEFAULT" +echo "VM SKU (high-NIC): $VM_SKU_HIGHNIC" +az account set --subscription "$SUBSCRIPTION_ID" + +# Enable parallel cluster creation +create_cluster() { + local CLUSTER=$1 + echo "==> Creating AKS cluster: $CLUSTER" + + az aks create -g "$RG" -n "$CLUSTER" -l "$LOCATION" \ + --network-plugin azure --node-count 1 \ + --node-vm-size "$VM_SKU_DEFAULT" \ + --enable-managed-identity --generate-ssh-keys \ + --load-balancer-sku standard --yes --only-show-errors + + echo "==> Adding high-NIC nodepool to $CLUSTER" + az aks nodepool add -g "$RG" -n highnic \ + --cluster-name "$CLUSTER" --node-count 2 \ + --node-vm-size "$VM_SKU_HIGHNIC" --mode User --only-show-errors + + echo "Finished AKS cluster: $CLUSTER" +} + +# Run both clusters in parallel +create_cluster "aks-cluster-a" & +pid_a=$! + +create_cluster "aks-cluster-b" & +pid_b=$! + +# Wait for both to finish +wait $pid_a $pid_b + +echo "AKS clusters created successfully!" diff --git a/.pipelines/swiftv2-long-running/scripts/create_nsg.sh b/.pipelines/swiftv2-long-running/scripts/create_nsg.sh new file mode 100644 index 0000000000..d37a125a3f --- /dev/null +++ b/.pipelines/swiftv2-long-running/scripts/create_nsg.sh @@ -0,0 +1,48 @@ +#!/usr/bin/env bash +set -e +trap 'echo "[ERROR] Failed during NSG creation or rule setup." >&2' ERR + +SUBSCRIPTION_ID=$1 +RG=$2 +LOCATION=$3 + +VNET_A1="cx_vnet_a1" +SUBNET1_PREFIX="10.10.1.0/24" +SUBNET2_PREFIX="10.10.2.0/24" +NSG_NAME="${VNET_A1}-nsg" + +echo "==> Creating Network Security Group: $NSG_NAME" +az network nsg create -g "$RG" -n "$NSG_NAME" -l "$LOCATION" --output none \ + && echo "[OK] NSG '$NSG_NAME' created." + +echo "==> Creating NSG rule to DENY traffic from Subnet1 ($SUBNET1_PREFIX) to Subnet2 ($SUBNET2_PREFIX)" +az network nsg rule create \ + -g "$RG" \ + --nsg-name "$NSG_NAME" \ + -n deny-subnet1-to-subnet2 \ + --priority 100 \ + --source-address-prefixes "$SUBNET1_PREFIX" \ + --destination-address-prefixes "$SUBNET2_PREFIX" \ + --direction Inbound \ + --access Deny \ + --protocol "*" \ + --description "Deny all traffic from Subnet1 to Subnet2" \ + --output none \ + && echo "[OK] Deny rule from Subnet1 → Subnet2 created." + +echo "==> Creating NSG rule to DENY traffic from Subnet2 ($SUBNET2_PREFIX) to Subnet1 ($SUBNET1_PREFIX)" +az network nsg rule create \ + -g "$RG" \ + --nsg-name "$NSG_NAME" \ + -n deny-subnet2-to-subnet1 \ + --priority 200 \ + --source-address-prefixes "$SUBNET2_PREFIX" \ + --destination-address-prefixes "$SUBNET1_PREFIX" \ + --direction Inbound \ + --access Deny \ + --protocol "*" \ + --description "Deny all traffic from Subnet2 to Subnet1" \ + --output none \ + && echo "[OK] Deny rule from Subnet2 → Subnet1 created." + +echo "NSG '$NSG_NAME' created successfully with bidirectional isolation between Subnet1 and Subnet2." diff --git a/.pipelines/swiftv2-long-running/scripts/create_pe.sh b/.pipelines/swiftv2-long-running/scripts/create_pe.sh new file mode 100644 index 0000000000..1d1aea0744 --- /dev/null +++ b/.pipelines/swiftv2-long-running/scripts/create_pe.sh @@ -0,0 +1,56 @@ +#!/usr/bin/env bash +set -e +trap 'echo "[ERROR] Failed during Private Endpoint or DNS setup." >&2' ERR + +SUBSCRIPTION_ID=$1 +LOCATION=$2 +RG=$3 +SA1_NAME=$4 # Storage account 1 + +VNET_A1="cx_vnet_a1" +VNET_A2="cx_vnet_a2" +VNET_A3="cx_vnet_a3" +SUBNET_PE_A1="pe" +PE_NAME="${SA1_NAME}-pe" +PRIVATE_DNS_ZONE="privatelink.blob.core.windows.net" + +# 1. Create Private DNS zone +echo "==> Creating Private DNS zone: $PRIVATE_DNS_ZONE" +az network private-dns zone create -g "$RG" -n "$PRIVATE_DNS_ZONE" --output none \ + && echo "[OK] DNS zone $PRIVATE_DNS_ZONE created." + +# 2. Link DNS zone to VNet +echo "==> Linking DNS zone $PRIVATE_DNS_ZONE to VNet $VNET_A1" +az network private-dns link vnet create \ + -g "$RG" -n "${VNET_A1}-link" \ + --zone-name "$PRIVATE_DNS_ZONE" \ + --virtual-network "$VNET_A1" \ + --registration-enabled false \ + && echo "[OK] Linked DNS zone to $VNET_A1." + +az network private-dns link vnet create \ + -g "$RG" -n "${VNET_A2}-link" -\ + -zone-name "$PRIVATE_DNS_ZONE" \ + --virtual-network "$VNET_A2" \ + --registration-enabled false \ + && echo "[OK] Linked DNS zone to $VNET_A2." + +az network private-dns link vnet create \ + -g "$RG" -n "${VNET_A3}-link" \ + --zone-name "$PRIVATE_DNS_ZONE" \ + --virtual-network "$VNET_A3" \ + --registration-enabled false \ + && echo "[OK] Linked DNS zone to $VNET_A3." + + +# 3. Create Private Endpoint +echo "==> Creating Private Endpoint for Storage Account: $SA1_NAME" +SA1_ID=$(az storage account show -g "$RG" -n "$SA1_NAME" --query id -o tsv) +az network private-endpoint create \ + -g "$RG" -n "$PE_NAME" -l "$LOCATION" \ + --vnet-name "$VNET_A1" --subnet "$SUBNET_PE_A1" \ + --private-connection-resource-id "$SA1_ID" \ + --group-id blob \ + --connection-name "${PE_NAME}-conn" \ + --output none \ + && echo "[OK] Private Endpoint $PE_NAME created for $SA1_NAME." diff --git a/.pipelines/swiftv2-long-running/scripts/create_peerings.sh b/.pipelines/swiftv2-long-running/scripts/create_peerings.sh new file mode 100644 index 0000000000..ce5cb58c19 --- /dev/null +++ b/.pipelines/swiftv2-long-running/scripts/create_peerings.sh @@ -0,0 +1,23 @@ +#!/usr/bin/env bash +set -e +trap 'echo "[ERROR] Failed during VNet peering creation." >&2' ERR + +RG=$1 +VNET_A1="cx_vnet_a1" +VNET_A2="cx_vnet_a2" +VNET_A3="cx_vnet_a3" +VNET_B1="cx_vnet_b1" + +peer_two_vnets() { + local rg="$1"; local v1="$2"; local v2="$3"; local name12="$4"; local name21="$5" + echo "==> Peering $v1 <-> $v2" + az network vnet peering create -g "$rg" -n "$name12" --vnet-name "$v1" --remote-vnet "$v2" --allow-vnet-access --output none \ + && echo "Created peering $name12" + az network vnet peering create -g "$rg" -n "$name21" --vnet-name "$v2" --remote-vnet "$v1" --allow-vnet-access --output none \ + && echo "Created peering $name21" +} + +peer_two_vnets "$RG" "$VNET_A1" "$VNET_A2" "A1-to-A2" "A2-to-A1" +peer_two_vnets "$RG" "$VNET_A2" "$VNET_A3" "A2-to-A3" "A3-to-A2" +peer_two_vnets "$RG" "$VNET_A1" "$VNET_A3" "A1-to-A3" "A3-to-A1" +echo "VNet peerings created successfully." diff --git a/.pipelines/swiftv2-long-running/scripts/create_storage.sh b/.pipelines/swiftv2-long-running/scripts/create_storage.sh new file mode 100644 index 0000000000..14c230734f --- /dev/null +++ b/.pipelines/swiftv2-long-running/scripts/create_storage.sh @@ -0,0 +1,39 @@ +#!/usr/bin/env bash +set -e +trap 'echo "[ERROR] Failed during Storage Account creation." >&2' ERR + +SUBSCRIPTION_ID=$1 +LOCATION=$2 +RG=$3 + +RAND=$(openssl rand -hex 4) +SA1="sa1${RAND}" +SA2="sa2${RAND}" + +# Set subscription context +az account set --subscription "$SUBSCRIPTION_ID" + +# Create storage accounts +for SA in "$SA1" "$SA2"; do + echo "==> Creating storage account $SA" + az storage account create \ + --name "$SA" \ + --resource-group "$RG" \ + --location "$LOCATION" \ + --sku Standard_LRS \ + --kind StorageV2 \ + --allow-blob-public-access false \ + --allow-shared-key-access false \ + --https-only true \ + --min-tls-version TLS1_2 \ + --query "name" -o tsv \ + && echo "Storage account $SA created successfully." +done + +echo "All storage accounts created successfully." + +# Set pipeline output variables +set +x +echo "##vso[task.setvariable variable=StorageAccount1;isOutput=true]$SA1" +echo "##vso[task.setvariable variable=StorageAccount2;isOutput=true]$SA2" +set -x diff --git a/.pipelines/swiftv2-long-running/scripts/create_vnets.sh b/.pipelines/swiftv2-long-running/scripts/create_vnets.sh new file mode 100644 index 0000000000..7363476488 --- /dev/null +++ b/.pipelines/swiftv2-long-running/scripts/create_vnets.sh @@ -0,0 +1,47 @@ +#!/usr/bin/env bash +set -e +trap 'echo "[ERROR] Failed while creating VNets or subnets. Check Azure CLI logs above." >&2' ERR + +SUBSCRIPTION_ID=$1 +LOCATION=$2 +RG=$3 + +az account set --subscription "$SUBSCRIPTION_ID" + +# VNets and subnets +VNET_A1="cx_vnet_a1" +VNET_A2="cx_vnet_a2" +VNET_A3="cx_vnet_a3" +VNET_B1="cx_vnet_b1" + +A1_S1="10.10.1.0/24" +A1_S2="10.10.2.0/24" +A1_PE="10.10.100.0/24" + +A2_MAIN="10.11.1.0/24" + +A3_MAIN="10.12.1.0/24" + +B1_MAIN="10.20.1.0/24" + +# A1 +az network vnet create -g "$RG" -n "$VNET_A1" --address-prefix 10.10.0.0/16 --subnet-name s1 --subnet-prefix "$A1_S1" -l "$LOCATION" --output none \ + && echo "Created $VNET_A1 with subnet s1" +az network vnet subnet create -g "$RG" --vnet-name "$VNET_A1" -n s2 --address-prefix "$A1_S2" --output none \ + && echo "Created $VNET_A1 with subnet s2" +az network vnet subnet create -g "$RG" --vnet-name "$VNET_A1" -n pe --address-prefix "$A1_PE" --output none \ + && echo "Created $VNET_A1 with subnet pe" + +# A2 +az network vnet create -g "$RG" -n "$VNET_A2" --address-prefix 10.11.0.0/16 --subnet-name s1 --subnet-prefix "$A2_MAIN" -l "$LOCATION" --output none \ + && echo "Created $VNET_A2 with subnet s1" + +# A3 +az network vnet create -g "$RG" -n "$VNET_A3" --address-prefix 10.12.0.0/16 --subnet-name s1 --subnet-prefix "$A3_MAIN" -l "$LOCATION" --output none \ + && echo "Created $VNET_A3 with subnet s1" + +# B1 +az network vnet create -g "$RG" -n "$VNET_B1" --address-prefix 10.20.0.0/16 --subnet-name s1 --subnet-prefix "$B1_MAIN" -l "$LOCATION" --output none \ + && echo "Created $VNET_B1 with subnet s1" + +echo "All VNets and subnets created successfully." diff --git a/.pipelines/swiftv2-long-running/template/long-running-pipeline-template.yaml b/.pipelines/swiftv2-long-running/template/long-running-pipeline-template.yaml new file mode 100644 index 0000000000..cc6016f17a --- /dev/null +++ b/.pipelines/swiftv2-long-running/template/long-running-pipeline-template.yaml @@ -0,0 +1,140 @@ +parameters: + - name: subscriptionId + type: string + - name: location + type: string + - name: resourceGroupName + type: string + - name: vmSkuDefault + type: string + - name: vmSkuHighNIC + type: string + - name: serviceConnection + type: string + +stages: + - stage: AKSClusterAndNetworking + displayName: "Stage: AKS Cluster and Networking Setup" + jobs: + # ------------------------------------------------------------ + # Job 1: Create Resource Group + # ------------------------------------------------------------ + - job: CreateResourceGroup + displayName: "Create Resource Group" + pool: + vmImage: ubuntu-latest + steps: + - checkout: self + - task: AzureCLI@2 + displayName: "Create resource group" + inputs: + azureSubscription: ${{ parameters.serviceConnection }} + scriptType: bash + scriptLocation: inlineScript + inlineScript: | + echo "==> Creating resource group ${{ parameters.resourceGroupName }} in ${{ parameters.location }}" + az group create \ + --name "${{ parameters.resourceGroupName }}" \ + --location "${{ parameters.location }}" \ + --subscription "${{ parameters.subscriptionId }}" + echo "Resource group created successfully." + + # ------------------------------------------------------------ + # Job 2: Create AKS Clusters + # ------------------------------------------------------------ + - job: CreateCluster + displayName: "Create AKS Clusters" + dependsOn: CreateResourceGroup + pool: + vmImage: ubuntu-latest + steps: + - checkout: self + - task: AzureCLI@2 + displayName: "Run create_aks.sh" + inputs: + azureSubscription: ${{ parameters.serviceConnection }} + scriptType: bash + scriptLocation: scriptPath + scriptPath: ".pipelines/swiftv2-long-running/scripts/create_aks.sh" + arguments: > + ${{ parameters.subscriptionId }} + ${{ parameters.location }} + ${{ parameters.resourceGroupName }} + ${{ parameters.vmSkuDefault }} + ${{ parameters.vmSkuHighNIC }} + + # ------------------------------------------------------------ + # Job 3: Networking & Storage + # ------------------------------------------------------------ + - job: NetworkingAndStorage + displayName: "Networking and Storage Setup" + dependsOn: CreateResourceGroup + pool: + vmImage: ubuntu-latest + steps: + - checkout: self + + # Task 1: Create VNets + - task: AzureCLI@2 + displayName: "Create customer vnets" + inputs: + azureSubscription: ${{ parameters.serviceConnection }} + scriptType: bash + scriptLocation: scriptPath + scriptPath: ".pipelines/swiftv2-long-running/scripts/create_vnets.sh" + arguments: > + ${{ parameters.subscriptionId }} + ${{ parameters.location }} + ${{ parameters.resourceGroupName }} + + # Task 2: Create Peerings + - task: AzureCLI@2 + displayName: "Create customer vnet peerings" + inputs: + azureSubscription: ${{ parameters.serviceConnection }} + scriptType: bash + scriptLocation: scriptPath + scriptPath: ".pipelines/swiftv2-long-running/scripts/create_peerings.sh" + arguments: > + ${{ parameters.resourceGroupName }} + + # Task 3: Create Storage Accounts + - task: AzureCLI@2 + name: CreateStorageAccounts + displayName: "Create storage accounts" + inputs: + azureSubscription: ${{ parameters.serviceConnection }} + scriptType: bash + scriptLocation: scriptPath + scriptPath: ".pipelines/swiftv2-long-running/scripts/create_storage.sh" + arguments: > + ${{ parameters.subscriptionId }} + ${{ parameters.location }} + ${{ parameters.resourceGroupName }} + + # Task 4: Create NSG + - task: AzureCLI@2 + displayName: "Create network security groups to restrict access between subnets" + inputs: + azureSubscription: ${{ parameters.serviceConnection }} + scriptType: bash + scriptLocation: scriptPath + scriptPath: ".pipelines/swiftv2-long-running/scripts/create_nsg.sh" + arguments: > + ${{ parameters.subscriptionId }} + ${{ parameters.resourceGroupName }} + ${{ parameters.location }} + + # Task 5: Create Private Endpoint + - task: AzureCLI@2 + displayName: "Create Private Endpoint for Storage Account" + inputs: + azureSubscription: ${{ parameters.serviceConnection }} + scriptType: bash + scriptLocation: scriptPath + scriptPath: ".pipelines/swiftv2-long-running/scripts/create_pe.sh" + arguments: > + ${{ parameters.subscriptionId }} + ${{ parameters.location }} + ${{ parameters.resourceGroupName }} + $(CreateStorageAccounts.StorageAccount1)