Skip to content

Manual Test Runbook — L1: Azure Backup Policy Module

Owner: Sagar  |  Time: ~8 min (Parts A + B offline) · +12 min (optional Part C integration apply)  |  Sandbox: snowops-sandbox-01

Promotes L1 (modules/azure/backup-policy/) from 🟦 Code Complete → 🟩 Shipped. Parts A + B are offline ($0). Part C applies the two vaults + four policies to the sandbox (~$0 — vaults are free and no instances are bound) and destroys.


Prerequisites

  • Sandbox subscription access active (PIM activated if required)
  • az login done; sandbox subscription selected
  • Identity has Contributor on the sandbox sub (vault + policy create)
  • SNOWOPS_SANDBOX_SUBSCRIPTION_ID + SNOWOPS_SANDBOX_TENANT_ID exported
  • Local tooling: terraform >= 1.6, go >= 1.22, az CLI >= 2.50
  • Working directory: repo root

Steps

Part A — terraform fmt + validate (offline, ~3 min)

  1. Module + example:
terraform -chdir=modules/azure/backup-policy fmt -recursive -check
terraform -chdir=modules/azure/backup-policy init -backend=false -input=false
terraform -chdir=modules/azure/backup-policy validate

terraform -chdir=modules/azure/backup-policy/examples/basic init -backend=false -input=false
terraform -chdir=modules/azure/backup-policy/examples/basic validate

Expected: Success! for both.

  1. Offline Terratest case:
cd tests/terratest
go test -v -timeout 5m ./modules/azure/... -run TestBackupPolicyValidate

Expected: PASS — exercises both vaults, all four workload policies, the daily+weekly+monthly+yearly retention tiers (prod profile), and the cross-variable preconditions, offline.

Part B — full Terratest suite (offline, ~5 min)

  1. bash cd tests/terratest && go test -count=1 -timeout 15m ./...

Expected: the full suite green (the new TestBackupPolicyValidate included).

Part C — integration apply (sandbox, ~12 min, ~$0)

No build-tagged integration test ships for L1 (a real backup run takes hours and a real restore is the L4 drill). This part is a manual apply-assert-destroy of the policy substrate.

  1. Apply the fixture (creates an RG + GeoRedundant Recovery Services vault + Backup vault + all four policies):
cd tests/terratest/fixtures/backup-policy
terraform init -input=false
terraform apply -auto-approve \
  -var "subscription_id=$SNOWOPS_SANDBOX_SUBSCRIPTION_ID" \
  -var "tenant_id=$SNOWOPS_SANDBOX_TENANT_ID" \
  -var "name_prefix=l1-drill-$RANDOM"
  1. Confirm the vaults and a policy exist with the expected redundancy + retention:
RSV=$(terraform output -raw recovery_services_vault_id | sed -E 's#.*/vaults/##')
RG=$(terraform output -json retention_summary >/dev/null; terraform state show 'azurerm_resource_group.this' | awk '/name /{print $3; exit}' | tr -d '"')

az backup vault show --name "$RSV" --resource-group "$RG" \
  --query "{redundancy:properties.redundancySettings, immutability:properties.securitySettings.immutabilitySettings.state}" -o json

az backup policy show --vault-name "$RSV" --resource-group "$RG" \
  --name "l1-drill-*-vm-policy" \
  --query "{daily:properties.retentionPolicy.dailySchedule.retentionDuration}" -o json 2>/dev/null || true

Expected: redundancy reflects GeoRedundant; the VM policy shows a 30-day daily retention (prod profile).

  1. Destroy:
terraform destroy -auto-approve \
  -var "subscription_id=$SNOWOPS_SANDBOX_SUBSCRIPTION_ID" \
  -var "tenant_id=$SNOWOPS_SANDBOX_TENANT_ID" \
  -var "name_prefix=<the-prefix-you-used>"

Expected: clean destroy (no protected items were bound, so the vaults delete without unregistering anything).


Pass criteria

  • Part A — module + example validate; TestBackupPolicyValidate passes
  • Part B — full offline suite passes
  • (Part C) fixture applies both vaults + four policies; redundancy = GeoRedundant, VM daily retention = 30; destroys clean
  • All test resources removed

Teardown

If Part C left anything behind (e.g. a destroy interrupted), delete the drill RG:

az group delete --name "l1-drill-<suffix>-rg" --yes --no-wait

An empty backup vault deletes cleanly. A vault with protected items cannot be deleted until protection is stopped and soft-deleted items are purged — L1 binds no instances, so this only matters once a consumer attaches one.


Sign-off

  • Tester: _  |  Date: _  |  Result: PASS / FAIL / N/A
  • Notes: