Deallocated Azure VM Residual Cost
What does ZopNight detect here?
Deallocated standalone Azure VMs bill $0 for compute yet keep charging for attached managed disks and public IPs. Savings sum the priced monthly cost of those residual children, itemised into disk and IP components; the rule abstains when no child matches or every child is unpriced.
Signal and threshold
| Field | Value |
|---|---|
| Rule IDs | RC-1384 |
| Category | orphan |
| Severity | low |
| Metric | none — pure configuration read |
| Source | deallocated_vm_residual.go |
Where it applies
Deallocated, standalone, and still billing children
Azure VM with Status = deallocated (compute billing stopped) and no ParentUID (standalone, not a VMSS member). The Azure analog of GCP RC-109 / AWS RC-001.
- resource.Status: must be deallocated (a merely stopped/not-deallocated VM still bills compute, so the residual-only basis does not apply).
- resource.ParentUID: empty (standalone).
- ResourceContextAware (SetResources) + PricingAware (SetPricing): the org resource set + per-UID monthly cost, to find and price the VM’s residual children.
- Child association: managed disk already carries ParentUID = managedBy (the VM); public-ip carries ParentUID = VM via the discoverer’s public-ip → NIC → VM ARG join (applyPublicIPLookupSets).
Adding up the disks and public IPs left behind
concrete-or-abstain (Category orphan, exempt from shouldDropLowSavings). Compute is $0 for a deallocated VM, so the deletable saving is the residual: Σ cost[child] over attached managed disks + public IPs (gated by the shared model.IsResidualCostChildType). CurrentCostUSD = SavingsUSD = residual, OptimizedCostUSD = 0. SavingsBreakdown itemises the residual into Managed disk + Public IP components (summing to SavingsUSD) for the UI. The child↔VM ParentUID match is case-insensitive (Azure returns the VM id and its children’s cross-ref ids with divergent resourceGroup casing). The rule abstains when resources/pricing were not injected, no child matched, or every child is unpriced, and never emits a $0 or advisory rec. Disjoint from RC-1380 (RI/SP commitment, compute-domain) and idle_vm.go (running VMs only).
Deleting the leftovers, or starting the VM
- Check whether the VM is intentionally deallocated (e.g., a long-running batch worker).
- If no longer needed, delete the VM, then its non-auto-delete managed disks.
- Release/delete any Standard public IP associated with the VM (it bills while allocated).
- If it should be running, start it (az vm start).