Service
ARM (Microsoft.Resources) — the resource-group resource index.
Azure API Action
Resources - List By Resource Group —
GET /subscriptions/{sub}/resourceGroups/{rg}/resources?api-version=2021-04-01
Expected behavior
Real Azure returns every resource in the group, whatever provider owns it.
Actual behavior
The listing returns only the providers ArmHandler knows about: its own inline Storage / Key Vault / Web state, plus Network, API Management, Managed Identity, plus whatever implements the CDI ResourceIndexContributor interface — and AciHandler is currently the only implementation.
So a resource group holding a VM comes back without the VM, even though the same VM answers a direct GET with 200 and appears in the type-scoped list under /providers/Microsoft.Compute/virtualMachines.
Providers with a management plane in floci-az that never reach the index:
| Provider |
Handler |
Microsoft.Compute/virtualMachines |
VmHandler |
Microsoft.ContainerService/managedClusters |
AksHandler |
Microsoft.ContainerRegistry/registries |
AcrHandler |
Microsoft.Cache/Redis |
RedisHandler |
Microsoft.DBforPostgreSQL/flexibleServers |
PostgresHandler |
Microsoft.DBforMySQL/flexibleServers |
MySqlHandler |
Microsoft.DBforMariaDB/servers |
MariaDbHandler |
Microsoft.Sql/servers |
SqlHandler |
Reproduction
docker run -d --rm --name floci-az-repro -p 4577:4577 \
floci/floci-az@sha256:6566c73b8f4b6e3ef90322c8c84a47258bb1ca13c82ea1d40027f7af11247e30
B=http://localhost:4577
SUB=00000000-0000-0000-0000-000000000001
RG=repro-rg
curl -s -X PUT "$B/subscriptions/$SUB/resourceGroups/$RG?api-version=2021-04-01" \
-H 'Content-Type: application/json' -d '{"location":"eastus"}'
curl -s -X PUT "$B/subscriptions/$SUB/resourceGroups/$RG/providers/Microsoft.Compute/virtualMachines/repro-vm?api-version=2024-11-01" \
-H 'Content-Type: application/json' -d '{
"location":"eastus",
"properties":{
"hardwareProfile":{"vmSize":"Standard_D2s_v3"},
"storageProfile":{"imageReference":{"publisher":"Canonical","offer":"0001-com-ubuntu-server-jammy","sku":"22_04-lts","version":"latest"},
"osDisk":{"createOption":"FromImage","name":"repro-osdisk"}},
"osProfile":{"adminUsername":"azureuser","computerName":"reprovm"}}}'
curl -s -X PUT "$B/subscriptions/$SUB/resourceGroups/$RG/providers/Microsoft.Storage/storageAccounts/reprosa?api-version=2023-01-01" \
-H 'Content-Type: application/json' -d '{"location":"eastus","sku":{"name":"Standard_LRS"},"kind":"StorageV2"}'
# The VM exists and is listed at the type-scoped level:
curl -s -o /dev/null -w 'direct GET -> HTTP %{http_code}\n' \
"$B/subscriptions/$SUB/resourceGroups/$RG/providers/Microsoft.Compute/virtualMachines/repro-vm?api-version=2024-11-01"
curl -s "$B/subscriptions/$SUB/resourceGroups/$RG/providers/Microsoft.Compute/virtualMachines?api-version=2024-11-01" \
| python3 -c 'import sys,json; print("type list ->", [r["name"] for r in json.load(sys.stdin)["value"]])'
# ...but the resource-group aggregation does not contain it:
curl -s "$B/subscriptions/$SUB/resourceGroups/$RG/resources?api-version=2021-04-01" \
| python3 -c 'import sys,json; print("rg index ->", [(r["name"], r["type"]) for r in json.load(sys.stdin)["value"]])'
Output on the pinned release above:
direct GET -> HTTP 200
type list -> ['repro-vm']
rg index -> [('reprosa', 'Microsoft.Storage/storageAccounts')]
The storage account is there. The VM is not.
Impact
ResourceIndexContributor's own javadoc records why this listing matters: "The azurerm provider calls that listing before deleting a resource group to verify it is empty; a service that skips registration lets terraform destroy remove a group whose resources still exist." That is exactly the state VMs, AKS clusters, registries, Redis caches and every DB server are in today.
- Anything that enumerates a group generically rather than per-type —
az resource list -g, the Resource Management SDKs, drift/verification tooling that diffs deployed state against expected — sees an incomplete group and reports real resources as missing.
Root cause
ArmHandler.handleResourceGroupBranch builds the index from a hand-maintained set of subsystems plus Instance<ResourceIndexContributor>. The interface exists precisely so a service can opt in with one method, but only ACI ever did — every service added since (and every service that predates the interface) is silently absent.
Related, not covered here
GET /subscriptions/{sub}/resources (subscription-level) returns only Key Vaults and API Management services, so on an estate with neither it returns an empty list even when the subscription holds resources. Same family of gap, different endpoint; happy to file separately.
Environment
- floci-az version / image tag:
floci/floci-az@sha256:6566c73b8f4b6e3ef90322c8c84a47258bb1ca13c82ea1d40027f7af11247e30
- Also reproduced against
main at a9e4799 with a @QuarkusTest + RestAssured case
- How you're running floci-az: Docker, and
./mvnw test
Service
ARM (
Microsoft.Resources) — the resource-group resource index.Azure API Action
Resources - List By Resource Group—GET /subscriptions/{sub}/resourceGroups/{rg}/resources?api-version=2021-04-01Expected behavior
Real Azure returns every resource in the group, whatever provider owns it.
Actual behavior
The listing returns only the providers
ArmHandlerknows about: its own inline Storage / Key Vault / Web state, plus Network, API Management, Managed Identity, plus whatever implements the CDIResourceIndexContributorinterface — andAciHandleris currently the only implementation.So a resource group holding a VM comes back without the VM, even though the same VM answers a direct
GETwith200and appears in the type-scoped list under/providers/Microsoft.Compute/virtualMachines.Providers with a management plane in floci-az that never reach the index:
Microsoft.Compute/virtualMachinesVmHandlerMicrosoft.ContainerService/managedClustersAksHandlerMicrosoft.ContainerRegistry/registriesAcrHandlerMicrosoft.Cache/RedisRedisHandlerMicrosoft.DBforPostgreSQL/flexibleServersPostgresHandlerMicrosoft.DBforMySQL/flexibleServersMySqlHandlerMicrosoft.DBforMariaDB/serversMariaDbHandlerMicrosoft.Sql/serversSqlHandlerReproduction
Output on the pinned release above:
The storage account is there. The VM is not.
Impact
ResourceIndexContributor's own javadoc records why this listing matters: "The azurerm provider calls that listing before deleting a resource group to verify it is empty; a service that skips registration letsterraform destroyremove a group whose resources still exist." That is exactly the state VMs, AKS clusters, registries, Redis caches and every DB server are in today.az resource list -g, the Resource Management SDKs, drift/verification tooling that diffs deployed state against expected — sees an incomplete group and reports real resources as missing.Root cause
ArmHandler.handleResourceGroupBranchbuilds the index from a hand-maintained set of subsystems plusInstance<ResourceIndexContributor>. The interface exists precisely so a service can opt in with one method, but only ACI ever did — every service added since (and every service that predates the interface) is silently absent.Related, not covered here
GET /subscriptions/{sub}/resources(subscription-level) returns only Key Vaults and API Management services, so on an estate with neither it returns an empty list even when the subscription holds resources. Same family of gap, different endpoint; happy to file separately.Environment
floci/floci-az@sha256:6566c73b8f4b6e3ef90322c8c84a47258bb1ca13c82ea1d40027f7af11247e30mainata9e4799with a@QuarkusTest+ RestAssured case./mvnw test