Configuration Guide#
HASTE environments are configured with the Azure Developer CLI. Every setting is
supplied with azd env set <NAME> <value> before azd up; the values are
read by infra/main.bicepparam at provision time and
by the deploy hooks in deploy/. Defaults live in
main.bicepparam, so an unset variable falls back to a sensible value.
This guide documents each configuration mode. For the end-to-end workflow, see
setup/README.md and deployment.md.
Contents#
Core settings
Batch (create vs. bring-your-own)
Batch image tags and pool immutability
hastegeo wheel pinning
Shared multi-tenant GPU pools
Email sender domain
Front Door
Development mode
First-admin bootstrap
Cleaning up an environment
Core settings#
Variable |
Default |
Purpose |
|---|---|---|
|
|
Prefix for all resource names. Generic default; override per deployment. |
|
|
Per-environment suffix; keeps names unique. |
|
|
Azure region. |
|
— |
APIM publisher email (required). |
|
|
APIM publisher name. |
|
env RG |
Resource group holding bring-your-own shared resources (Batch, ACR). |
|
— |
Shared Azure Container Registry name (without |
Resource names are HASTE_RESOURCE_PREFIX + HASTE_RANDOM_SUFFIX based (not
azd’s resourceToken) so what-if stays clean against existing deployments.
Batch (create vs. bring-your-own)#
HASTE runs GPU workloads on Azure Batch. Both the Batch account and the GPU pool can either be created in the environment resource group or reused from a shared resource group.
Variable |
Default |
Values |
Purpose |
|---|---|---|---|
|
|
|
Create a Batch account in the env RG, or reference a shared one. |
|
— |
account name |
Required when the account mode is |
|
|
|
Create the GPU pool, or reference an existing one. |
|
— |
pool resource id |
Required when the pool mode is |
Additional pool parameters (batchPoolVmSize, batchPoolMaxNodes,
batchPoolSubnetName) have defaults in infra/main.bicep
and can be overridden by adding them to main.bicepparam.
Common combinations:
Self-contained fork —
HASTE_BATCH_ACCOUNT_MODE=CreateandHASTE_BATCH_POOL_MODE=Createcreate a Batch account and a GPU pool in the environment resource group.Shared account, own pool —
HASTE_BATCH_ACCOUNT_MODE=ExistingwithHASTE_BATCH_POOL_MODE=Createcreates only a new named pool on the shared account, in the shared resource group, via a cross-RG-scoped sub-module. It never modifies the account or sibling pools.Shared account and pool — both set to
Existingreference the account and pool for app-settings wiring only; nothing is written to the shared resource group.
When the pool is created on a shared account, review what-if against both
the environment resource group and HASTE_SHARED_RESOURCE_GROUP, and make sure
the deploy identity has pool-write on the shared account.
hastegeo wheel pinning#
The Function Apps install hastegeo from a published wheel, but
api/*/requirements.txt commit -e ../../hastelib as the default install source
so docker-compose and local Function builds work straight from the checked-out
tree with no wheel publish.
That relative path does not resolve inside a deployment package — only
api/<app> is uploaded — so the line must be rewritten to the published wheel
before packaging. CI does this in
deploy_apps.sh;
azd does it with a pair of hooks:
Hook |
Script |
Purpose |
|---|---|---|
|
Resolve the wheel URL and pin it into the |
|
|
Restore the editable source from a verbatim backup. |
Variable |
Default |
Purpose |
|---|---|---|
|
(blank) |
Exact |
Four things worth knowing:
The hooks are declared per service in
azure.yaml, not at the root. Root-level hooks fire around the matchingazdcommand, so a rootprepackageruns forazd packagebut is skipped byazd deploy’s internal packaging step — which would ship the unresolvable editable path and fail the Oryx build.test_hastegeo_pin_hooks_are_service_scopedguards the placement.titilerhas nohastegeodependency and needs neither hook.The pin fails the deploy on error, deliberately. A mis-resolved wheel produces an app that deploys “successfully” and only breaks when a task runs.
Resolution requires
pythonand an authenticatedghCLI, because the resolver lists release assets viagh release view.
Email sender domain#
The email backend (Azure Communication Services) is provisioned in-IaC, so its connection string is a deploy-time output rather than a manually pasted secret.
Variable |
Default |
Values |
Purpose |
|---|---|---|---|
|
|
|
Sender-domain strategy. |
|
— |
domain |
Required when the type is |
AzureManaged provisions an
azurecomm.netsender domain with no DNS step — the default, best for forks and quick environments.Custom provisions a custom sender domain. DNS verification (TXT/SPF/DKIM records) lives in the customer’s DNS zone and is an out-of-band, one-time step.
No Key Vault is introduced; the connection string is wired from a listKeys()
output to the Function App settings.
Front Door#
Azure Front Door and its WAF are a feature-flagged module, deployed only when enabled.
Variable |
Default |
Purpose |
|---|---|---|
|
|
Provision Front Door + WAF in front of the app. |
Development mode#
Development mode is a dev-only switch. It must never be true in production.
Variable |
Default |
Purpose |
|---|---|---|
|
|
Anonymous Function auth + auto-provisioning of users as administrators. |
When true, the API uses anonymous auth and GetUserById auto-creates any
unknown caller as an administrator — convenient for local and throwaway
environments, unacceptable for production. When false (the default and the
production setting), Functions are key-protected (the postdeploy hook injects the
host key into the APIM backends) and unknown users are rejected until an admin
adds them.
The Docker Compose UI image pre-fills administrators in the SWA emulator’s
mock-login form. The source staticwebapp.config.json used for production is
unchanged.
First-admin bootstrap#
Production uses DEVELOPMENT_MODE=false, so users are managed explicitly and are
not auto-provisioned as administrators. That creates a bootstrap problem: an
admin is needed to add the first users, but a fresh environment has none. The
postdeploy hooks solve it by seeding a first admin.
Variable |
Default |
Purpose |
|---|---|---|
|
signed-in user |
Email of the first administrator. |
Interactive deploys — if
HASTE_FIRST_ADMIN_EMAILis unset, the seed uses the signed-in deployer’s email (deploy/seed-storage-defaults.ps1), writes it intousers_acl.jsonas an administrator, and invites it to the Static Web App (deploy/invite-user.ps1).Non-interactive / CI / service-principal deploys — there is no signed-in user, so set
HASTE_FIRST_ADMIN_EMAIL. Without it, the first-admin seed is skipped and the environment has no administrator.
Both hooks are idempotent (skip-if-exists / dedup). After the first admin signs in, subsequent users are added through the app’s admin user-management flow — the first-admin seed is a one-time bootstrap, not the ongoing mechanism.
Cleaning up an environment#
Deleting an environment does not immediately free its name. APIM, Front Door, and
Batch resources are soft-deleted and retained by Azure for a day or two, so
you cannot reuse the same HASTE_RESOURCE_PREFIX + HASTE_RANDOM_SUFFIX
combination right away.
To tear down and reuse a name sooner:
# Delete the environment's resources.
azd down --force --purge
# APIM must be purged from its soft-deleted state before the name is free.
az apim deletedservice list -o table
az apim deletedservice purge --service-name <name-from-the-list> --location <region>
azd down --purge purges soft-deletable resources it manages; a shared Batch
pool created on a shared account is additive, so remove it explicitly if it
is no longer needed. Otherwise, choose a new suffix and let Azure auto-purge the
old resources.