Database Post-Deploy Verification
Run schema migrations on AppOnboard-created databases (listed in prepare-plan.json.services[]) before health checks. The app must be running first — if it's crashing, fix that before attempting migrations.
Create App Database (if needed)
⛔ Azure PostgreSQL/MySQL Flexible Server only creates the system
postgres/mysqldatabase by default. If the app's config references a named database (e.g.,car_sale_db,myapp_production), create it BEFORE the container starts:powershellaz postgres flexible-server db create -g \{rg\} -s \{serverName\} -d \{dbName\}Detect the database name from: (1)
prereq-output.json.initCommands[]withtype: "db-migrate", (2) app config files (config-docker.yml,.env,database.yml), (3) composePOSTGRES_DBenv var. If the container crashes withdatabase "X" does not exist, this step was missed.
Discover the migration command from the codebase (check in order):
| Signal | Command | Working directory |
|---|---|---|
alembic.ini exists | alembic upgrade head | Directory containing alembic.ini |
Django manage.py exists | python manage.py migrate | Directory containing manage.py |
prisma/schema.prisma exists | npx prisma migrate deploy | Project root |
EF Migrations/ directory | dotnet ef database update | Project root |
Rails db/migrate/ directory | rails db:migrate | Project root |
Sequelize migrations/ + .sequelizerc | npx sequelize-cli db:migrate | Project root |
Execute via the Deployed Environment
App Service (Linux only)
az webapp ssh -n {app} -g {rg} --subscription {sub}
# Then run the migration command interactivelyContainer Apps
az containerapp exec -n {ca} -g {rg} --subscription {sub} --command "{migration_command}"
# If the app's WORKDIR differs from migration tool location:
az containerapp exec -n {ca} -g {rg} --subscription {sub} --command "cd /app/backend && alembic upgrade head"Error Handling
If the migration command fails, classify as IAC_ERROR and check based on the database type:
- DB unreachable → check firewall rules (PostgreSQL:
AllowAllAzureServicesAndResourcesWithinAzureIps, SQL: server firewall, MySQL: similar) - Extension/feature missing → check DB-specific config (PostgreSQL:
azure.extensions, SQL: compatibility level, MySQL:require_secure_transport) - Module not found → verify the runtime includes the migration tool
⛔
\{pass\}MUST be the same password passed toaz deployment sub create --parameters pgAdminPassword=\{value\}. See deploy-safety.md § Deploy Checklist — generate each secret ONCE, persist todeploy-secrets.env, reuse everywhere. Mismatched passwords cause silent auth failures on migrations and connectivity checks.
PostgreSQL-Specific Checks
Run BEFORE migrations when services[] includes PostgreSQL Flexible Server:
- Firewall connectivity:
az postgres flexible-server execute -n \{pg\} -g \{rg\} -u \{admin\} -p \{pass\} -d postgres --querytext "SELECT 1"— if this fails, the firewall rule is missing or RBAC propagation hasn't completed. CheckAllowAllAzureServicesAndResourcesWithinAzureIpsexists, wait 60s, retry - Extension availability:
az postgres flexible-server parameter show -g \{rg\} -n \{pg\} --name azure.extensions --query value -o tsv— verify the extensions the app needs (e.g.,uuid-osspfor Alembic/Django UUID fields) are in the allow-list. If missing, the Bicep module should have set them — checkinfra/modules/postgresql.bicep
MySQL Flexible Server Checks
Run BEFORE migrations when services[] includes MySQL Flexible Server:
- Firewall connectivity:
az mysql flexible-server execute -n \{mysql\} -u \{admin\} -p \{pass\} -d mysql -q "SELECT 1"— if this fails, check the firewall rule and RBAC propagation. Note:executeresolves by server name (no-gneeded) - SSL enforcement:
az mysql flexible-server parameter show -g \{rg\} -n \{mysql\} --name require_secure_transport --query value -o tsv— verify matches the app's connection string SSL mode
Azure SQL Checks
Run BEFORE migrations when services[] includes Azure SQL:
- Firewall connectivity:
az sql db show -g \{rg\} -s \{sqlServer\} -n \{dbName\} --query status -o tsv— verify the database isOnline - Server firewall:
az sql server firewall-rule list -g \{rg\} -s \{sqlServer\} -o table— verifyAllowAllWindowsAzureIps(0.0.0.0 → 0.0.0.0) exists for Azure-internal access