-
Notifications
You must be signed in to change notification settings - Fork 523
/
ec2_host.go
140 lines (118 loc) 路 4.33 KB
/
ec2_host.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
package aws
import (
"fmt"
"strings"
"github.com/shopspring/decimal"
"github.com/infracost/infracost/internal/logging"
"github.com/infracost/infracost/internal/resources"
"github.com/infracost/infracost/internal/schema"
)
// EC2Host defines an AWS EC2 dedicated host. It supports multiple instance families & allows
// you to run workloads on a physical server dedicated for your use. You can use on-demand or
// reservation pricing.
//
// See more resource information here: https://aws.amazon.com/ec2/dedicated-hosts/
//
// See the pricing information here: https://aws.amazon.com/ec2/dedicated-hosts/pricing/
type EC2Host struct {
Address string
Region string
InstanceType string
InstanceFamily string
ReservedInstanceTerm *string `infracost_usage:"reserved_instance_term"`
ReservedInstancePaymentOption *string `infracost_usage:"reserved_instance_payment_option"`
}
func (r *EC2Host) CoreType() string {
return "EC2Host"
}
func (r *EC2Host) UsageSchema() []*schema.UsageItem {
return []*schema.UsageItem{
{Key: "reserved_instance_term", DefaultValue: "", ValueType: schema.String},
{Key: "reserved_instance_payment_option", DefaultValue: "", ValueType: schema.String},
}
}
func (r *EC2Host) PopulateUsage(u *schema.UsageData) {
resources.PopulateArgsWithUsage(r, u)
}
func (r *EC2Host) BuildResource() *schema.Resource {
purchaseOptionLabel := "on-demand"
priceFilter := &schema.PriceFilter{
PurchaseOption: strPtr("on_demand"),
}
var err error
if r.ReservedInstanceTerm != nil {
resolver := &ec2HostReservationResolver{
term: strVal(r.ReservedInstanceTerm),
paymentOption: strVal(r.ReservedInstancePaymentOption),
}
priceFilter, err = resolver.PriceFilter()
if err != nil {
logging.Logger.Warn().Msgf(err.Error())
}
purchaseOptionLabel = "reserved"
}
instanceFamily := r.InstanceFamily
if r.InstanceType != "" {
split := strings.Split(r.InstanceType, ".")
if len(split) > 0 {
instanceFamily = split[0]
}
}
hostPurchaseType := "HostUsage"
if purchaseOptionLabel == "reserved" {
hostPurchaseType = "ReservedHostUsage"
}
hostAttributeFilters := []*schema.AttributeFilter{
{Key: "usagetype", ValueRegex: regexPtr(fmt.Sprintf("%s:%s$", hostPurchaseType, instanceFamily))},
}
costComponents := []*schema.CostComponent{
{
Name: fmt.Sprintf("EC2 Dedicated Host (%s, %s)", purchaseOptionLabel, instanceFamily),
Unit: "hours",
UnitMultiplier: decimal.NewFromInt(1),
HourlyQuantity: decimalPtr(decimal.NewFromInt(1)),
ProductFilter: &schema.ProductFilter{
VendorName: strPtr("aws"),
Region: strPtr(r.Region),
Service: strPtr("AmazonEC2"),
ProductFamily: strPtr("Dedicated Host"),
AttributeFilters: hostAttributeFilters,
},
PriceFilter: priceFilter,
},
}
return &schema.Resource{
Name: r.Address,
UsageSchema: r.UsageSchema(),
CostComponents: costComponents,
}
}
type ec2HostReservationResolver struct {
term string
paymentOption string
}
// PriceFilter implementation for ec2HostReservationResolver
// Allowed values for ReservedInstanceTerm: ["1_year", "3_year"]
// Allowed values for ReservedInstancePaymentOption: ["all_upfront", "partial_upfront", "no_upfront"]
func (r ec2HostReservationResolver) PriceFilter() (*schema.PriceFilter, error) {
purchaseOptionLabel := "reserved"
def := &schema.PriceFilter{
PurchaseOption: strPtr(purchaseOptionLabel),
}
termLength := reservedTermsMapping[r.term]
purchaseOption := reservedHostPaymentOptionMapping[r.paymentOption]
validTerms := sliceOfKeysFromMap(reservedTermsMapping)
if !stringInSlice(validTerms, r.term) {
return def, fmt.Errorf("Invalid reserved_instance_term, ignoring reserved options. Expected: %s. Got: %s", strings.Join(validTerms, ", "), r.term)
}
validOptions := sliceOfKeysFromMap(reservedPaymentOptionMapping)
if !stringInSlice(validOptions, r.paymentOption) {
return def, fmt.Errorf("Invalid reserved_instance_payment_option, ignoring reserved options. Expected: %s. Got: %s", strings.Join(validOptions, ", "), r.paymentOption)
}
return &schema.PriceFilter{
PurchaseOption: strPtr(purchaseOptionLabel),
StartUsageAmount: strPtr("0"),
TermLength: strPtr(termLength),
TermPurchaseOption: strPtr(purchaseOption),
}, nil
}