Skip to content

feat: infracost v2, usage-aware deployml estimate#64

Draft
andrewtclim wants to merge 2 commits into
mainfrom
andrew/infracost-estimate
Draft

feat: infracost v2, usage-aware deployml estimate#64
andrewtclim wants to merge 2 commits into
mainfrom
andrew/infracost-estimate

Conversation

@andrewtclim

@andrewtclim andrewtclim commented Jun 16, 2026

Copy link
Copy Markdown

infracost v2: make deployml estimate actually useful

The problem

Right now deployml estimate prints $34.55 — 10 costed, 61 free, 71 total, which isn't helpful:

  • 50 of the 71 "resources" are just API-enablement flags, not things that cost money.
  • "costed" doesn't mean "costs money". 9 of the 10 were actually $0.
  • Infracost assumes zero usage by default, so Cloud Run, BigQuery, and GCS all show $0. The only real number is Cloud SQL, since it runs 24/7.

So the old estimate shows the cost of a deployment nobody uses, not what a student actually pays.

What I changed

deployml estimate now feeds infracost a realistic usage profile and prints a two-bucket breakdown:

  ~$35 / month   ($34.55 fixed  +  ~$0.92 usage)

  ALWAYS-ON  (billed 24/7 even if you never use the stack)
    $ 34.55  Cloud SQL    MLflow's backend database

  USAGE-BASED  (scales with activity · profile: light)
    $  0.44  BigQuery     prediction logging & analytics
    $  0.24  GCS Bucket   object / artifact storage
    $  0.24  Cloud Run    MLflow / FastAPI / Grafana

  Biggest lever: Cloud SQL is 97% of your cost and runs 24/7.

Main ideas:

  • --profile light|heavy (default light). Light is a typical student doing the coursework, heavy is a busy project (~10-20x), so students see both ends.
  • Two buckets: always-on (fixed, like Cloud SQL) vs usage-based (scales with activity), every line labelled in plain English.
  • A "biggest lever" line that points at the main cost driver.
  • The 61 free/API resources collapse into a single line instead of cluttering the output.

Files

  • utils/usage_profiles.py (new): the light/heavy usage numbers plus a helper to render them for infracost.
  • utils/infracost.py: the scan-with-usage flow, per-resource cost lookup, and the two-bucket display. Also pins infracost inspect --file <scan> so it reads back our scan instead of infracost's global "last scan" cache.
  • cli/cli.py: estimate gets --profile, plus a costs command for post-deploy.
  • tests/test_infracost.py: 22 tests, all passing.

Tested live

  • light ≈ $35 ($34.55 fixed + $0.92 usage), Cloud SQL is 97% of it.
  • heavy ≈ $53. The baseline doesn't move, only the usage line goes up, which is the point.

Follow-ups

  • The light/heavy numbers are reasonable assumptions, not measured from a real student. Fine for a pre-deploy estimate, but they're guesses.
  • Next: make deployml costs read the student's actual GCP usage (Cloud Run requests, GCS bytes, BigQuery bytes scanned) and give a real run-rate. That turns light/heavy into just labels ("you're a light user") instead of the pricing input.
  • Known issue: check_infracost_authenticated() only checks that a token file exists, so it still returns true for an expired token. Not fixed here.

…sts commands

- Rewrites infracost.py for v2 CLI (scan + inspect --json, dropped deprecated breakdown command)
- Adds deployml estimate: pre-deploy cost prediction from config, no GCP credentials needed
- Adds deployml costs: cost check against live deployed Terraform workspace
- Adds check_infracost_authenticated() with macOS + Linux credential path support
- Fixes copy_modules_to_workspace to include cloud_sql_postgres when mlflow uses postgresql
- Updates deployml doctor to show infracost install + auth status
- Adds 14 unit tests for infracost.py
- Updates docs/features/costs.md and tutorial with estimate/costs commands
Infracost defaults usage-based services (Cloud Run, BigQuery, GCS) to zero
usage, so the previous estimate only surfaced the always-on Cloud SQL cost
and showed $0 for everything else -- misleading for students.

The estimate command now feeds infracost a realistic usage profile
(--profile light|heavy, default light) and renders a two-bucket view:
ALWAYS-ON (fixed 24/7) vs USAGE-BASED (scales with activity), each line
labelled in plain English, plus a 'biggest lever' call-out.

- add usage_profiles.py: LIGHT/HEAVY dicts + render_usage_yaml()
- infracost.py: ResourceCost dataclass, run_infracost_scan_with_usage(),
  fetch_resource_costs_detailed(), display_estimate(), run_estimate_analysis();
  pin 'infracost inspect --file <scan>' instead of the global scan cache
- cli.py: estimate gains --profile and calls the new flow
- tests: 22 passing
@andrewtclim andrewtclim changed the title feat: infracost v2 support — deployml estimate and deployml costs feat: infracost v2, usage-aware deployml estimate Jul 14, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant