Files
orca/cloud/apps/relay-ops/src/cost-model.ts
Jinwoo Hong 3eec77c11a chore(cloud): add the relay fence broker, ops console, Terraform root, scripts, and 24 cloud-* workflows (#18413)
Phase 6 of the relay split: the relay's deploy/operate surface moves under cloud/ with 24 cloud-* workflows gated on ORCA_CLOUD_OPERATIONS_ENABLED, the Cloud SQL rollout lease action, the relay Terraform root (dual-accept identities for both repositories), scripts, docs, CODEOWNERS, and a terraform validate job in Cloud Verify.
2026-09-03 06:55:14 -04:00

116 lines
3.6 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import type {
RelayOpsEnvironment,
RelayOpsMachineType,
RelayOpsRegion
} from './environment-config.js'
import type { ResourceInventory } from './resource-inventory.js'
export type CostLine = {
label: string
monthlyUsd: number
basis: string
}
export type CostModel = {
kind: 'planning-estimate'
monthlyUsd: number
rangeUsd: [number, number]
actualBilling: { available: false; reason: string }
lines: CostLine[]
caveats: string[]
}
const HOURS_PER_MONTH = 730
const MACHINE_HOURLY_USD: Record<
RelayOpsRegion,
Record<RelayOpsMachineType, number>
> = {
'us-central1': {
'e2-standard-2': 0.06701142,
'e2-standard-4': 0.13402284
},
'asia-east2': {
'e2-standard-2': 0.0938,
'e2-standard-4': 0.1875
}
}
const SHARED_NETWORK_FLOOR_USD = 19
const REGIONAL_NAT_FLOOR_USD = 5
function round(value: number): number {
return Math.round(value * 100) / 100
}
export function buildCostModel(
environment: RelayOpsEnvironment,
resources: ResourceInventory
): CostModel {
const runningCells = resources.cells.filter((cell) => (cell.targetSize ?? 0) > 0)
const runningCellCount = runningCells.reduce((sum, cell) => sum + (cell.targetSize ?? 0), 0)
const compute = runningCells.reduce(
(sum, cell) =>
sum + (cell.targetSize ?? 0) * MACHINE_HOURLY_USD[cell.region][cell.machineType],
0
) * HOURS_PER_MONTH
const disks = runningCellCount * 30 * 0.1
const sqlRunning = resources.sql?.activationPolicy === 'ALWAYS'
const sql = sqlRunning ? (environment.id === 'production' ? 105 : 52) : 0
const cloudRunMinimums =
(resources.director?.minInstances ?? 0) + (resources.auth?.minInstances ?? 0)
const cloudRun = cloudRunMinimums * 10
const configuredRegions = new Set(
(resources.cells.length > 0 ? resources.cells : environment.cells).map((cell) => cell.region)
)
const networkFoundation =
SHARED_NETWORK_FLOOR_USD + configuredRegions.size * REGIONAL_NAT_FLOOR_USD
const observability = environment.id === 'production' ? 12 : 5
const lines: CostLine[] = [
{
label: 'Relay cell VMs',
monthlyUsd: round(compute),
basis: `${runningCellCount} configured VM cells at regional machine rates × 730 hours`
},
{
label: 'Cell boot disks',
monthlyUsd: round(disks),
basis: `${runningCellCount} × 30 GB balanced persistent disk`
},
{
label: 'Cloud SQL',
monthlyUsd: sql,
basis: sqlRunning ? `${resources.sql?.tier ?? 'configured tier'} active` : 'stopped'
},
{
label: 'Cloud Run minimums',
monthlyUsd: cloudRun,
basis: `${cloudRunMinimums} configured minimum instances`
},
{
label: 'Load balancer and network floor',
monthlyUsd: networkFoundation,
basis: `shared HTTPS foundation plus NAT floor in ${configuredRegions.size} configured region${configuredRegions.size === 1 ? '' : 's'}`
},
{
label: 'Logs and monitoring allowance',
monthlyUsd: observability,
basis: 'planning allowance; varies with traffic and retention'
}
]
const monthlyUsd = round(lines.reduce((sum, line) => sum + line.monthlyUsd, 0))
return {
kind: 'planning-estimate',
monthlyUsd,
rangeUsd: [round(monthlyUsd * 0.85), round(monthlyUsd * 1.3)],
actualBilling: {
available: false,
reason: 'Cloud Billing export is not configured in either Relay project.'
},
lines,
caveats: [
'This is a modeled run-rate, not the Cloud Billing invoice.',
'Network egress, actual request traffic, credits, discounts, taxes, and free tiers are excluded.',
'Use the GCP Billing report for authoritative spend and forecasts.'
]
}
}