feat: infracost v2, usage-aware deployml estimate#64
Draft
andrewtclim wants to merge 2 commits into
Draft
Conversation
…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
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
infracost v2: make
deployml estimateactually usefulThe problem
Right now
deployml estimateprints$34.55 — 10 costed, 61 free, 71 total, which isn't helpful:So the old estimate shows the cost of a deployment nobody uses, not what a student actually pays.
What I changed
deployml estimatenow feeds infracost a realistic usage profile and prints a two-bucket breakdown: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.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 pinsinfracost inspect --file <scan>so it reads back our scan instead of infracost's global "last scan" cache.cli/cli.py:estimategets--profile, plus acostscommand for post-deploy.tests/test_infracost.py: 22 tests, all passing.Tested live
Follow-ups
deployml costsread 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.check_infracost_authenticated()only checks that a token file exists, so it still returns true for an expired token. Not fixed here.