Always-on / fixed infrastructure (Terraform)¶
Source: examples/always-on-infrastructure.yaml
To check and price this model from a clone of the repository:
infra-cost-model validate examples/always-on-infrastructure.yaml
infra-cost-model compute --time-basis monthly examples/always-on-infrastructure.yaml
# Example: Always-on / fixed infrastructure (Terraform)
# Demonstrates Issue #196:
# - Per-metric `fixed` flags: one node carries BOTH a fixed monthly dimension
# and a usage-driven dimension (NAT gateway hours + GB processed; ALB-hours
# + LCUs) without splitting into two nodes.
# - Always-on nodes: a fixed resource (Secrets Manager secret) is costed
# without a synthetic incoming edge and emits no unreachable warning.
# - No spurious DP#9 conflict: a mixed node may receive DAG edges; the warning
# fires only for a fully-fixed node that also receives edges.
#
# Issue: https://github.com/elecnix/infra-cost-model/issues/196
version: "1.0"
workflow:
name: always-on-web-api
entry: aws_lb.main
frequency:
unit: perMinute
value: 1000
nodes:
# Entry: Application Load Balancer. Mixed — fixed ALB-hours plus usage-driven
# LCUs. Being the entry node it has no incoming edge, so no DP#9 conflict.
aws_lb.main:
nodeType: routing
resourceAddress: aws_lb.main
provider: aws
service: AmazonALB
region: us-east-1
usageMetrics:
albHours: { unit: hours, value: 730, fixed: true } # always-on, $/month
# One LCU-hour covers 25 new connections a second for an hour, or
# 90,000 connections. One request opens one connection: 1/90,000.
newConnections: { unit: LCU-hours, value: 0.0000111111 }
aws_lambda_function.api:
nodeType: compute
resourceAddress: aws_lambda_function.api
provider: aws
service: AWSLambda
region: us-east-1
usageMetrics:
invocations: { unit: requests, value: 1 }
avgDurationMs: { unit: ms, value: 500 }
memoryMb: { unit: MB, value: 256 }
aws_dynamodb_table.data:
nodeType: storage
resourceAddress: aws_dynamodb_table.data
provider: aws
service: AmazonDynamoDB
region: us-east-1
usageMetrics:
readRequests: { unit: requests, value: 1 }
# NAT gateway: mixed — fixed gateway-hours plus usage-driven GB processed.
# It DOES receive an edge (egress flows through it), and because only one of
# its metrics is fixed there is no DP#9 conflict.
aws_nat_gateway.main:
nodeType: routing
resourceAddress: aws_nat_gateway.main
provider: aws
service: AmazonVPC
region: us-east-1
usageMetrics:
# The NAT gateway handler maps these names to the catalog metrics
# NAT-Gateway-Hour and NAT-Gateway-DataProcessed.
natHours: { unit: hours, value: 730, fixed: true } # always-on, $/month
dataProcessedGb: { unit: GB, value: 0.00005 } # ~50KB/req, scales with traffic
# Secrets Manager secret: a purely fixed, always-on resource. It has NO
# incoming edge — it is costed anyway and emits no unreachable warning.
aws_secretsmanager_secret.api_key:
nodeType: storage
resourceAddress: aws_secretsmanager_secret.api_key
provider: aws
service: AWSSecretsManager
region: us-east-1
usageMetrics:
# The handler maps secretsCount to the catalog metric SecretsManager-Secret.
secretsCount: { unit: secrets, value: 1, fixed: true }
edges:
- { from: aws_lb.main, to: aws_lambda_function.api, rate: 1.0 }
- { from: aws_lambda_function.api, to: aws_dynamodb_table.data, rate: 1.0, type: read }
- { from: aws_lambda_function.api, to: aws_nat_gateway.main, rate: 1.0 }