From 1603370606324c2f8b2754a30250ddf6eced9bf5 Mon Sep 17 00:00:00 2001 From: Erik Zilber Date: Mon, 7 Oct 2024 16:46:28 -0400 Subject: [PATCH] Add support for LKE, Volume, NodeBalancer, and network transfer pricing endpoints (#1591) * Added LKE Types datasource * Added Node Balancer Types datasource * Added Volume Types datasource * Added Network Transfer Prices datasource * Abstracted base pricing types * Addressed PR comments * Fixed filters for new endpoints --- linode/framework_provider.go | 11 +- linode/helper/base_pricing_types.go | 50 ++++++++ .../framework_datasource_schema.go | 24 +--- linode/instancetype/framework_models.go | 10 +- linode/lketypes/datasource_test.go | 35 +++++ linode/lketypes/framework_datasource.go | 73 +++++++++++ .../lketypes/framework_datasource_schema.go | 34 +++++ linode/lketypes/framework_models.go | 121 ++++++++++++++++++ linode/lketypes/tmpl/data_basic.gotf | 10 ++ linode/lketypes/tmpl/template.go | 12 ++ linode/nbtypes/datasource_test.go | 38 ++++++ linode/nbtypes/framework_datasource.go | 73 +++++++++++ linode/nbtypes/framework_datasource_schema.go | 34 +++++ linode/nbtypes/framework_models.go | 121 ++++++++++++++++++ linode/nbtypes/tmpl/data_basic.gotf | 10 ++ linode/nbtypes/tmpl/template.go | 12 ++ .../networktransferprices/datasource_test.go | 38 ++++++ .../framework_datasource.go | 73 +++++++++++ .../framework_datasource_schema.go | 34 +++++ .../networktransferprices/framework_models.go | 121 ++++++++++++++++++ .../tmpl/data_basic.gotf | 10 ++ linode/networktransferprices/tmpl/template.go | 12 ++ linode/volumetypes/datasource_test.go | 38 ++++++ linode/volumetypes/framework_datasource.go | 73 +++++++++++ .../framework_datasource_schema.go | 34 +++++ linode/volumetypes/framework_models.go | 121 ++++++++++++++++++ linode/volumetypes/tmpl/data_basic.gotf | 10 ++ linode/volumetypes/tmpl/template.go | 12 ++ 28 files changed, 1219 insertions(+), 25 deletions(-) create mode 100644 linode/helper/base_pricing_types.go create mode 100644 linode/lketypes/datasource_test.go create mode 100644 linode/lketypes/framework_datasource.go create mode 100644 linode/lketypes/framework_datasource_schema.go create mode 100644 linode/lketypes/framework_models.go create mode 100644 linode/lketypes/tmpl/data_basic.gotf create mode 100644 linode/lketypes/tmpl/template.go create mode 100644 linode/nbtypes/datasource_test.go create mode 100644 linode/nbtypes/framework_datasource.go create mode 100644 linode/nbtypes/framework_datasource_schema.go create mode 100644 linode/nbtypes/framework_models.go create mode 100644 linode/nbtypes/tmpl/data_basic.gotf create mode 100644 linode/nbtypes/tmpl/template.go create mode 100644 linode/networktransferprices/datasource_test.go create mode 100644 linode/networktransferprices/framework_datasource.go create mode 100644 linode/networktransferprices/framework_datasource_schema.go create mode 100644 linode/networktransferprices/framework_models.go create mode 100644 linode/networktransferprices/tmpl/data_basic.gotf create mode 100644 linode/networktransferprices/tmpl/template.go create mode 100644 linode/volumetypes/datasource_test.go create mode 100644 linode/volumetypes/framework_datasource.go create mode 100644 linode/volumetypes/framework_datasource_schema.go create mode 100644 linode/volumetypes/framework_models.go create mode 100644 linode/volumetypes/tmpl/data_basic.gotf create mode 100644 linode/volumetypes/tmpl/template.go diff --git a/linode/framework_provider.go b/linode/framework_provider.go index 22cab83ff..7dc261184 100644 --- a/linode/framework_provider.go +++ b/linode/framework_provider.go @@ -3,8 +3,6 @@ package linode import ( "context" - "github.com/linode/terraform-provider-linode/v2/linode/vpcips" - "github.com/hashicorp/terraform-plugin-framework/datasource" "github.com/hashicorp/terraform-plugin-framework/provider" "github.com/hashicorp/terraform-plugin-framework/provider/schema" @@ -46,13 +44,16 @@ import ( "github.com/linode/terraform-provider-linode/v2/linode/lke" "github.com/linode/terraform-provider-linode/v2/linode/lkeclusters" "github.com/linode/terraform-provider-linode/v2/linode/lkenodepool" + "github.com/linode/terraform-provider-linode/v2/linode/lketypes" "github.com/linode/terraform-provider-linode/v2/linode/lkeversions" "github.com/linode/terraform-provider-linode/v2/linode/nb" "github.com/linode/terraform-provider-linode/v2/linode/nbconfig" "github.com/linode/terraform-provider-linode/v2/linode/nbconfigs" "github.com/linode/terraform-provider-linode/v2/linode/nbnode" "github.com/linode/terraform-provider-linode/v2/linode/nbs" + "github.com/linode/terraform-provider-linode/v2/linode/nbtypes" "github.com/linode/terraform-provider-linode/v2/linode/networkingip" + "github.com/linode/terraform-provider-linode/v2/linode/networktransferprices" "github.com/linode/terraform-provider-linode/v2/linode/objbucket" "github.com/linode/terraform-provider-linode/v2/linode/objcluster" "github.com/linode/terraform-provider-linode/v2/linode/objkey" @@ -73,7 +74,9 @@ import ( "github.com/linode/terraform-provider-linode/v2/linode/vlan" "github.com/linode/terraform-provider-linode/v2/linode/volume" "github.com/linode/terraform-provider-linode/v2/linode/volumes" + "github.com/linode/terraform-provider-linode/v2/linode/volumetypes" "github.com/linode/terraform-provider-linode/v2/linode/vpc" + "github.com/linode/terraform-provider-linode/v2/linode/vpcips" "github.com/linode/terraform-provider-linode/v2/linode/vpcs" "github.com/linode/terraform-provider-linode/v2/linode/vpcsubnet" "github.com/linode/terraform-provider-linode/v2/linode/vpcsubnets" @@ -237,6 +240,7 @@ func (p *FrameworkProvider) DataSources(ctx context.Context) []func() datasource profile.NewDataSource, nb.NewDataSource, networkingip.NewDataSource, + networktransferprices.NewDataSource, lkeversions.NewDataSource, regions.NewDataSource, ipv6range.NewDataSource, @@ -253,6 +257,7 @@ func (p *FrameworkProvider) DataSources(ctx context.Context) []func() datasource domain.NewDataSource, user.NewDataSource, nbconfig.NewDataSource, + nbtypes.NewDataSource, instancetype.NewDataSource, instancetypes.NewDataSource, image.NewDataSource, @@ -276,12 +281,14 @@ func (p *FrameworkProvider) DataSources(ctx context.Context) []func() datasource vpcsubnets.NewDataSource, vpcs.NewDataSource, volumes.NewDataSource, + volumetypes.NewDataSource, accountavailability.NewDataSource, nbconfigs.NewDataSource, ipv6ranges.NewDataSource, domains.NewDataSource, lke.NewDataSource, lkeclusters.NewDataSource, + lketypes.NewDataSource, placementgroup.NewDataSource, placementgroups.NewDataSource, childaccount.NewDataSource, diff --git a/linode/helper/base_pricing_types.go b/linode/helper/base_pricing_types.go new file mode 100644 index 000000000..f3e96878c --- /dev/null +++ b/linode/helper/base_pricing_types.go @@ -0,0 +1,50 @@ +package helper + +import ( + "github.com/hashicorp/terraform-plugin-framework/attr" + "github.com/hashicorp/terraform-plugin-framework/datasource/schema" + "github.com/hashicorp/terraform-plugin-framework/types" +) + +var PriceObjectType = types.ObjectType{ + AttrTypes: map[string]attr.Type{ + "hourly": types.Float64Type, + "monthly": types.Float64Type, + }, +} + +var RegionPriceObjectType = types.ObjectType{ + AttrTypes: map[string]attr.Type{ + "id": types.StringType, + "hourly": types.Float64Type, + "monthly": types.Float64Type, + }, +} + +func GetPricingTypeAttributes(typeName string) map[string]schema.Attribute { + return map[string]schema.Attribute{ + "id": schema.StringAttribute{ + Description: "The unique ID assigned to this " + typeName + ".", + Required: true, + }, + "label": schema.StringAttribute{ + Description: "The " + typeName + "'s label.", + Computed: true, + Optional: true, + }, + "price": schema.ListAttribute{ + Description: "Cost in US dollars, broken down into hourly and monthly charges.", + Computed: true, + ElementType: PriceObjectType, + }, + "region_prices": schema.ListAttribute{ + Description: "A list of region-specific prices for this " + typeName + ".", + Computed: true, + ElementType: RegionPriceObjectType, + }, + "transfer": schema.Int64Attribute{ + Description: "The monthly outbound transfer amount, in MB.", + Computed: true, + }, + } +} diff --git a/linode/instancetype/framework_datasource_schema.go b/linode/instancetype/framework_datasource_schema.go index 8af4219bf..351808cff 100644 --- a/linode/instancetype/framework_datasource_schema.go +++ b/linode/instancetype/framework_datasource_schema.go @@ -4,27 +4,13 @@ import ( "github.com/hashicorp/terraform-plugin-framework/attr" "github.com/hashicorp/terraform-plugin-framework/datasource/schema" "github.com/hashicorp/terraform-plugin-framework/types" + "github.com/linode/terraform-provider-linode/v2/linode/helper" ) -var priceObjectType = types.ObjectType{ - AttrTypes: map[string]attr.Type{ - "hourly": types.Float64Type, - "monthly": types.Float64Type, - }, -} - -var regionPriceObjectType = types.ObjectType{ - AttrTypes: map[string]attr.Type{ - "id": types.StringType, - "hourly": types.Float64Type, - "monthly": types.Float64Type, - }, -} - var backupsObjectType = types.ObjectType{ AttrTypes: map[string]attr.Type{ - "price": types.ListType{ElemType: priceObjectType}, - "region_prices": types.ListType{ElemType: regionPriceObjectType}, + "price": types.ListType{ElemType: helper.PriceObjectType}, + "region_prices": types.ListType{ElemType: helper.RegionPriceObjectType}, }, } @@ -56,7 +42,7 @@ var Attributes = map[string]schema.Attribute{ "price": schema.ListAttribute{ Description: "Cost in US dollars, broken down into hourly and monthly charges.", Computed: true, - ElementType: priceObjectType, + ElementType: helper.PriceObjectType, }, "addons": schema.ListAttribute{ Description: "Information about the optional Backup service offered for Linodes.", @@ -66,7 +52,7 @@ var Attributes = map[string]schema.Attribute{ "region_prices": schema.ListAttribute{ Description: "A list of region-specific prices for this plan.", Computed: true, - ElementType: regionPriceObjectType, + ElementType: helper.RegionPriceObjectType, }, "network_out": schema.Int64Attribute{ Description: "The Mbits outbound bandwidth allocation.", diff --git a/linode/instancetype/framework_models.go b/linode/instancetype/framework_models.go index 83ded6d18..810e0c3e4 100644 --- a/linode/instancetype/framework_models.go +++ b/linode/instancetype/framework_models.go @@ -3,6 +3,8 @@ package instancetype import ( "context" + "github.com/linode/terraform-provider-linode/v2/linode/helper" + "github.com/hashicorp/terraform-plugin-framework/attr" "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/types" @@ -134,7 +136,7 @@ func FlattenPrice(ctx context.Context, price linodego.LinodePrice) ( result["hourly"] = types.Float64Value(float64(price.Hourly)) result["monthly"] = types.Float64Value(float64(price.Monthly)) - obj, diag := types.ObjectValue(priceObjectType.AttrTypes, result) + obj, diag := types.ObjectValue(helper.PriceObjectType.AttrTypes, result) if diag.HasError() { return nil, diag } @@ -142,7 +144,7 @@ func FlattenPrice(ctx context.Context, price linodego.LinodePrice) ( objList := []attr.Value{obj} resultList, diag := types.ListValue( - priceObjectType, + helper.PriceObjectType, objList, ) if diag.HasError() { @@ -158,7 +160,7 @@ func FlattenRegionPrices(prices []linodego.LinodeRegionPrice) ( result := make([]attr.Value, len(prices)) for i, price := range prices { - obj, d := types.ObjectValue(regionPriceObjectType.AttrTypes, map[string]attr.Value{ + obj, d := types.ObjectValue(helper.RegionPriceObjectType.AttrTypes, map[string]attr.Value{ "id": types.StringValue(price.ID), "hourly": types.Float64Value(float64(price.Hourly)), "monthly": types.Float64Value(float64(price.Monthly)), @@ -171,7 +173,7 @@ func FlattenRegionPrices(prices []linodego.LinodeRegionPrice) ( } priceList, d := basetypes.NewListValue( - regionPriceObjectType, + helper.RegionPriceObjectType, result, ) return &priceList, d diff --git a/linode/lketypes/datasource_test.go b/linode/lketypes/datasource_test.go new file mode 100644 index 000000000..a7dc0a276 --- /dev/null +++ b/linode/lketypes/datasource_test.go @@ -0,0 +1,35 @@ +//go:build integration || lketypes + +package lketypes_test + +import ( + "testing" + + "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/linode/terraform-provider-linode/v2/linode/acceptance" + "github.com/linode/terraform-provider-linode/v2/linode/lketypes/tmpl" +) + +func TestAccDataSourceLKETypes_basic(t *testing.T) { + t.Parallel() + + dataSourceName := "data.linode_lke_types.foobar" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acceptance.PreCheck(t) }, + ProtoV5ProviderFactories: acceptance.ProtoV5ProviderFactories, + Steps: []resource.TestStep{ + { + Config: tmpl.DataBasic(t), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(dataSourceName, "types.#", "1"), + resource.TestCheckResourceAttr(dataSourceName, "types.0.id", "lke-sa"), + resource.TestCheckResourceAttr(dataSourceName, "types.0.label", "LKE Standard Availability"), + resource.TestCheckResourceAttrSet(dataSourceName, "types.0.transfer"), + resource.TestCheckResourceAttrSet(dataSourceName, "types.0.price.0.hourly"), + resource.TestCheckResourceAttrSet(dataSourceName, "types.0.price.0.monthly"), + ), + }, + }, + }) +} diff --git a/linode/lketypes/framework_datasource.go b/linode/lketypes/framework_datasource.go new file mode 100644 index 000000000..f35b16a77 --- /dev/null +++ b/linode/lketypes/framework_datasource.go @@ -0,0 +1,73 @@ +package lketypes + +import ( + "context" + + "github.com/hashicorp/terraform-plugin-framework/datasource" + "github.com/hashicorp/terraform-plugin-log/tflog" + "github.com/linode/linodego" + "github.com/linode/terraform-provider-linode/v2/linode/helper" +) + +func NewDataSource() datasource.DataSource { + return &DataSource{ + BaseDataSource: helper.NewBaseDataSource( + helper.BaseDataSourceConfig{ + Name: "linode_lke_types", + Schema: &frameworkDataSourceSchema, + }, + ), + } +} + +type DataSource struct { + helper.BaseDataSource +} + +func (r *DataSource) Read( + ctx context.Context, + req datasource.ReadRequest, + resp *datasource.ReadResponse, +) { + tflog.Debug(ctx, "Read data.linode_lke_types") + + var data LKETypeFilterModel + + resp.Diagnostics.Append(req.Config.Get(ctx, &data)...) + if resp.Diagnostics.HasError() { + return + } + + id, d := filterConfig.GenerateID(data.Filters) + if d != nil { + resp.Diagnostics.Append(d) + return + } + data.ID = id + + result, d := filterConfig.GetAndFilter( + ctx, r.Meta.Client, data.Filters, listLKETypes, data.Order, data.OrderBy) + if d != nil { + resp.Diagnostics.Append(d) + return + } + + data.parseLKETypes(helper.AnySliceToTyped[linodego.LKEType](result)) + + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) +} + +func listLKETypes(ctx context.Context, client *linodego.Client, filter string) ([]any, error) { + tflog.Debug(ctx, "Listing LKE types", map[string]any{ + "filter_header": filter, + }) + + types, err := client.ListLKETypes(ctx, &linodego.ListOptions{ + Filter: filter, + }) + if err != nil { + return nil, err + } + + return helper.TypedSliceToAny(types), nil +} diff --git a/linode/lketypes/framework_datasource_schema.go b/linode/lketypes/framework_datasource_schema.go new file mode 100644 index 000000000..7c3af3117 --- /dev/null +++ b/linode/lketypes/framework_datasource_schema.go @@ -0,0 +1,34 @@ +package lketypes + +import ( + "github.com/hashicorp/terraform-plugin-framework/datasource/schema" + "github.com/linode/terraform-provider-linode/v2/linode/helper" + "github.com/linode/terraform-provider-linode/v2/linode/helper/frameworkfilter" +) + +var lkeTypeSchema = schema.NestedBlockObject{ + Attributes: helper.GetPricingTypeAttributes("LKE Type"), +} + +var filterConfig = frameworkfilter.Config{ + "label": {APIFilterable: true, TypeFunc: frameworkfilter.FilterTypeString}, + "transfer": {APIFilterable: true, TypeFunc: frameworkfilter.FilterTypeInt}, +} + +var frameworkDataSourceSchema = schema.Schema{ + Attributes: map[string]schema.Attribute{ + "id": schema.StringAttribute{ + Description: "The data source's unique ID.", + Computed: true, + }, + "order_by": filterConfig.OrderBySchema(), + "order": filterConfig.OrderSchema(), + }, + Blocks: map[string]schema.Block{ + "filter": filterConfig.Schema(), + "types": schema.ListNestedBlock{ + Description: "The returned list of LKE types.", + NestedObject: lkeTypeSchema, + }, + }, +} diff --git a/linode/lketypes/framework_models.go b/linode/lketypes/framework_models.go new file mode 100644 index 000000000..b357dfbfd --- /dev/null +++ b/linode/lketypes/framework_models.go @@ -0,0 +1,121 @@ +package lketypes + +import ( + "github.com/hashicorp/terraform-plugin-framework/attr" + "github.com/hashicorp/terraform-plugin-framework/diag" + "github.com/hashicorp/terraform-plugin-framework/types" + "github.com/hashicorp/terraform-plugin-framework/types/basetypes" + "github.com/linode/linodego" + "github.com/linode/terraform-provider-linode/v2/linode/helper" + "github.com/linode/terraform-provider-linode/v2/linode/helper/frameworkfilter" +) + +type DataSourceModel struct { + ID types.String `tfsdk:"id"` + Label types.String `tfsdk:"label"` + Price types.List `tfsdk:"price"` + RegionPrices types.List `tfsdk:"region_prices"` + Transfer types.Int64 `tfsdk:"transfer"` +} + +func (data *DataSourceModel) parseLKEType(lkeType *linodego.LKEType, +) diag.Diagnostics { + data.ID = types.StringValue(lkeType.ID) + + price, diags := flattenPrice(lkeType.Price) + if diags.HasError() { + return diags + } + data.Price = *price + + data.Label = types.StringValue(lkeType.Label) + + regionPrices, d := flattenRegionPrices(lkeType.RegionPrices) + if d.HasError() { + return d + } + data.RegionPrices = *regionPrices + + data.Transfer = types.Int64Value(int64(lkeType.Transfer)) + + return nil +} + +func flattenPrice(price linodego.LKETypePrice) ( + *basetypes.ListValue, diag.Diagnostics, +) { + result := make(map[string]attr.Value) + + result["hourly"] = types.Float64Value(float64(price.Hourly)) + result["monthly"] = types.Float64Value(float64(price.Monthly)) + + obj, diag := types.ObjectValue(helper.PriceObjectType.AttrTypes, result) + if diag.HasError() { + return nil, diag + } + + objList := []attr.Value{obj} + + resultList, diag := types.ListValue( + helper.PriceObjectType, + objList, + ) + if diag.HasError() { + return nil, diag + } + + return &resultList, nil +} + +func flattenRegionPrices(prices []linodego.LKETypeRegionPrice) ( + *basetypes.ListValue, diag.Diagnostics, +) { + result := make([]attr.Value, len(prices)) + + for i, price := range prices { + obj, d := types.ObjectValue(helper.RegionPriceObjectType.AttrTypes, map[string]attr.Value{ + "id": types.StringValue(price.ID), + "hourly": types.Float64Value(float64(price.Hourly)), + "monthly": types.Float64Value(float64(price.Monthly)), + }) + if d.HasError() { + return nil, d + } + + result[i] = obj + } + + priceList, d := basetypes.NewListValue( + helper.RegionPriceObjectType, + result, + ) + return &priceList, d +} + +type LKETypeFilterModel struct { + ID types.String `tfsdk:"id"` + Order types.String `tfsdk:"order"` + OrderBy types.String `tfsdk:"order_by"` + Filters frameworkfilter.FiltersModelType `tfsdk:"filter"` + Types []DataSourceModel `tfsdk:"types"` +} + +func (model *LKETypeFilterModel) parseLKETypes(lkeTypes []linodego.LKEType, +) diag.Diagnostics { + result := make([]DataSourceModel, len(lkeTypes)) + + for i := range lkeTypes { + var m DataSourceModel + + diags := m.parseLKEType(&lkeTypes[i]) + if diags.HasError() { + return diags + } + + result[i] = m + } + + model.Types = result + + return nil +} diff --git a/linode/lketypes/tmpl/data_basic.gotf b/linode/lketypes/tmpl/data_basic.gotf new file mode 100644 index 000000000..5b260627c --- /dev/null +++ b/linode/lketypes/tmpl/data_basic.gotf @@ -0,0 +1,10 @@ +{{ define "lke_types_data_basic" }} + +data "linode_lke_types" "foobar" { + filter { + name = "label" + values = ["LKE Standard Availability"] + } +} + +{{ end }} \ No newline at end of file diff --git a/linode/lketypes/tmpl/template.go b/linode/lketypes/tmpl/template.go new file mode 100644 index 000000000..687ebbe6b --- /dev/null +++ b/linode/lketypes/tmpl/template.go @@ -0,0 +1,12 @@ +package tmpl + +import ( + "testing" + + "github.com/linode/terraform-provider-linode/v2/linode/acceptance" +) + +func DataBasic(t *testing.T) string { + return acceptance.ExecuteTemplate(t, + "lke_types_data_basic", nil) +} diff --git a/linode/nbtypes/datasource_test.go b/linode/nbtypes/datasource_test.go new file mode 100644 index 000000000..d97eb41dc --- /dev/null +++ b/linode/nbtypes/datasource_test.go @@ -0,0 +1,38 @@ +//go:build integration || nbtypes + +package nbtypes_test + +import ( + "testing" + + "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/linode/terraform-provider-linode/v2/linode/acceptance" + "github.com/linode/terraform-provider-linode/v2/linode/nbtypes/tmpl" +) + +func TestAccDataSourceNodeBalancerTypes_basic(t *testing.T) { + t.Parallel() + + dataSourceName := "data.linode_nb_types.foobar" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acceptance.PreCheck(t) }, + ProtoV5ProviderFactories: acceptance.ProtoV5ProviderFactories, + Steps: []resource.TestStep{ + { + Config: tmpl.DataBasic(t), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(dataSourceName, "types.#", "1"), + resource.TestCheckResourceAttr(dataSourceName, "types.0.id", "nodebalancer"), + resource.TestCheckResourceAttr(dataSourceName, "types.0.label", "NodeBalancer"), + resource.TestCheckResourceAttrSet(dataSourceName, "types.0.transfer"), + resource.TestCheckResourceAttrSet(dataSourceName, "types.0.price.0.hourly"), + resource.TestCheckResourceAttrSet(dataSourceName, "types.0.price.0.monthly"), + resource.TestCheckResourceAttrSet(dataSourceName, "types.0.region_prices.0.id"), + resource.TestCheckResourceAttrSet(dataSourceName, "types.0.region_prices.0.hourly"), + resource.TestCheckResourceAttrSet(dataSourceName, "types.0.region_prices.0.monthly"), + ), + }, + }, + }) +} diff --git a/linode/nbtypes/framework_datasource.go b/linode/nbtypes/framework_datasource.go new file mode 100644 index 000000000..bcaf07679 --- /dev/null +++ b/linode/nbtypes/framework_datasource.go @@ -0,0 +1,73 @@ +package nbtypes + +import ( + "context" + + "github.com/hashicorp/terraform-plugin-framework/datasource" + "github.com/hashicorp/terraform-plugin-log/tflog" + "github.com/linode/linodego" + "github.com/linode/terraform-provider-linode/v2/linode/helper" +) + +func NewDataSource() datasource.DataSource { + return &DataSource{ + BaseDataSource: helper.NewBaseDataSource( + helper.BaseDataSourceConfig{ + Name: "linode_nb_types", + Schema: &frameworkDataSourceSchema, + }, + ), + } +} + +type DataSource struct { + helper.BaseDataSource +} + +func (r *DataSource) Read( + ctx context.Context, + req datasource.ReadRequest, + resp *datasource.ReadResponse, +) { + tflog.Debug(ctx, "Read data.linode_nb_types") + + var data NodeBalancerTypeFilterModel + + resp.Diagnostics.Append(req.Config.Get(ctx, &data)...) + if resp.Diagnostics.HasError() { + return + } + + id, d := filterConfig.GenerateID(data.Filters) + if d != nil { + resp.Diagnostics.Append(d) + return + } + data.ID = id + + result, d := filterConfig.GetAndFilter( + ctx, r.Meta.Client, data.Filters, listNodeBalancerTypes, data.Order, data.OrderBy) + if d != nil { + resp.Diagnostics.Append(d) + return + } + + data.parseNodeBalancerTypes(helper.AnySliceToTyped[linodego.NodeBalancerType](result)) + + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) +} + +func listNodeBalancerTypes(ctx context.Context, client *linodego.Client, filter string) ([]any, error) { + tflog.Debug(ctx, "Listing Node Balancer types", map[string]any{ + "filter_header": filter, + }) + + types, err := client.ListNodeBalancerTypes(ctx, &linodego.ListOptions{ + Filter: filter, + }) + if err != nil { + return nil, err + } + + return helper.TypedSliceToAny(types), nil +} diff --git a/linode/nbtypes/framework_datasource_schema.go b/linode/nbtypes/framework_datasource_schema.go new file mode 100644 index 000000000..89bc9c327 --- /dev/null +++ b/linode/nbtypes/framework_datasource_schema.go @@ -0,0 +1,34 @@ +package nbtypes + +import ( + "github.com/hashicorp/terraform-plugin-framework/datasource/schema" + "github.com/linode/terraform-provider-linode/v2/linode/helper" + "github.com/linode/terraform-provider-linode/v2/linode/helper/frameworkfilter" +) + +var nodebalancerTypeSchema = schema.NestedBlockObject{ + Attributes: helper.GetPricingTypeAttributes("Node Balancer Type"), +} + +var filterConfig = frameworkfilter.Config{ + "label": {APIFilterable: true, TypeFunc: frameworkfilter.FilterTypeString}, + "transfer": {APIFilterable: true, TypeFunc: frameworkfilter.FilterTypeInt}, +} + +var frameworkDataSourceSchema = schema.Schema{ + Attributes: map[string]schema.Attribute{ + "id": schema.StringAttribute{ + Description: "The data source's unique ID.", + Computed: true, + }, + "order_by": filterConfig.OrderBySchema(), + "order": filterConfig.OrderSchema(), + }, + Blocks: map[string]schema.Block{ + "filter": filterConfig.Schema(), + "types": schema.ListNestedBlock{ + Description: "The returned list of Node Balancer types.", + NestedObject: nodebalancerTypeSchema, + }, + }, +} diff --git a/linode/nbtypes/framework_models.go b/linode/nbtypes/framework_models.go new file mode 100644 index 000000000..6b0010213 --- /dev/null +++ b/linode/nbtypes/framework_models.go @@ -0,0 +1,121 @@ +package nbtypes + +import ( + "github.com/hashicorp/terraform-plugin-framework/attr" + "github.com/hashicorp/terraform-plugin-framework/diag" + "github.com/hashicorp/terraform-plugin-framework/types" + "github.com/hashicorp/terraform-plugin-framework/types/basetypes" + "github.com/linode/linodego" + "github.com/linode/terraform-provider-linode/v2/linode/helper" + "github.com/linode/terraform-provider-linode/v2/linode/helper/frameworkfilter" +) + +type DataSourceModel struct { + ID types.String `tfsdk:"id"` + Label types.String `tfsdk:"label"` + Price types.List `tfsdk:"price"` + RegionPrices types.List `tfsdk:"region_prices"` + Transfer types.Int64 `tfsdk:"transfer"` +} + +func (data *DataSourceModel) parseNodeBalancerType(nbType *linodego.NodeBalancerType, +) diag.Diagnostics { + data.ID = types.StringValue(nbType.ID) + + price, diags := flattenPrice(nbType.Price) + if diags.HasError() { + return diags + } + data.Price = *price + + data.Label = types.StringValue(nbType.Label) + + regionPrices, d := flattenRegionPrices(nbType.RegionPrices) + if d.HasError() { + return d + } + data.RegionPrices = *regionPrices + + data.Transfer = types.Int64Value(int64(nbType.Transfer)) + + return nil +} + +func flattenPrice(price linodego.NodeBalancerTypePrice) ( + *basetypes.ListValue, diag.Diagnostics, +) { + result := make(map[string]attr.Value) + + result["hourly"] = types.Float64Value(float64(price.Hourly)) + result["monthly"] = types.Float64Value(float64(price.Monthly)) + + obj, diag := types.ObjectValue(helper.PriceObjectType.AttrTypes, result) + if diag.HasError() { + return nil, diag + } + + objList := []attr.Value{obj} + + resultList, diag := types.ListValue( + helper.PriceObjectType, + objList, + ) + if diag.HasError() { + return nil, diag + } + + return &resultList, nil +} + +func flattenRegionPrices(prices []linodego.NodeBalancerTypeRegionPrice) ( + *basetypes.ListValue, diag.Diagnostics, +) { + result := make([]attr.Value, len(prices)) + + for i, price := range prices { + obj, d := types.ObjectValue(helper.RegionPriceObjectType.AttrTypes, map[string]attr.Value{ + "id": types.StringValue(price.ID), + "hourly": types.Float64Value(float64(price.Hourly)), + "monthly": types.Float64Value(float64(price.Monthly)), + }) + if d.HasError() { + return nil, d + } + + result[i] = obj + } + + priceList, d := basetypes.NewListValue( + helper.RegionPriceObjectType, + result, + ) + return &priceList, d +} + +type NodeBalancerTypeFilterModel struct { + ID types.String `tfsdk:"id"` + Order types.String `tfsdk:"order"` + OrderBy types.String `tfsdk:"order_by"` + Filters frameworkfilter.FiltersModelType `tfsdk:"filter"` + Types []DataSourceModel `tfsdk:"types"` +} + +func (model *NodeBalancerTypeFilterModel) parseNodeBalancerTypes(nbTypes []linodego.NodeBalancerType, +) diag.Diagnostics { + result := make([]DataSourceModel, len(nbTypes)) + + for i := range nbTypes { + var m DataSourceModel + + diags := m.parseNodeBalancerType(&nbTypes[i]) + if diags.HasError() { + return diags + } + + result[i] = m + } + + model.Types = result + + return nil +} diff --git a/linode/nbtypes/tmpl/data_basic.gotf b/linode/nbtypes/tmpl/data_basic.gotf new file mode 100644 index 000000000..fb8fffe12 --- /dev/null +++ b/linode/nbtypes/tmpl/data_basic.gotf @@ -0,0 +1,10 @@ +{{ define "nb_types_data_basic" }} + +data "linode_nb_types" "foobar" { + filter { + name = "label" + values = ["NodeBalancer"] + } +} + +{{ end }} \ No newline at end of file diff --git a/linode/nbtypes/tmpl/template.go b/linode/nbtypes/tmpl/template.go new file mode 100644 index 000000000..b57ade428 --- /dev/null +++ b/linode/nbtypes/tmpl/template.go @@ -0,0 +1,12 @@ +package tmpl + +import ( + "testing" + + "github.com/linode/terraform-provider-linode/v2/linode/acceptance" +) + +func DataBasic(t *testing.T) string { + return acceptance.ExecuteTemplate(t, + "nb_types_data_basic", nil) +} diff --git a/linode/networktransferprices/datasource_test.go b/linode/networktransferprices/datasource_test.go new file mode 100644 index 000000000..018966654 --- /dev/null +++ b/linode/networktransferprices/datasource_test.go @@ -0,0 +1,38 @@ +//go:build integration || networktransferprices + +package networktransferprices_test + +import ( + "testing" + + "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/linode/terraform-provider-linode/v2/linode/acceptance" + "github.com/linode/terraform-provider-linode/v2/linode/networktransferprices/tmpl" +) + +func TestAccDataSourceNetworkTransferPrices_basic(t *testing.T) { + t.Parallel() + + dataSourceName := "data.linode_network_transfer_prices.foobar" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acceptance.PreCheck(t) }, + ProtoV5ProviderFactories: acceptance.ProtoV5ProviderFactories, + Steps: []resource.TestStep{ + { + Config: tmpl.DataBasic(t), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(dataSourceName, "types.#", "1"), + resource.TestCheckResourceAttr(dataSourceName, "types.0.id", "network_transfer"), + resource.TestCheckResourceAttr(dataSourceName, "types.0.label", "Network Transfer"), + resource.TestCheckResourceAttrSet(dataSourceName, "types.0.transfer"), + resource.TestCheckResourceAttrSet(dataSourceName, "types.0.price.0.hourly"), + resource.TestCheckResourceAttrSet(dataSourceName, "types.0.price.0.monthly"), + resource.TestCheckResourceAttrSet(dataSourceName, "types.0.region_prices.0.id"), + resource.TestCheckResourceAttrSet(dataSourceName, "types.0.region_prices.0.hourly"), + resource.TestCheckResourceAttrSet(dataSourceName, "types.0.region_prices.0.monthly"), + ), + }, + }, + }) +} diff --git a/linode/networktransferprices/framework_datasource.go b/linode/networktransferprices/framework_datasource.go new file mode 100644 index 000000000..7700e1fcb --- /dev/null +++ b/linode/networktransferprices/framework_datasource.go @@ -0,0 +1,73 @@ +package networktransferprices + +import ( + "context" + + "github.com/hashicorp/terraform-plugin-framework/datasource" + "github.com/hashicorp/terraform-plugin-log/tflog" + "github.com/linode/linodego" + "github.com/linode/terraform-provider-linode/v2/linode/helper" +) + +func NewDataSource() datasource.DataSource { + return &DataSource{ + BaseDataSource: helper.NewBaseDataSource( + helper.BaseDataSourceConfig{ + Name: "linode_network_transfer_prices", + Schema: &frameworkDataSourceSchema, + }, + ), + } +} + +type DataSource struct { + helper.BaseDataSource +} + +func (r *DataSource) Read( + ctx context.Context, + req datasource.ReadRequest, + resp *datasource.ReadResponse, +) { + tflog.Debug(ctx, "Read data.linode_network_transfer_prices") + + var data NetworkTransferPriceFilterModel + + resp.Diagnostics.Append(req.Config.Get(ctx, &data)...) + if resp.Diagnostics.HasError() { + return + } + + id, d := filterConfig.GenerateID(data.Filters) + if d != nil { + resp.Diagnostics.Append(d) + return + } + data.ID = id + + result, d := filterConfig.GetAndFilter( + ctx, r.Meta.Client, data.Filters, listNetworkTransferPrices, data.Order, data.OrderBy) + if d != nil { + resp.Diagnostics.Append(d) + return + } + + data.parseNetworkTransferPrices(helper.AnySliceToTyped[linodego.NetworkTransferPrice](result)) + + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) +} + +func listNetworkTransferPrices(ctx context.Context, client *linodego.Client, filter string) ([]any, error) { + tflog.Debug(ctx, "Listing Network Transfer Prices", map[string]any{ + "filter_header": filter, + }) + + types, err := client.ListNetworkTransferPrices(ctx, &linodego.ListOptions{ + Filter: filter, + }) + if err != nil { + return nil, err + } + + return helper.TypedSliceToAny(types), nil +} diff --git a/linode/networktransferprices/framework_datasource_schema.go b/linode/networktransferprices/framework_datasource_schema.go new file mode 100644 index 000000000..3db54b351 --- /dev/null +++ b/linode/networktransferprices/framework_datasource_schema.go @@ -0,0 +1,34 @@ +package networktransferprices + +import ( + "github.com/hashicorp/terraform-plugin-framework/datasource/schema" + "github.com/linode/terraform-provider-linode/v2/linode/helper" + "github.com/linode/terraform-provider-linode/v2/linode/helper/frameworkfilter" +) + +var networkTransferPriceSchema = schema.NestedBlockObject{ + Attributes: helper.GetPricingTypeAttributes("Network Transfer Price"), +} + +var filterConfig = frameworkfilter.Config{ + "label": {APIFilterable: true, TypeFunc: frameworkfilter.FilterTypeString}, + "transfer": {APIFilterable: true, TypeFunc: frameworkfilter.FilterTypeInt}, +} + +var frameworkDataSourceSchema = schema.Schema{ + Attributes: map[string]schema.Attribute{ + "id": schema.StringAttribute{ + Description: "The data source's unique ID.", + Computed: true, + }, + "order_by": filterConfig.OrderBySchema(), + "order": filterConfig.OrderSchema(), + }, + Blocks: map[string]schema.Block{ + "filter": filterConfig.Schema(), + "types": schema.ListNestedBlock{ + Description: "The returned list of Network Transfer Prices.", + NestedObject: networkTransferPriceSchema, + }, + }, +} diff --git a/linode/networktransferprices/framework_models.go b/linode/networktransferprices/framework_models.go new file mode 100644 index 000000000..3efb1901a --- /dev/null +++ b/linode/networktransferprices/framework_models.go @@ -0,0 +1,121 @@ +package networktransferprices + +import ( + "github.com/hashicorp/terraform-plugin-framework/attr" + "github.com/hashicorp/terraform-plugin-framework/diag" + "github.com/hashicorp/terraform-plugin-framework/types" + "github.com/hashicorp/terraform-plugin-framework/types/basetypes" + "github.com/linode/linodego" + "github.com/linode/terraform-provider-linode/v2/linode/helper" + "github.com/linode/terraform-provider-linode/v2/linode/helper/frameworkfilter" +) + +type DataSourceModel struct { + ID types.String `tfsdk:"id"` + Label types.String `tfsdk:"label"` + Price types.List `tfsdk:"price"` + RegionPrices types.List `tfsdk:"region_prices"` + Transfer types.Int64 `tfsdk:"transfer"` +} + +func (data *DataSourceModel) parseNetworkTransferPrice(networkTransferPrice *linodego.NetworkTransferPrice, +) diag.Diagnostics { + data.ID = types.StringValue(networkTransferPrice.ID) + + price, diags := flattenPrice(networkTransferPrice.Price) + if diags.HasError() { + return diags + } + data.Price = *price + + data.Label = types.StringValue(networkTransferPrice.Label) + + regionPrices, d := flattenRegionPrices(networkTransferPrice.RegionPrices) + if d.HasError() { + return d + } + data.RegionPrices = *regionPrices + + data.Transfer = types.Int64Value(int64(networkTransferPrice.Transfer)) + + return nil +} + +func flattenPrice(price linodego.NetworkTransferTypePrice) ( + *basetypes.ListValue, diag.Diagnostics, +) { + result := make(map[string]attr.Value) + + result["hourly"] = types.Float64Value(float64(price.Hourly)) + result["monthly"] = types.Float64Value(float64(price.Monthly)) + + obj, diag := types.ObjectValue(helper.PriceObjectType.AttrTypes, result) + if diag.HasError() { + return nil, diag + } + + objList := []attr.Value{obj} + + resultList, diag := types.ListValue( + helper.PriceObjectType, + objList, + ) + if diag.HasError() { + return nil, diag + } + + return &resultList, nil +} + +func flattenRegionPrices(prices []linodego.NetworkTransferTypeRegionPrice) ( + *basetypes.ListValue, diag.Diagnostics, +) { + result := make([]attr.Value, len(prices)) + + for i, price := range prices { + obj, d := types.ObjectValue(helper.RegionPriceObjectType.AttrTypes, map[string]attr.Value{ + "id": types.StringValue(price.ID), + "hourly": types.Float64Value(float64(price.Hourly)), + "monthly": types.Float64Value(float64(price.Monthly)), + }) + if d.HasError() { + return nil, d + } + + result[i] = obj + } + + priceList, d := basetypes.NewListValue( + helper.RegionPriceObjectType, + result, + ) + return &priceList, d +} + +type NetworkTransferPriceFilterModel struct { + ID types.String `tfsdk:"id"` + Order types.String `tfsdk:"order"` + OrderBy types.String `tfsdk:"order_by"` + Filters frameworkfilter.FiltersModelType `tfsdk:"filter"` + Types []DataSourceModel `tfsdk:"types"` +} + +func (model *NetworkTransferPriceFilterModel) parseNetworkTransferPrices(networkTransferPrices []linodego.NetworkTransferPrice, +) diag.Diagnostics { + result := make([]DataSourceModel, len(networkTransferPrices)) + + for i := range networkTransferPrices { + var m DataSourceModel + + diags := m.parseNetworkTransferPrice(&networkTransferPrices[i]) + if diags.HasError() { + return diags + } + + result[i] = m + } + + model.Types = result + + return nil +} diff --git a/linode/networktransferprices/tmpl/data_basic.gotf b/linode/networktransferprices/tmpl/data_basic.gotf new file mode 100644 index 000000000..423075e6f --- /dev/null +++ b/linode/networktransferprices/tmpl/data_basic.gotf @@ -0,0 +1,10 @@ +{{ define "network_transfer_prices_data_basic" }} + +data "linode_network_transfer_prices" "foobar" { + filter { + name = "label" + values = ["Network Transfer"] + } +} + +{{ end }} \ No newline at end of file diff --git a/linode/networktransferprices/tmpl/template.go b/linode/networktransferprices/tmpl/template.go new file mode 100644 index 000000000..fe21d70d6 --- /dev/null +++ b/linode/networktransferprices/tmpl/template.go @@ -0,0 +1,12 @@ +package tmpl + +import ( + "testing" + + "github.com/linode/terraform-provider-linode/v2/linode/acceptance" +) + +func DataBasic(t *testing.T) string { + return acceptance.ExecuteTemplate(t, + "network_transfer_prices_data_basic", nil) +} diff --git a/linode/volumetypes/datasource_test.go b/linode/volumetypes/datasource_test.go new file mode 100644 index 000000000..ab9a17285 --- /dev/null +++ b/linode/volumetypes/datasource_test.go @@ -0,0 +1,38 @@ +//go:build integration || volumetypes + +package volumetypes_test + +import ( + "testing" + + "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/linode/terraform-provider-linode/v2/linode/acceptance" + "github.com/linode/terraform-provider-linode/v2/linode/volumetypes/tmpl" +) + +func TestAccDataSourceVolumeTypes_basic(t *testing.T) { + t.Parallel() + + dataSourceName := "data.linode_volume_types.foobar" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acceptance.PreCheck(t) }, + ProtoV5ProviderFactories: acceptance.ProtoV5ProviderFactories, + Steps: []resource.TestStep{ + { + Config: tmpl.DataBasic(t), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(dataSourceName, "types.#", "1"), + resource.TestCheckResourceAttr(dataSourceName, "types.0.id", "volume"), + resource.TestCheckResourceAttr(dataSourceName, "types.0.label", "Storage Volume"), + resource.TestCheckResourceAttrSet(dataSourceName, "types.0.transfer"), + resource.TestCheckResourceAttrSet(dataSourceName, "types.0.price.0.hourly"), + resource.TestCheckResourceAttrSet(dataSourceName, "types.0.price.0.monthly"), + resource.TestCheckResourceAttrSet(dataSourceName, "types.0.region_prices.0.id"), + resource.TestCheckResourceAttrSet(dataSourceName, "types.0.region_prices.0.hourly"), + resource.TestCheckResourceAttrSet(dataSourceName, "types.0.region_prices.0.monthly"), + ), + }, + }, + }) +} diff --git a/linode/volumetypes/framework_datasource.go b/linode/volumetypes/framework_datasource.go new file mode 100644 index 000000000..f08ecb3b6 --- /dev/null +++ b/linode/volumetypes/framework_datasource.go @@ -0,0 +1,73 @@ +package volumetypes + +import ( + "context" + + "github.com/hashicorp/terraform-plugin-framework/datasource" + "github.com/hashicorp/terraform-plugin-log/tflog" + "github.com/linode/linodego" + "github.com/linode/terraform-provider-linode/v2/linode/helper" +) + +func NewDataSource() datasource.DataSource { + return &DataSource{ + BaseDataSource: helper.NewBaseDataSource( + helper.BaseDataSourceConfig{ + Name: "linode_volume_types", + Schema: &frameworkDataSourceSchema, + }, + ), + } +} + +type DataSource struct { + helper.BaseDataSource +} + +func (r *DataSource) Read( + ctx context.Context, + req datasource.ReadRequest, + resp *datasource.ReadResponse, +) { + tflog.Debug(ctx, "Read data.linode_volume_types") + + var data VolumeTypeFilterModel + + resp.Diagnostics.Append(req.Config.Get(ctx, &data)...) + if resp.Diagnostics.HasError() { + return + } + + id, d := filterConfig.GenerateID(data.Filters) + if d != nil { + resp.Diagnostics.Append(d) + return + } + data.ID = id + + result, d := filterConfig.GetAndFilter( + ctx, r.Meta.Client, data.Filters, listVolumeTypes, data.Order, data.OrderBy) + if d != nil { + resp.Diagnostics.Append(d) + return + } + + data.parseVolumeTypes(helper.AnySliceToTyped[linodego.VolumeType](result)) + + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) +} + +func listVolumeTypes(ctx context.Context, client *linodego.Client, filter string) ([]any, error) { + tflog.Debug(ctx, "Listing Volume types", map[string]any{ + "filter_header": filter, + }) + + types, err := client.ListVolumeTypes(ctx, &linodego.ListOptions{ + Filter: filter, + }) + if err != nil { + return nil, err + } + + return helper.TypedSliceToAny(types), nil +} diff --git a/linode/volumetypes/framework_datasource_schema.go b/linode/volumetypes/framework_datasource_schema.go new file mode 100644 index 000000000..71d5bd3ad --- /dev/null +++ b/linode/volumetypes/framework_datasource_schema.go @@ -0,0 +1,34 @@ +package volumetypes + +import ( + "github.com/hashicorp/terraform-plugin-framework/datasource/schema" + "github.com/linode/terraform-provider-linode/v2/linode/helper" + "github.com/linode/terraform-provider-linode/v2/linode/helper/frameworkfilter" +) + +var volumeTypeSchema = schema.NestedBlockObject{ + Attributes: helper.GetPricingTypeAttributes("Volume Type"), +} + +var filterConfig = frameworkfilter.Config{ + "label": {APIFilterable: true, TypeFunc: frameworkfilter.FilterTypeString}, + "transfer": {APIFilterable: true, TypeFunc: frameworkfilter.FilterTypeInt}, +} + +var frameworkDataSourceSchema = schema.Schema{ + Attributes: map[string]schema.Attribute{ + "id": schema.StringAttribute{ + Description: "The data source's unique ID.", + Computed: true, + }, + "order_by": filterConfig.OrderBySchema(), + "order": filterConfig.OrderSchema(), + }, + Blocks: map[string]schema.Block{ + "filter": filterConfig.Schema(), + "types": schema.ListNestedBlock{ + Description: "The returned list of Volume types.", + NestedObject: volumeTypeSchema, + }, + }, +} diff --git a/linode/volumetypes/framework_models.go b/linode/volumetypes/framework_models.go new file mode 100644 index 000000000..07a8afed2 --- /dev/null +++ b/linode/volumetypes/framework_models.go @@ -0,0 +1,121 @@ +package volumetypes + +import ( + "github.com/hashicorp/terraform-plugin-framework/attr" + "github.com/hashicorp/terraform-plugin-framework/diag" + "github.com/hashicorp/terraform-plugin-framework/types" + "github.com/hashicorp/terraform-plugin-framework/types/basetypes" + "github.com/linode/linodego" + "github.com/linode/terraform-provider-linode/v2/linode/helper" + "github.com/linode/terraform-provider-linode/v2/linode/helper/frameworkfilter" +) + +type DataSourceModel struct { + ID types.String `tfsdk:"id"` + Label types.String `tfsdk:"label"` + Price types.List `tfsdk:"price"` + RegionPrices types.List `tfsdk:"region_prices"` + Transfer types.Int64 `tfsdk:"transfer"` +} + +func (data *DataSourceModel) parseVolumeType(volumeType *linodego.VolumeType, +) diag.Diagnostics { + data.ID = types.StringValue(volumeType.ID) + + price, diags := flattenPrice(volumeType.Price) + if diags.HasError() { + return diags + } + data.Price = *price + + data.Label = types.StringValue(volumeType.Label) + + regionPrices, d := flattenRegionPrices(volumeType.RegionPrices) + if d.HasError() { + return d + } + data.RegionPrices = *regionPrices + + data.Transfer = types.Int64Value(int64(volumeType.Transfer)) + + return nil +} + +func flattenPrice(price linodego.VolumeTypePrice) ( + *basetypes.ListValue, diag.Diagnostics, +) { + result := make(map[string]attr.Value) + + result["hourly"] = types.Float64Value(float64(price.Hourly)) + result["monthly"] = types.Float64Value(float64(price.Monthly)) + + obj, diag := types.ObjectValue(helper.PriceObjectType.AttrTypes, result) + if diag.HasError() { + return nil, diag + } + + objList := []attr.Value{obj} + + resultList, diag := types.ListValue( + helper.PriceObjectType, + objList, + ) + if diag.HasError() { + return nil, diag + } + + return &resultList, nil +} + +func flattenRegionPrices(prices []linodego.VolumeTypeRegionPrice) ( + *basetypes.ListValue, diag.Diagnostics, +) { + result := make([]attr.Value, len(prices)) + + for i, price := range prices { + obj, d := types.ObjectValue(helper.RegionPriceObjectType.AttrTypes, map[string]attr.Value{ + "id": types.StringValue(price.ID), + "hourly": types.Float64Value(float64(price.Hourly)), + "monthly": types.Float64Value(float64(price.Monthly)), + }) + if d.HasError() { + return nil, d + } + + result[i] = obj + } + + priceList, d := basetypes.NewListValue( + helper.RegionPriceObjectType, + result, + ) + return &priceList, d +} + +type VolumeTypeFilterModel struct { + ID types.String `tfsdk:"id"` + Order types.String `tfsdk:"order"` + OrderBy types.String `tfsdk:"order_by"` + Filters frameworkfilter.FiltersModelType `tfsdk:"filter"` + Types []DataSourceModel `tfsdk:"types"` +} + +func (model *VolumeTypeFilterModel) parseVolumeTypes(volumeTypes []linodego.VolumeType, +) diag.Diagnostics { + result := make([]DataSourceModel, len(volumeTypes)) + + for i := range volumeTypes { + var m DataSourceModel + + diags := m.parseVolumeType(&volumeTypes[i]) + if diags.HasError() { + return diags + } + + result[i] = m + } + + model.Types = result + + return nil +} diff --git a/linode/volumetypes/tmpl/data_basic.gotf b/linode/volumetypes/tmpl/data_basic.gotf new file mode 100644 index 000000000..341fba2c9 --- /dev/null +++ b/linode/volumetypes/tmpl/data_basic.gotf @@ -0,0 +1,10 @@ +{{ define "volume_types_data_basic" }} + +data "linode_volume_types" "foobar" { + filter { + name = "label" + values = ["Storage Volume"] + } +} + +{{ end }} \ No newline at end of file diff --git a/linode/volumetypes/tmpl/template.go b/linode/volumetypes/tmpl/template.go new file mode 100644 index 000000000..2ff0f75fe --- /dev/null +++ b/linode/volumetypes/tmpl/template.go @@ -0,0 +1,12 @@ +package tmpl + +import ( + "testing" + + "github.com/linode/terraform-provider-linode/v2/linode/acceptance" +) + +func DataBasic(t *testing.T) string { + return acceptance.ExecuteTemplate(t, + "volume_types_data_basic", nil) +}