Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add monthly_hrs usage field for aws/azure/gcp VMs #1812

Merged
6 changes: 6 additions & 0 deletions Makefile
Expand Up @@ -75,6 +75,12 @@ test_cmd:
test_update_cmd:
INFRACOST_LOG_LEVEL=warn go test -timeout 30m $(LD_FLAGS) ./cmd/infracost $(or $(ARGS), -update -v -cover)

test_usage:
INFRACOST_LOG_LEVEL=warn go test -timeout 30m $(LD_FLAGS) ./internal/usage $(or $(ARGS), -v -cover)

test_update_usage:
INFRACOST_LOG_LEVEL=warn go test -timeout 30m $(LD_FLAGS) ./internal/usage $(or $(ARGS), -update -v -cover)

# Run AWS resource tests
test_aws:
INFRACOST_LOG_LEVEL=warn go test -timeout 30m $(LD_FLAGS) ./internal/providers/terraform/aws $(or $(ARGS), -v -cover)
Expand Down
7 changes: 7 additions & 0 deletions infracost-usage-example.yml
Expand Up @@ -232,6 +232,7 @@ resource_usage:
reserved_instance_payment_option: all_upfront # Payment option for Reserved Instances, can be: no_upfront, partial_upfront, all_upfront.
monthly_cpu_credit_hrs: 350 # Number of hours in the month where the instance is expected to burst. Only applicable with t2, t3 & t4 Instance types. T2 requires credit_specification to be unlimited.
vcpu_count: 2 # Number of the vCPUs for the instance type. Only applicable with t2, t3 & t4 Instance types. T2 requires credit_specification to be unlimited.
monthly_hrs: 450 # Monthly number of hours the instance ran for.

aws_fsx_windows_file_system.my_system:
backup_storage_gb: 10000 # Total storage used for backups in GB.
Expand Down Expand Up @@ -647,6 +648,9 @@ resource_usage:
google_compute_image.my_image:
storage_gb: 1000 # Total size of image storage in GB.

google_compute_instance.my_instance:
monthly_hrs: 450 # Monthly number of hours the instance ran for.

google_compute_machine_image.my_machine_image:
storage_gb: 1000 # Total size of machine image storage in GB.

Expand Down Expand Up @@ -965,6 +969,7 @@ resource_usage:
monthly_data_processed_gb: 100000 # Monthly data processed by the firewall in GB.

azurerm_linux_virtual_machine.my_linux_vm:
monthly_hrs: 450 # Monthly number of hours the instance ran for.
os_disk:
monthly_disk_operations: 2000000 # Number of disk operations (writes, reads, deletes) using a unit size of 256KiB.

Expand Down Expand Up @@ -1103,12 +1108,14 @@ resource_usage:
monthly_disk_operations: 100000 # Monthly number of disk operations (writes, reads, deletes) using a unit size of 256KiB per additional disk.

azurerm_virtual_machine.my_vm:
monthly_hrs: 450 # Monthly number of hours the instance ran for.
storage_os_disk:
monthly_disk_operations: 100000 # Monthly number of main disk operations (writes, reads, deletes) using a unit size of 256KiB.
storage_data_disk:
monthly_disk_operations: 100000 # Monthly number of disk operations (writes, reads, deletes) using a unit size of 256KiB per additional disk.

azurerm_windows_virtual_machine.my_windows_vm:
monthly_hrs: 450 # Monthly number of hours the instance ran for.
os_disk:
monthly_disk_operations: 2000000 # Number of disk operations (writes, reads, deletes) using a unit size of 256KiB.

Expand Down

Large diffs are not rendered by default.

Expand Up @@ -236,3 +236,20 @@ resource "aws_instance" "instance_withLaunchTemplateOverride" {
volume_size = 20
}
}

resource "aws_instance" "instance_withMonthlyHours" {
ami = "fake_ami"
instance_type = "t3.medium"
}

resource "aws_instance" "instance_ebsOptimized_withMonthlyHours" {
ami = "fake_ami"
instance_type = "r3.xlarge"
ebs_optimized = true
}

resource "aws_instance" "instance_detailedMonitoring_withMonthlyHours" {
ami = "fake_ami"
instance_type = "m3.large"
monitoring = true
}
Expand Up @@ -79,3 +79,12 @@ resource_usage:
aws_instance.instance_withLaunchTemplateOverride:
monthly_cpu_credit_hrs: 730
vcpu_count: 2

aws_instance.instance_withMonthlyHours:
monthly_hrs: 100

aws_instance.instance_ebsOptimized_withMonthlyHours:
monthly_hrs: 100

aws_instance.instance_detailedMonitoring_withMonthlyHours:
monthly_hrs: 100
Expand Up @@ -42,7 +42,7 @@ func aksClusterNodePool(name, region string, n gjson.Result, nodeCount decimal.D
Name: name,
}
instanceType := n.Get("vm_size").String()
costComponents = append(costComponents, linuxVirtualMachineCostComponent(region, instanceType))
costComponents = append(costComponents, linuxVirtualMachineCostComponent(region, instanceType, nil))
mainResource.CostComponents = costComponents
schema.MultiplyQuantities(mainResource, nodeCount)

Expand Down
22 changes: 16 additions & 6 deletions internal/providers/terraform/azure/linux_virtual_machine.go
Expand Up @@ -25,7 +25,12 @@ func NewAzureRMLinuxVirtualMachine(d *schema.ResourceData, u *schema.UsageData)

instanceType := d.Get("size").String()

costComponents := []*schema.CostComponent{linuxVirtualMachineCostComponent(region, instanceType)}
var monthlyHours *float64 = nil
if u != nil {
monthlyHours = u.GetFloat("monthly_hrs")
}

costComponents := []*schema.CostComponent{linuxVirtualMachineCostComponent(region, instanceType, monthlyHours)}

if d.Get("additional_capabilities.0.ultra_ssd_enabled").Bool() {
costComponents = append(costComponents, ultraSSDReservationCostComponent(region))
Expand All @@ -45,7 +50,7 @@ func NewAzureRMLinuxVirtualMachine(d *schema.ResourceData, u *schema.UsageData)
}
}

func linuxVirtualMachineCostComponent(region string, instanceType string) *schema.CostComponent {
func linuxVirtualMachineCostComponent(region string, instanceType string, monthlyHours *float64) *schema.CostComponent {
purchaseOption := "Consumption"
purchaseOptionLabel := "pay as you go"

Expand All @@ -56,11 +61,16 @@ func linuxVirtualMachineCostComponent(region string, instanceType string) *schem
instanceType = fmt.Sprintf("Standard_%s", instanceType)
}

qty := decimal.NewFromFloat(730)
if monthlyHours != nil {
qty = decimal.NewFromFloat(*monthlyHours)
}

return &schema.CostComponent{
Name: fmt.Sprintf("Instance usage (%s, %s)", purchaseOptionLabel, instanceType),
Unit: "hours",
UnitMultiplier: decimal.NewFromInt(1),
HourlyQuantity: decimalPtr(decimal.NewFromInt(1)),
Name: fmt.Sprintf("Instance usage (%s, %s)", purchaseOptionLabel, instanceType),
Unit: "hours",
UnitMultiplier: decimal.NewFromInt(1),
MonthlyQuantity: decimalPtr(qty),
ProductFilter: &schema.ProductFilter{
VendorName: strPtr("azure"),
Region: strPtr(region),
Expand Down
Expand Up @@ -18,7 +18,7 @@ func NewAzureRMLinuxVirtualMachineScaleSet(d *schema.ResourceData, u *schema.Usa

instanceType := d.Get("sku").String()

costComponents := []*schema.CostComponent{linuxVirtualMachineCostComponent(region, instanceType)}
costComponents := []*schema.CostComponent{linuxVirtualMachineCostComponent(region, instanceType, nil)}
subResources := make([]*schema.Resource, 0)

if d.Get("additional_capabilities.0.ultra_ssd_enabled").Bool() {
Expand Down
Expand Up @@ -13,6 +13,12 @@
├─ Storage (S4) 1 months $1.54
└─ Disk operations Monthly cost depends on usage: $0.0005 per 10k operations

azurerm_linux_virtual_machine.basic_b1_withMonthlyHours
├─ Instance usage (pay as you go, Standard_B1s) 100 hours $1.04
└─ os_disk
├─ Storage (S4) 1 months $1.54
└─ Disk operations Monthly cost depends on usage: $0.0005 per 10k operations

azurerm_linux_virtual_machine.standard_a2_ultra_enabled
├─ Instance usage (pay as you go, Standard_A2_v2) 730 hours $66.43
├─ Ultra disk reservation (if unattached) Monthly cost depends on usage: $4.38 per vCPU
Expand All @@ -31,7 +37,7 @@
└─ os_disk
└─ Storage (P4) 1 months $5.28

OVERALL TOTAL $357.95
OVERALL TOTAL $360.52
──────────────────────────────────
5 cloud resources were detected:
5 were estimated, all of which include usage-based costs, see https://infracost.io/usage-file
6 cloud resources were detected:
6 were estimated, all of which include usage-based costs, see https://infracost.io/usage-file
Expand Up @@ -137,3 +137,29 @@ resource "azurerm_linux_virtual_machine" "standard_a2_ultra_enabled" {
version = "latest"
}
}

resource "azurerm_linux_virtual_machine" "basic_b1_withMonthlyHours" {
name = "basic_b1"
resource_group_name = "fake_resource_group"
location = "eastus"

size = "Standard_B1s"
admin_username = "fakeuser"
admin_password = "fakepass"

network_interface_ids = [
"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/testrg/providers/Microsoft.Network/networkInterfaces/fakenic",
]

os_disk {
caching = "ReadWrite"
storage_account_type = "Standard_LRS"
}

source_image_reference {
publisher = "Canonical"
offer = "UbuntuServer"
sku = "16.04-LTS"
version = "latest"
}
}
Expand Up @@ -3,3 +3,5 @@ resource_usage:
azurerm_linux_virtual_machine.standard_a2_v2_custom_disk:
os_disk:
monthly_disk_operations: 20000
azurerm_linux_virtual_machine.basic_b1_withMonthlyHours:
monthly_hrs: 100
Expand Up @@ -8,6 +8,13 @@
├─ Storage (S4) 1 months $1.54
└─ Disk operations Monthly cost depends on usage: $0.0005 per 10k operations

azurerm_virtual_machine.linux_withMonthlyHours
├─ Instance usage (pay as you go, Standard_DS1_v2) 100 hours $7.30
├─ Ultra disk reservation (if unattached) Monthly cost depends on usage: $4.38 per vCPU
└─ storage_os_disk
├─ Storage (S4) 1 months $1.54
└─ Disk operations Monthly cost depends on usage: $0.0005 per 10k operations

azurerm_virtual_machine.windows
├─ Instance usage (pay as you go, Standard_DS1_v2) 730 hours $91.98
├─ Ultra disk reservation (if unattached) Monthly cost depends on usage: $4.38 per vCPU
Expand All @@ -27,10 +34,17 @@
├─ Provisioned IOPS 2,048 IOPS $101.66
└─ Throughput 8 MB/s $2.80

OVERALL TOTAL $385.16
azurerm_virtual_machine.windows_withMonthlyHours
├─ Instance usage (pay as you go, Standard_DS1_v2) 100 hours $12.60
├─ Ultra disk reservation (if unattached) Monthly cost depends on usage: $4.38 per vCPU
└─ storage_os_disk
├─ Storage (S4) 1 months $1.54
└─ Disk operations Monthly cost depends on usage: $0.0005 per 10k operations

OVERALL TOTAL $408.13
──────────────────────────────────
6 cloud resources were detected:
2 were estimated, all of which include usage-based costs, see https://infracost.io/usage-file
8 cloud resources were detected:
4 were estimated, all of which include usage-based costs, see https://infracost.io/usage-file
∙ 4 were free:
∙ 1 x azurerm_network_interface
∙ 1 x azurerm_resource_group
Expand Down
Expand Up @@ -61,8 +61,35 @@ resource "azurerm_virtual_machine" "linux" {
os_profile_linux_config {
disable_password_authentication = false
}
}

resource "azurerm_virtual_machine" "linux_withMonthlyHours" {
name = "vm"
location = azurerm_resource_group.main.location
resource_group_name = azurerm_resource_group.main.name
network_interface_ids = [azurerm_network_interface.main.id]
vm_size = "Standard_DS1_v2"

storage_image_reference {
publisher = "Canonical"
offer = "UbuntuServer"
sku = "16.04-LTS"
version = "latest"
}
storage_os_disk {
name = "myosdisk1"
caching = "ReadWrite"
create_option = "FromImage"
managed_disk_type = "Standard_LRS"
}
os_profile {
computer_name = "hostname"
admin_username = "testadmin"
admin_password = "Password1234!"
}
os_profile_linux_config {
disable_password_authentication = false
}
}

resource "azurerm_virtual_machine" "windows" {
Expand Down Expand Up @@ -113,3 +140,24 @@ resource "azurerm_virtual_machine" "windows" {
lun = 4
}
}

resource "azurerm_virtual_machine" "windows_withMonthlyHours" {
name = "vm"
location = azurerm_resource_group.main.location
resource_group_name = azurerm_resource_group.main.name
network_interface_ids = [azurerm_network_interface.main.id]
vm_size = "Standard_DS1_v2"

storage_os_disk {
name = "myosdisk1"
caching = "ReadWrite"
create_option = "FromImage"
managed_disk_type = "Standard_LRS"
os_type = "Windows"
}
os_profile {
computer_name = "hostname"
admin_username = "testadmin"
admin_password = "Password1234!"
}
}
Expand Up @@ -5,3 +5,7 @@ resource_usage:
monthly_disk_operations: 1000000
storage_data_disk:
monthly_disk_operations: 2000000
azurerm_virtual_machine.linux_withMonthlyHours:
monthly_hrs: 100
azurerm_virtual_machine.windows_withMonthlyHours:
monthly_hrs: 100
Expand Up @@ -13,6 +13,12 @@
├─ Storage (S4) 1 months $1.54
└─ Disk operations Monthly cost depends on usage: $0.0005 per 10k operations

azurerm_windows_virtual_machine.basic_a2_withMonthlyHours
├─ Instance usage (pay as you go, Basic_A2) 100 hours $13.30
└─ os_disk
├─ Storage (S4) 1 months $1.54
└─ Disk operations Monthly cost depends on usage: $0.0005 per 10k operations

azurerm_windows_virtual_machine.standard_a2_ultra_enabled
├─ Instance usage (pay as you go, Standard_A2_v2) 730 hours $99.28
├─ Ultra disk reservation (if unattached) Monthly cost depends on usage: $4.38 per vCPU
Expand All @@ -37,7 +43,7 @@
└─ os_disk
└─ Storage (P4) 1 months $5.28

OVERALL TOTAL $1,943.37
OVERALL TOTAL $1,958.20
──────────────────────────────────
6 cloud resources were detected:
6 were estimated, all of which include usage-based costs, see https://infracost.io/usage-file
7 cloud resources were detected:
7 were estimated, all of which include usage-based costs, see https://infracost.io/usage-file
Expand Up @@ -167,3 +167,29 @@ resource "azurerm_windows_virtual_machine" "Standard_E16-8as_v4" {
version = "fake"
}
}

resource "azurerm_windows_virtual_machine" "basic_a2_withMonthlyHours" {
name = "basic_a2"
resource_group_name = "fake_resource_group"
location = "eastus"

size = "Basic_A2"
admin_username = "fakeuser"
admin_password = "fakepass"

network_interface_ids = [
"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/testrg/providers/Microsoft.Network/networkInterfaces/fakenic",
]

os_disk {
caching = "ReadWrite"
storage_account_type = "Standard_LRS"
}

source_image_reference {
publisher = "MicrosoftWindowsServer"
offer = "WindowsServer"
sku = "2016-Datacenter"
version = "latest"
}
}
Expand Up @@ -3,3 +3,5 @@ resource_usage:
azurerm_windows_virtual_machine.standard_a2_v2_custom_disk:
os_disk:
monthly_disk_operations: 20000
azurerm_windows_virtual_machine.basic_a2_withMonthlyHours:
monthly_hrs: 100
10 changes: 8 additions & 2 deletions internal/providers/terraform/azure/virtual_machine.go
Expand Up @@ -32,13 +32,19 @@ func NewAzureRMVirtualMachine(d *schema.ResourceData, u *schema.UsageData) *sche
os = "Windows"
}

var monthlyHours *float64 = nil
if u != nil {
monthlyHours = u.GetFloat("monthly_hrs")
}

if strings.ToLower(os) == "windows" {
licenseType := d.Get("license_type").String()
costComponents = append(costComponents, windowsVirtualMachineCostComponent(region, instanceType, licenseType))
costComponents = append(costComponents, windowsVirtualMachineCostComponent(region, instanceType, licenseType, monthlyHours))
} else {
costComponents = append(costComponents, linuxVirtualMachineCostComponent(region, instanceType))
costComponents = append(costComponents, linuxVirtualMachineCostComponent(region, instanceType, monthlyHours))
}

// TODO: is this always assuming ultrassdreservation cost?
costComponents = append(costComponents, ultraSSDReservationCostComponent(region))

var storageOperations *decimal.Decimal
Expand Down