Idle GCP VM Instance
What does ZopNight detect here?
GCE VMs averaging below 5% CPU over 30 days receive a recurring off-hours schedule when the aggregator's heatmap measures a real idle window; savings equal cost times that measured idle percentage. Critical-role and stateful- workload names are vetoed, and missing schedule data or pricing means the rule abstains.
Signal and threshold
| Field | Value |
|---|---|
| Rule IDs | RC-102 |
| Category | schedule |
| Severity | medium |
| Metric | none — pure configuration read |
| Source | idle_vm.go |
Where it applies
CPU idleness plus the DR and database vetoes
- resource.Status: statusTerminated
- MetricsAware (SetMultiMetrics): gcpCPUMetricName (CPUUtilization) read by name off the nested UID→metricName view over gcpCPULookbackDays days (Bug-1: compute harvests 9 metrics, so a bare-UID read would be CPU only ~1/9 of the time); abstains when the named series is absent.
- ScheduleAware (SetScheduleData): the aggregator’s heatmap-derived model.ScheduleData (same RC-093/RC-110 path) keyed by UID, carrying the measured off-hours IdlePercentage.
- Skip when the VM already carries a schedule tag (intentionally parked, not abandoned).
- Critical-role veto (matchesCriticalRole, shared with RC-110/RC-111): abstains on a DR/backup/standby-named VM, which must stay ready to absorb production traffic on failover even when CPU-idle.
- Stateful-workload veto (matchesStatefulWorkload, shared with RC-110/RC-111): abstains on a self-managed database/cache/broker VM (via discoverer engine/tier Metadata, data-tier Tags, or a boundary-matched name token): the heatmap’s CPU/inbound-network/disk idle window cannot prove a durable-state, typically single-replica service is safe to park.
A 5% CPU floor over 30 days
gcpCPUThreshold=5.0, gcpCPULookbackDays=30Savings scaled by the measured off-hours window
concrete-or-abstain (cost-driven schedule). When the VM is CPU-idle, is not a critical-role/stateful-workload VM, and the aggregator’s heatmap shows a measured off-hours window, savings = cost × ScheduleData[uid].IdlePercentage, optimized = cost − savings; the lever is a recurring off-hours schedule (never a one-shot stop/terminate, never a single-axis CPU rightsize since memory is unobservable on GCE). The rule abstains (returns nil) when pricing is unknown/zero, no measured schedule data exists, or the critical-role/stateful-workload veto fires. There is no $0 advisory and no fabricated flat fraction. (Was previously documented as advisory/$0; reworked under the 2026-06-27 concrete-or-abstain directive; critical-role/stateful-workload vetoes added to close the gap where RC-102 was the only sibling of RC-110/RC-111 without them.)
Applying the recurring off-hours schedule
- Review the recommended off-hours schedule (Start / Stop / Timezone)
- Apply it from this recommendation (recurring off-hours park, not a one-shot stop)
A single CPU series read by name
gcpCPUMetricName (gcpCPULookbackDays day lookback)