MCPcopy Index your code
hub / github.com/cycloidio/terracost

github.com/cycloidio/terracost @v1.13.5-cy

Chat with this repo
repository ↗ · DeepWiki ↗ · release v1.13.5-cy ↗ · + Follow
652 symbols 2,461 edges 177 files 446 documented · 68%
What it actually does AI analysis from the code graph — generated when you open this
loading…
README

TerraCost logo

TerraCost

PkgGoDev

Go library for estimating Terraform costs using ingested cloud vendor prices. It is meant to be imported and used by programs (API's or standalone) with access to a MySQL-compatible database and the Internet.

Installation

go mod edit -replace github.com/hashicorp/terraform=github.com/cycloidio/terraform@v1.13.5-cy \
  && go mod edit -replace github.com/gruntwork-io/terragrunt=github.com/cycloidio/terragrunt@terraform-cy-v1.13.5 \
  && go get github.com/cycloidio/terracost

We need to do a -replace because of https://github.com/golang/go/issues/30354#issuecomment-466557015. We have custom forks of Terraform and Terragrunt and in order to use TerraCost they need to be replaced when importing also.

Requirements

  • Go 1.25 or newer
  • MySQL database

Provider support

Currently Terracost supports the following providers and with an specific subset of resources from them: * AWS * Google * AzureRM

Google Credentials

To be able to ingest the pricing data from Google the credentials needed have to have access to Compute Engine API and have also billing enabled. This is needed to be able to fetch the Machine Types, for the SKUs we would only need an normal set of credentials (or even API Key) but as we need both we have to use the more complex one. If you do not know how to activate those permissions, just use the credentials and the import will fail and on the logs will inform of what is missing and how to activate it.

Usage

Migrating the database

db, err := sql.Open("mysql", "root:password@tcp(IP:3306)/databasename?multiStatements=true")

// Can be called on every start of your program, it does nothing if the migrations
// have been executed already.
err = mysql.Migrate(context.Background(), db, "pricing_migrations")

Ingesting pricing data

db, err := sql.Open("mysql", "root:password@tcp(IP:3306)/databasename?multiStatements=true")
backend := mysql.NewBackend(db)

// service can be "AmazonEC2" or "AmazonRDS"
// region is any AWS region, e.g. "us-east-1" or "eu-west-3"
ingester, err := aws.NewIngester(service, region)
err = terracost.IngestPricing(context.Background(), backend, ingester)

Tracking ingestion progress

We're using the github.com/machinebox/progress library for tracking ingestion progress.

  1. Create a channel that will receive progress updates and set up a goroutine (it will print the bytes ingested out of bytes total and remaining time each time progress update is sent on the channel):
progressCh := make(chan progress.Progress, 0)

go func() {
    for p := range progressCh {
        // Check the docs for all available methods: https://pkg.go.dev/github.com/machinebox/progress#Progress
        fmt.Printf("%d / %d (%s remaining)\n", p.N(), p.Size(), p.Remaining().String())
    }
}()
  1. Initialize an ingester capable of tracking progress (in this example the channel will receive an update every 5 seconds):
ingester, err := aws.NewIngester(service, region, aws.WithProgress(progressCh, 5*time.Second))
  1. Use the ingester as in the previous section.

Estimating a Terraform plan

Plan estimation is possible after all the relevant pricing data have been ingested and stored in the database.

  1. Generate a plan using terraform and convert it to JSON:
terraform plan -out update.tfplan
terraform show -json update.tfplan > tfplan.json
  1. Read the plan file, estimate it and show the resource differences:
db, err := db.Open("mysql", "...")
backend := mysql.NewBackend(db)

file, err := os.Open("path/to/tfplan.json")
plan, err := terracost.EstimateTerraformPlan(context.Background(), backend, file)

for _, res := range plan.ResourceDifferences() {
  priorCost, err := res.PriorCost()
  plannedCost, err := res.PlannedCost()

  fmt.Printf("%s: %s -> %s\n", res.Address, priorCost, plannedCost)
}

Check the documentation for all available fields.

Usage estimation

Some resources do cannot be estimated just by the configuration and need some extra usage information, for that we have some default on usage/usage.go which are also all the resources and options we support currently and can be overwritten when estimating if passing a custom one instead of the custom Default one.

Examples

For more examples, please check examples.

Contributing

For Contributing Guide, please read CONTIBUTING.md.

License

This project is licensed under the MIT license. Please see LICENSE for more details.

Meet Cycloid

Cycloid is a hybrid cloud DevOps collaboration platform providing end-to-end frameworks to accelerate and industrialize software delivery.

As of now, we have three open-source tools:

  • TerraCognita: Read from your existing cloud providers and generate IaC in Terraform
  • InfraMap: Reads .tfstate or HCL to generate a graph specific for each provider
  • TerraCost: Cloud cost estimation for Terraform in the CLI

...and the functionality of each is also embedded in our DevOps solution, which you can find out more about here.

Extension points exported contracts — how you extend this code

Ingester (Interface)
go:generate mockgen -destination=mock/ingester.go -mock_names=Ingester=Ingester -package mock github.com/cycloidio/terra [5 …
ingestion.go
Provider (Interface)
go:generate mockgen -destination=../mock/terraform_provider.go -mock_names=Provider=TerraformProvider -package mock gith [5 …
terraform/provider.go
Backend (Interface)
go:generate mockgen -destination=../mock/backend.go -mock_names=Backend=Backend -package mock github.com/cycloidio/terra [3 …
backend/backend.go
HTTPClient (Interface)
go:generate mockgen -destination=../mock/http_client.go -mock_names=HTTPClient=HTTPClient -package mock github.com/cyclo [2 …
aws/options.go
Repository (Interface)
go:generate mockgen -destination=../mock/product_repository.go -mock_names=Repository=ProductRepository -package mock gi
product/repository.go
Repository (Interface)
go:generate mockgen -destination=../mock/price_repository.go -mock_names=Repository=PriceRepository -package mock github
price/repository.go
IngestionFilter (FuncType)
IngestionFilter allows control over what pricing data is ingested. Given a price.WithProduct the function returns true i
google/filter.go
Option (FuncType)
Option is used to configure the Ingester.
google/option.go

Core symbols most depended-on inside this repo

StringPtr
called by 1286
util/util.go
NewMonthly
called by 73
cost/cost.go
String
called by 54
aws/region/code.go
ResourceComponents
called by 52
aws/terraform/provider.go
Components
called by 27
aws/terraform/lb.go
GetUsage
called by 24
usage/usage.go
String
called by 21
mysql/filters.go
PlannedCost
called by 21
cost/plan.go

Shape

Method 267
Function 228
Struct 139
FuncType 6
Interface 6
TypeAlias 6

Languages

Go100%

Modules by API surface

terraform/plan.go15 symbols
terraform/hcl.go12 symbols
terraform/schema.go11 symbols
azurerm/terraform/managed_disk.go11 symbols
mock/product_repository.go10 symbols
mock/price_repository.go10 symbols
aws/terraform/rds_cluster.go10 symbols
mysql/product.go9 symbols
mysql/price.go9 symbols
aws/terraform/rds_cluster_instance.go9 symbols
aws/terraform/instance.go9 symbols
aws/terraform/efs_file_system.go9 symbols

Datastores touched

(mysql)Database · 1 repos

For agents

$ claude mcp add terracost \
  -- python -m otcore.mcp_server <graph>

⬇ download graph artifact

Ask about this repo answers extend the page