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

Add support for Watson Discovery resource #164

Merged
merged 11 commits into from
Apr 22, 2024
17 changes: 17 additions & 0 deletions infracost-usage-example.yml
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,11 @@ resource_type_default_usage:
wa_instance: 1
wa_monthly_active_users: 1001
wa_voice_users: 101
wd_instance: 1
wd_documents: 11000
wd_queries: 11000
wd_custom_models: 4
wd_collections: 301
ibm_tg_gateway:
connection: 3
data_transfer_global: 1000
Expand Down Expand Up @@ -1303,6 +1308,18 @@ resource_usage:
wa_monthly_active_users: 1100 # The number of monthly active users
wa_monthly_voice_users: 100 # The number of monthly active voice users

ibm_resource_instance.watson_discovery_plus:
wd_instance: 1 # Number of instances used per month
wd_documents: 11000 # Number of monthly documents created; 10,000 included in the Plus plan; $50 for every additional 1,000 documents.
wd_queries: 11000 # Number of queries documents created; 10,000 included in the Plus plan; $20 for every additional 1,000 queries.

ibm_resource_instance.watson_discovery_enterprise:
wd_instance: 1 # Number of instances used per month
wd_documents: 101000 # Number of monthly documents created; 100,000 included in the Enterprise plan; $5 for every additional 1,000 documents.
wd_queries: 101000 # Number of queries documents created; 100,000 included in the Enterprise plan; $5 for every additional 1,000 queries.
wd_custom_models: 4 # Number of monthly custom models created; 3 included in the Enterprise plan; $500 for every additional custom model.
wd_collections: 301 # Number of monthly collections created; 300 included in the Enterprise plan. $500 for every additional 100 collections.

ibm_tg_gateway.tg_gateway:
connection: 25 # Monthly number of connections to the gateway
data_transfer_local: 2500 # Monthly local traffic through the gateway in GB
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,18 @@
ibm_resource_instance.wa_instance_trial
└─ Trial 1 $0.00

ibm_resource_instance.watson_discovery_enterprise
├─ Instance 1 Instance $5,000.00
├─ Additional Monthly Documents 1,000 Documents $5.00
├─ Additional Monthly Queries 1,000 Queries $5.00
├─ Additional Monthly Custom Models 1 Custom Models $500.00
└─ Additional Monthly Collections 1 Hundred Collections $500.00

ibm_resource_instance.watson_discovery_plus
├─ Instance 1 Instance $500.00
├─ Additional Monthly Documents 1,000 Documents $50.00
└─ Additional Monthly Queries 1,000 Queries $20.00

ibm_resource_instance.wml_instance_essentials
├─ Capacity Unit-Hours 20 CUH $10.40
├─ Class 1 Resource Units 50 RU $0.03
Expand All @@ -105,7 +117,7 @@
├─ Class 2 Resource Units 50 RU $0.09
└─ Class 3 Resource Units 50 RU $0.25

OVERALL TOTAL $8,880.14
OVERALL TOTAL $15,460.14
──────────────────────────────────
23 cloud resources were detected:
23 were estimated, all of which include usage-based costs, see https://infracost.io/usage-file
25 cloud resources were detected:
25 were estimated, all of which include usage-based costs, see https://infracost.io/usage-file
Original file line number Diff line number Diff line change
Expand Up @@ -184,3 +184,19 @@ resource "ibm_resource_instance" "wa_instance_enterprise" {
location = "us-south"
resource_group_id = "default"
}

resource "ibm_resource_instance" "watson_discovery_plus" {
name = "wd_plus"
service = "discovery"
plan = "plus"
location = "us-south"
resource_group_id = "default"
}

resource "ibm_resource_instance" "watson_discovery_enterprise" {
name = "wd_enterprise"
service = "discovery"
plan = "enterprise"
location = "us-south"
resource_group_id = "default"
}
Original file line number Diff line number Diff line change
Expand Up @@ -55,4 +55,16 @@ resource_usage:
ibm_resource_instance.wa_instance_enterprise:
wa_instance: 1
wa_monthly_active_users: 51000
wa_voice_users: 1000
wa_voice_users: 1000

ibm_resource_instance.watson_discovery_plus:
wd_instance: 1 # Number of instances used per month
wd_documents: 11000 # Number of monthly documents created; 10,000 included in the Plus plan; $50 for every additional 1,000 documents.
wd_queries: 11000 # Number of queries documents created; 10,000 included in the Plus plan; $20 for every additional 1,000 queries.

ibm_resource_instance.watson_discovery_enterprise:
wd_instance: 1 # Number of instances used per month
wd_documents: 101000 # Number of monthly documents created; 100,000 included in the Enterprise plan; $5 for every additional 1,000 documents.
wd_queries: 101000 # Number of queries documents created; 100,000 included in the Enterprise plan; $5 for every additional 1,000 queries.
wd_custom_models: 4 # Number of monthly custom models created; 3 included in the Enterprise plan; $500 for every additional custom model.
wd_collections: 301 # Number of monthly collections created; 300 included in the Enterprise plan. $500 for every additional 100 collections.
12 changes: 12 additions & 0 deletions internal/resources/ibm/resource_instance.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,12 @@ type ResourceInstance struct {
WA_Instance *float64 `infracost_usage:"wa_instance"`
WA_mau *float64 `infracost_usage:"wa_monthly_active_users"`
WA_vu *float64 `infracost_usage:"wa_voice_users"`
// Watson Discovery
WD_Instance *float64 `infracost_usage:"wd_instance"`
WD_Documents *float64 `infracost_usage:"wd_documents"`
WD_Queries *float64 `infracost_usage:"wd_queries"`
WD_CustomModels *float64 `infracost_usage:"wd_custom_models"`
WD_Collections *float64 `infracost_usage:"wd_collections"`
}

type ResourceCostComponentsFunc func(*ResourceInstance) []*schema.CostComponent
Expand Down Expand Up @@ -105,6 +111,11 @@ var ResourceInstanceUsageSchema = []*schema.UsageItem{
{Key: "wa_instance", DefaultValue: 0, ValueType: schema.Float64},
{Key: "wa_monthly_active_users", DefaultValue: 0, ValueType: schema.Float64},
{Key: "wa_voice_users", DefaultValue: 0, ValueType: schema.Float64},
{Key: "wd_instance", DefaultValue: 0, ValueType: schema.Float64},
{Key: "wd_documents", DefaultValue: 0, ValueType: schema.Float64},
{Key: "wd_queries", DefaultValue: 0, ValueType: schema.Float64},
{Key: "wd_custom_models", DefaultValue: 0, ValueType: schema.Float64},
{Key: "wd_collections", DefaultValue: 0, ValueType: schema.Float64},
}

var ResourceInstanceCostMap map[string]ResourceCostComponentsFunc = map[string]ResourceCostComponentsFunc{
Expand All @@ -119,6 +130,7 @@ var ResourceInstanceCostMap map[string]ResourceCostComponentsFunc = map[string]R
"continuous-delivery": GetContinuousDeliveryCostComponenets,
"pm-20": GetWMLCostComponents,
"conversation": GetWACostComponents,
"discovery": GetWDCostComponents,
}

func KMSKeyVersionsFreeCostComponent(r *ResourceInstance) *schema.CostComponent {
Expand Down
258 changes: 258 additions & 0 deletions internal/resources/ibm/resource_instance_discovery.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,258 @@
package ibm

import (
"fmt"
"math"

"github.com/infracost/infracost/internal/schema"
"github.com/shopspring/decimal"
)

const ENTERPRISE_PLAN_PROGRAMMATIC_NAME string = "enterprise"
const PLUS_PLAN_PROGRAMMATIC_NAME string = "plus"

/*
* Plus = 'plus'
* Enterprise = 'enterprise'
* Premium = 'premium' (not applicable, need to call for pricing)
*/
func GetWDCostComponents(r *ResourceInstance) []*schema.CostComponent {
if r.Plan == PLUS_PLAN_PROGRAMMATIC_NAME {
return []*schema.CostComponent{
WDInstanceCostComponent(r),
WDMonthlyDocumentsCostComponent(r),
WDMonthlyQueriesCostComponent(r),
}
} else if r.Plan == ENTERPRISE_PLAN_PROGRAMMATIC_NAME {
return []*schema.CostComponent{
WDInstanceCostComponent(r),
WDMonthlyDocumentsCostComponent(r),
WDMonthlyQueriesCostComponent(r),
WDMonthlyCustomModelsCostComponent(r),
WDMonthlyCollectionsCostComponent(r),
}
} else {
costComponent := schema.CostComponent{
Name: fmt.Sprintf("Plan %s with customized pricing", r.Plan),
UnitMultiplier: decimal.NewFromInt(1), // Final quantity for this cost component will be divided by this amount
MonthlyQuantity: decimalPtr(decimal.NewFromInt(1)),
}
costComponent.SetCustomPrice(decimalPtr(decimal.NewFromInt(0)))
return []*schema.CostComponent{
&costComponent,
}
}
}

/*
* Instance
* - Plus: $USD/instance/month
* - Enterprise: $USD/instance/month
*/
func WDInstanceCostComponent(r *ResourceInstance) *schema.CostComponent {

var instances_unit_name string
var quantity *decimal.Decimal

if r.Plan == PLUS_PLAN_PROGRAMMATIC_NAME {
instances_unit_name = "PLUS_SERVICE_INSTANCES_PER_MONTH"
} else {
instances_unit_name = "ENTERPRISE_SERVICE_INSTANCES_PER_MONTH"
}

if r.WD_Instance != nil {
quantity = decimalPtr(decimal.NewFromFloat(*r.WD_Instance))
} else {
quantity = decimalPtr(decimal.NewFromInt(1))
}

return &schema.CostComponent{
Name: "Instance",
Unit: "Instance",
UnitMultiplier: decimal.NewFromInt(1), // Final quantity for this cost component will be divided by this amount
MonthlyQuantity: quantity,
ProductFilter: &schema.ProductFilter{
VendorName: strPtr("ibm"),
Region: strPtr(r.Location),
Service: &r.Service,
AttributeFilters: []*schema.AttributeFilter{
{Key: "planName", Value: &r.Plan},
},
},
PriceFilter: &schema.PriceFilter{
Unit: strPtr(instances_unit_name),
},
}
}

/*
* Documents:
* - Plus: $USD/documents/month. Includes 10,000 documents per month; $USD for every additional 1,000 documents.
* - Enterprise: $USD/documents/month. Includes 100,000 documents per month; $USD for every additional 1,000 documents.
*/
func WDMonthlyDocumentsCostComponent(r *ResourceInstance) *schema.CostComponent {

var documents_included int // Base number of documents that are included with an instance and do not have a cost
var documents_unit_name string // Unit to display
var quantity *decimal.Decimal // Quantity of current cost component (e.g. number of additional 1000 "blocks" over the base number of documents included)

if r.Plan == PLUS_PLAN_PROGRAMMATIC_NAME {
documents_unit_name = "PLUS_DOCUMENTS_TOTAL"
documents_included = 10000
} else {
documents_unit_name = "ENTERPRISE_DOCUMENTS_TOTAL"
documents_included = 100000
}

if r.WD_Documents != nil {

additional_documents := *r.WD_Documents - float64(documents_included)

if additional_documents > 0 {
quantity = decimalPtr(decimal.NewFromFloat(additional_documents))
}
} else {
quantity = decimalPtr(decimal.NewFromInt(0))
}

return &schema.CostComponent{
Name: "Additional Monthly Documents",
Unit: "Documents",
UnitMultiplier: decimal.NewFromFloat(1), // Final quantity for this cost component will be divided by this amount
MonthlyQuantity: quantity,
ProductFilter: &schema.ProductFilter{
VendorName: strPtr("ibm"),
Region: strPtr(r.Location),
Service: &r.Service,
AttributeFilters: []*schema.AttributeFilter{
{Key: "planName", Value: &r.Plan},
},
},
PriceFilter: &schema.PriceFilter{
Unit: strPtr(documents_unit_name),
},
}
}

/*
* Queries:
* - Plus: $USD/queries/month. Includes 10,000 queries per month; $USD for every additional 1,000 queries.
* - Enterprise: $USD/queries/month. Includes 100,000 queries per month; $USD for every additional 1,000 queries.
*/
func WDMonthlyQueriesCostComponent(r *ResourceInstance) *schema.CostComponent {

var quantity *decimal.Decimal
var queries_included int // Base number of queries that are included with an instance and do not have a cost

if r.Plan == PLUS_PLAN_PROGRAMMATIC_NAME {
queries_included = 10000
} else {
queries_included = 100000
}

if r.WD_Queries != nil {

additional_queries := *r.WD_Queries - float64(queries_included)

if additional_queries > 0 {
quantity = decimalPtr(decimal.NewFromFloat(additional_queries))
}
} else {
quantity = decimalPtr(decimal.NewFromInt(0))
}

return &schema.CostComponent{
Name: "Additional Monthly Queries",
Unit: "Queries",
UnitMultiplier: decimal.NewFromInt(1), // Final quantity for this cost component will be divided by this amount
MonthlyQuantity: quantity,
ProductFilter: &schema.ProductFilter{
VendorName: strPtr("ibm"),
Region: strPtr(r.Location),
Service: &r.Service,
AttributeFilters: []*schema.AttributeFilter{
{Key: "planName", Value: &r.Plan},
},
},
PriceFilter: &schema.PriceFilter{
Unit: strPtr("GRADUATED_PRICE_QUERIES_PER_MONTH"),
},
}
}

/*
* Custom Models:
* - Enterprise: $USD/additional custom models/month. Includes 3 custom models per month.
*/
func WDMonthlyCustomModelsCostComponent(r *ResourceInstance) *schema.CostComponent {

var quantity *decimal.Decimal
var custom_models_included int = 3 // Base number of custom models that are included with an instance and do not have a cost

if r.WD_CustomModels != nil {
// Determine number of custom models that go over the base number of custom models included
quantity = decimalPtr(decimal.NewFromFloat(*r.WD_CustomModels - float64(custom_models_included)))
} else {
quantity = decimalPtr(decimal.NewFromInt(0))
}

return &schema.CostComponent{
Name: "Additional Monthly Custom Models",
Unit: "Custom Models",
UnitMultiplier: decimal.NewFromInt(1), // Final quantity for this cost component will be divided by this amount
MonthlyQuantity: quantity,
ProductFilter: &schema.ProductFilter{
VendorName: strPtr("ibm"),
Region: strPtr(r.Location),
Service: &r.Service,
AttributeFilters: []*schema.AttributeFilter{
{Key: "planName", Value: &r.Plan},
},
},
PriceFilter: &schema.PriceFilter{
Unit: strPtr("CUSTOM_MODELS_PER_MONTH"),
},
}
}

/*
* Collections
* - Enterprise: $USD/additional collections/month. Includes 300 collections per month; $USD for every additional 100 collections.
*/
func WDMonthlyCollectionsCostComponent(r *ResourceInstance) *schema.CostComponent {

var quantity *decimal.Decimal
var collections_additional_range int = 100 // Additional cost for every 100 over the included amount of collections
var collections_included int = 300 // Base number of collections that are included with an instance and do not have a cost

if r.WD_Collections != nil {

additional_collections := *r.WD_Collections - float64(collections_included)

if additional_collections > 0 {
// Determine number of 100 "blocks" of collections go over the base number of collections included
quantity = decimalPtr(decimal.NewFromFloat(math.Ceil(additional_collections / float64(collections_additional_range))))
}

} else {
quantity = decimalPtr(decimal.NewFromInt(0))
}

return &schema.CostComponent{
Name: "Additional Monthly Collections",
Unit: "Hundred Collections",
UnitMultiplier: decimal.NewFromFloat(1), // Final quantity for this cost component will be divided by this amount
MonthlyQuantity: quantity,
ProductFilter: &schema.ProductFilter{
VendorName: strPtr("ibm"),
Region: strPtr(r.Location),
Service: &r.Service,
AttributeFilters: []*schema.AttributeFilter{
{Key: "planName", Value: &r.Plan},
},
},
PriceFilter: &schema.PriceFilter{
Unit: strPtr("ENTERPRISE_COLLECTIONS_TOTAL"),
},
}
}
Loading