diff --git a/docs/data-sources/machine_type.md b/docs/data-sources/machine_type.md new file mode 100644 index 000000000..c096f1d01 --- /dev/null +++ b/docs/data-sources/machine_type.md @@ -0,0 +1,67 @@ +--- +# generated by https://github.com/hashicorp/terraform-plugin-docs +page_title: "stackit_machine_type Data Source - stackit" +subcategory: "" +description: |- + Machine type data source. +--- + +# stackit_machine_type (Data Source) + +Machine type data source. + +## Example Usage + +```terraform +data "stackit_machine_type" "two_vcpus_filter" { + project_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" + filter = "vcpus==2" +} + +data "stackit_machine_type" "filter_sorted_ascending_false" { + project_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" + filter = "vcpus >= 2 && ram >= 2048" + sort_ascending = false +} + +data "stackit_machine_type" "intel_icelake_generic_filter" { + project_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" + filter = "extraSpecs.cpu==\"intel-icelake-generic\" && vcpus == 2" +} + +# returns warning +data "stackit_machine_type" "no_match" { + project_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" + filter = "vcpus == 99" +} +``` + + +## Schema + +### Required + +- `filter` (String) Expr-lang filter for filtering machine types. + +Examples: +- vcpus == 2 +- ram >= 2048 +- extraSpecs.cpu == "intel-icelake-generic" +- extraSpecs.cpu == "intel-icelake-generic" && vcpus == 2 + +See https://expr-lang.org/docs/language-definition for syntax. +- `project_id` (String) STACKIT Project ID. + +### Optional + +- `sort_ascending` (Boolean) Sort machine types by name ascending (`true`) or descending (`false`). Defaults to `false` + +### Read-Only + +- `description` (String) Machine type description. +- `disk` (Number) Disk size in GB. +- `extra_specs` (Map of String) Extra specs (e.g., CPU type, overcommit ratio). +- `id` (String) Terraform's internal resource ID. It is structured as "`project_id`,`image_id`". +- `name` (String) Name of the machine type (e.g. 's1.2'). +- `ram` (Number) RAM size in MB. +- `vcpus` (Number) Number of vCPUs. diff --git a/examples/data-sources/stackit_machine_type/data-source.tf b/examples/data-sources/stackit_machine_type/data-source.tf new file mode 100644 index 000000000..6120b15fc --- /dev/null +++ b/examples/data-sources/stackit_machine_type/data-source.tf @@ -0,0 +1,21 @@ +data "stackit_machine_type" "two_vcpus_filter" { + project_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" + filter = "vcpus==2" +} + +data "stackit_machine_type" "filter_sorted_ascending_false" { + project_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" + filter = "vcpus >= 2 && ram >= 2048" + sort_ascending = false +} + +data "stackit_machine_type" "intel_icelake_generic_filter" { + project_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" + filter = "extraSpecs.cpu==\"intel-icelake-generic\" && vcpus == 2" +} + +# returns warning +data "stackit_machine_type" "no_match" { + project_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" + filter = "vcpus == 99" +} \ No newline at end of file diff --git a/stackit/internal/services/iaas/iaas_acc_test.go b/stackit/internal/services/iaas/iaas_acc_test.go index 38b04894f..645eca304 100644 --- a/stackit/internal/services/iaas/iaas_acc_test.go +++ b/stackit/internal/services/iaas/iaas_acc_test.go @@ -88,6 +88,9 @@ var ( //go:embed testdata/resource-server-max-server-attachments.tf resourceServerMaxAttachmentConfig string + + //go:embed testdata/datasource-machinetype.tf + dataSourceMachineTypeConfig string ) const ( @@ -487,6 +490,10 @@ var testConfigKeyPairMaxUpdated = func() config.Variables { return updatedConfig }() +var testConfigMachineTypeVars = config.Variables{ + "project_id": config.StringVariable(testutil.ProjectId), +} + // if no local file is provided the test should create a default file and work with this instead of failing var localFileForIaasImage os.File @@ -4022,6 +4029,47 @@ func TestAccImageMax(t *testing.T) { }) } +func TestAccMachineTyp(t *testing.T) { + t.Logf("TestAccMachineTyp projectid: %s", testutil.ConvertConfigVariable(testConfigMachineTypeVars["project_id"])) + resource.ParallelTest(t, resource.TestCase{ + ProtoV6ProviderFactories: testutil.TestAccProtoV6ProviderFactories, + Steps: []resource.TestStep{ + { + ConfigVariables: testConfigMachineTypeVars, + Config: fmt.Sprintf("%s\n%s", dataSourceMachineTypeConfig, testutil.IaaSProviderConfig()), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("data.stackit_machine_type.two_vcpus_filter", "project_id", testutil.ConvertConfigVariable(testConfigMachineTypeVars["project_id"])), + resource.TestCheckResourceAttrSet("data.stackit_machine_type.two_vcpus_filter", "id"), + resource.TestCheckResourceAttrSet("data.stackit_machine_type.two_vcpus_filter", "name"), + resource.TestCheckResourceAttrSet("data.stackit_machine_type.two_vcpus_filter", "vcpus"), + resource.TestCheckResourceAttr("data.stackit_machine_type.two_vcpus_filter", "vcpus", "2"), + resource.TestCheckResourceAttrSet("data.stackit_machine_type.two_vcpus_filter", "ram"), + resource.TestCheckResourceAttrSet("data.stackit_machine_type.two_vcpus_filter", "disk"), + resource.TestCheckResourceAttrSet("data.stackit_machine_type.two_vcpus_filter", "description"), + resource.TestCheckResourceAttrSet("data.stackit_machine_type.two_vcpus_filter", "extra_specs.cpu"), + + resource.TestCheckResourceAttr("data.stackit_machine_type.filter_sorted_ascending_false", "project_id", testutil.ConvertConfigVariable(testConfigMachineTypeVars["project_id"])), + resource.TestCheckResourceAttrSet("data.stackit_machine_type.filter_sorted_ascending_false", "id"), + resource.TestCheckResourceAttrSet("data.stackit_machine_type.filter_sorted_ascending_false", "name"), + resource.TestCheckResourceAttrSet("data.stackit_machine_type.filter_sorted_ascending_false", "vcpus"), + resource.TestCheckResourceAttrSet("data.stackit_machine_type.filter_sorted_ascending_false", "ram"), + resource.TestCheckResourceAttrSet("data.stackit_machine_type.filter_sorted_ascending_false", "disk"), + resource.TestCheckResourceAttrSet("data.stackit_machine_type.filter_sorted_ascending_false", "description"), + resource.TestCheckResourceAttrSet("data.stackit_machine_type.filter_sorted_ascending_false", "extra_specs.cpu"), + + resource.TestCheckResourceAttr("data.stackit_machine_type.no_match", "project_id", testutil.ConvertConfigVariable(testConfigMachineTypeVars["project_id"])), + resource.TestCheckNoResourceAttr("data.stackit_machine_type.no_match", "description"), + resource.TestCheckNoResourceAttr("data.stackit_machine_type.no_match", "disk"), + resource.TestCheckNoResourceAttr("data.stackit_machine_type.no_match", "extra_specs"), + resource.TestCheckNoResourceAttr("data.stackit_machine_type.no_match", "id"), + resource.TestCheckNoResourceAttr("data.stackit_machine_type.no_match", "name"), + resource.TestCheckNoResourceAttr("data.stackit_machine_type.no_match", "ram"), + ), + }, + }, + }) +} + func testAccCheckDestroy(s *terraform.State) error { checkFunctions := []func(s *terraform.State) error{ testAccCheckNetworkV1Destroy, diff --git a/stackit/internal/services/iaas/machinetype/datasource.go b/stackit/internal/services/iaas/machinetype/datasource.go new file mode 100644 index 000000000..3f3301126 --- /dev/null +++ b/stackit/internal/services/iaas/machinetype/datasource.go @@ -0,0 +1,237 @@ +package machineType + +import ( + "context" + "fmt" + "net/http" + "sort" + "strings" + + "github.com/hashicorp/terraform-plugin-framework/datasource" + "github.com/hashicorp/terraform-plugin-framework/datasource/schema" + "github.com/hashicorp/terraform-plugin-framework/diag" + "github.com/hashicorp/terraform-plugin-framework/schema/validator" + "github.com/hashicorp/terraform-plugin-framework/types" + "github.com/hashicorp/terraform-plugin-log/tflog" + "github.com/stackitcloud/stackit-sdk-go/services/iaas" + "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/conversion" + "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/core" + iaasUtils "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/services/iaas/utils" + "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/utils" + "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/validate" +) + +// Ensure the implementation satisfies the expected interfaces. +var _ datasource.DataSource = &machineTypeDataSource{} + +type DataSourceModel struct { + Id types.String `tfsdk:"id"` // required by Terraform to identify state + ProjectId types.String `tfsdk:"project_id"` + SortAscending types.Bool `tfsdk:"sort_ascending"` + Filter types.String `tfsdk:"filter"` + Description types.String `tfsdk:"description"` + Disk types.Int64 `tfsdk:"disk"` + ExtraSpecs types.Map `tfsdk:"extra_specs"` + Name types.String `tfsdk:"name"` + Ram types.Int64 `tfsdk:"ram"` + Vcpus types.Int64 `tfsdk:"vcpus"` +} + +// NewMachineTypeDataSource instantiates the data source +func NewMachineTypeDataSource() datasource.DataSource { + return &machineTypeDataSource{} +} + +type machineTypeDataSource struct { + client *iaas.APIClient +} + +func (m *machineTypeDataSource) Metadata(_ context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) { + resp.TypeName = req.ProviderTypeName + "_machine_type" +} + +func (m *machineTypeDataSource) Configure(ctx context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) { + providerData, ok := conversion.ParseProviderData(ctx, req.ProviderData, &resp.Diagnostics) + if !ok { + return + } + + client := iaasUtils.ConfigureClient(ctx, &providerData, &resp.Diagnostics) + if resp.Diagnostics.HasError() { + return + } + m.client = client + + tflog.Info(ctx, "IAAS client configured") +} + +func (m *machineTypeDataSource) Schema(_ context.Context, _ datasource.SchemaRequest, resp *datasource.SchemaResponse) { + resp.Schema = schema.Schema{ + MarkdownDescription: "Machine type data source.", + Attributes: map[string]schema.Attribute{ + "id": schema.StringAttribute{ + Description: "Terraform's internal resource ID. It is structured as \"`project_id`,`image_id`\".", + Computed: true, + }, + "project_id": schema.StringAttribute{ + Description: "STACKIT Project ID.", + Required: true, + Validators: []validator.String{ + validate.UUID(), + validate.NoSeparator(), + }, + }, + "sort_ascending": schema.BoolAttribute{ + Description: "Sort machine types by name ascending (`true`) or descending (`false`). Defaults to `false`", + Optional: true, + }, + "filter": schema.StringAttribute{ + Description: `Expr-lang filter for filtering machine types. + +Examples: +- vcpus == 2 +- ram >= 2048 +- extraSpecs.cpu == "intel-icelake-generic" +- extraSpecs.cpu == "intel-icelake-generic" && vcpus == 2 + +See https://expr-lang.org/docs/language-definition for syntax.`, + Required: true, + }, + "description": schema.StringAttribute{ + Description: "Machine type description.", + Computed: true, + }, + "disk": schema.Int64Attribute{ + Description: "Disk size in GB.", + Computed: true, + }, + "extra_specs": schema.MapAttribute{ + Description: "Extra specs (e.g., CPU type, overcommit ratio).", + ElementType: types.StringType, + Computed: true, + }, + "name": schema.StringAttribute{ + Description: "Name of the machine type (e.g. 's1.2').", + Computed: true, + }, + "ram": schema.Int64Attribute{ + Description: "RAM size in MB.", + Computed: true, + }, + "vcpus": schema.Int64Attribute{ + Description: "Number of vCPUs.", + Computed: true, + }, + }, + } +} + +func (m *machineTypeDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { // nolint:gocritic // function signature required by Terraform + var model DataSourceModel + resp.Diagnostics.Append(req.Config.Get(ctx, &model)...) + if resp.Diagnostics.HasError() { + return + } + + projectId := model.ProjectId.ValueString() + sortAscending := model.SortAscending.ValueBool() + + ctx = tflog.SetField(ctx, "project_id", projectId) + ctx = tflog.SetField(ctx, "filter_is_null", model.Filter.IsNull()) + ctx = tflog.SetField(ctx, "filter_is_unknown", model.Filter.IsUnknown()) + + listMachineTypeReq := m.client.ListMachineTypes(ctx, projectId) + + if !model.Filter.IsNull() && !model.Filter.IsUnknown() && strings.TrimSpace(model.Filter.ValueString()) != "" { + listMachineTypeReq = listMachineTypeReq.Filter(strings.TrimSpace(model.Filter.ValueString())) + } + + apiResp, err := listMachineTypeReq.Execute() + if err != nil { + utils.LogError(ctx, &resp.Diagnostics, err, "Failed to read machine types", + fmt.Sprintf("Unable to retrieve machine types for project %q %s.", projectId, err), + map[int]string{ + http.StatusForbidden: fmt.Sprintf("Access denied to project %q.", projectId), + }, + ) + resp.State.RemoveResource(ctx) + return + } + + if apiResp.Items == nil || len(*apiResp.Items) == 0 { + core.LogAndAddWarning(ctx, &resp.Diagnostics, "No machine types found", "No matching machine types.") + return + } + + // Convert items to []*iaas.MachineType + machineTypes := make([]*iaas.MachineType, len(*apiResp.Items)) + for i := range *apiResp.Items { + machineTypes[i] = &(*apiResp.Items)[i] + } + + sorted, err := sortMachineTypeByName(machineTypes, sortAscending) + if err != nil { + core.LogAndAddWarning(ctx, &resp.Diagnostics, "Unable to sort", err.Error()) + return + } + + first := sorted[0] + if err := mapDataSourceFields(ctx, first, &model); err != nil { + core.LogAndAddError(ctx, &resp.Diagnostics, "Mapping error", fmt.Sprintf("Failed to translate API response: %v", err)) + return + } + + resp.Diagnostics.Append(resp.State.Set(ctx, model)...) + tflog.Info(ctx, "Successfully read machine type") +} + +func mapDataSourceFields(ctx context.Context, machineType *iaas.MachineType, model *DataSourceModel) error { + if machineType == nil || model == nil { + return fmt.Errorf("nil input provided") + } + + if machineType.Name == nil || *machineType.Name == "" { + return fmt.Errorf("machine type name is missing") + } + + model.Id = utils.BuildInternalTerraformId(model.ProjectId.ValueString(), *machineType.Name) + model.Name = types.StringPointerValue(machineType.Name) + model.Description = types.StringPointerValue(machineType.Description) + model.Disk = types.Int64PointerValue(machineType.Disk) + model.Ram = types.Int64PointerValue(machineType.Ram) + model.Vcpus = types.Int64PointerValue(machineType.Vcpus) + + extra := types.MapNull(types.StringType) + if machineType.ExtraSpecs != nil && len(*machineType.ExtraSpecs) > 0 { + var diags diag.Diagnostics + extra, diags = types.MapValueFrom(ctx, types.StringType, *machineType.ExtraSpecs) + if diags.HasError() { + return fmt.Errorf("converting extraspecs: %w", core.DiagsToError(diags)) + } + } + model.ExtraSpecs = extra + return nil +} + +func sortMachineTypeByName(input []*iaas.MachineType, ascending bool) ([]*iaas.MachineType, error) { + if input == nil { + return nil, fmt.Errorf("input slice is nil") + } + + // Filter out nil or missing name + filtered := make([]*iaas.MachineType, 0) + for _, m := range input { + if m != nil && m.Name != nil { + filtered = append(filtered, m) + } + } + + sort.SliceStable(filtered, func(i, j int) bool { + if ascending { + return *filtered[i].Name < *filtered[j].Name + } + return *filtered[i].Name > *filtered[j].Name + }) + + return filtered, nil +} diff --git a/stackit/internal/services/iaas/machinetype/datasource_test.go b/stackit/internal/services/iaas/machinetype/datasource_test.go new file mode 100644 index 000000000..3fde4794d --- /dev/null +++ b/stackit/internal/services/iaas/machinetype/datasource_test.go @@ -0,0 +1,241 @@ +package machineType + +import ( + "context" + "strings" + "testing" + + "github.com/google/go-cmp/cmp" + "github.com/hashicorp/terraform-plugin-framework/attr" + "github.com/hashicorp/terraform-plugin-framework/types" + "github.com/stackitcloud/stackit-sdk-go/core/utils" + "github.com/stackitcloud/stackit-sdk-go/services/iaas" +) + +func TestMapDataSourceFields(t *testing.T) { + tests := []struct { + name string + initial DataSourceModel + input *iaas.MachineType + expected DataSourceModel + expectError bool + }{ + { + name: "valid simple values", + initial: DataSourceModel{ + ProjectId: types.StringValue("pid"), + }, + input: &iaas.MachineType{ + Name: utils.Ptr("s1.2"), + Description: utils.Ptr("general-purpose small"), + Disk: utils.Ptr(int64(20)), + Ram: utils.Ptr(int64(2048)), + Vcpus: utils.Ptr(int64(2)), + ExtraSpecs: &map[string]interface{}{ + "cpu": "amd-epycrome-7702", + "overcommit": "1", + "environment": "general", + }, + }, + expected: DataSourceModel{ + Id: types.StringValue("pid,s1.2"), + ProjectId: types.StringValue("pid"), + Name: types.StringValue("s1.2"), + Description: types.StringValue("general-purpose small"), + Disk: types.Int64Value(20), + Ram: types.Int64Value(2048), + Vcpus: types.Int64Value(2), + ExtraSpecs: types.MapValueMust(types.StringType, map[string]attr.Value{ + "cpu": types.StringValue("amd-epycrome-7702"), + "overcommit": types.StringValue("1"), + "environment": types.StringValue("general"), + }), + }, + expectError: false, + }, + { + name: "missing name should fail", + initial: DataSourceModel{ + ProjectId: types.StringValue("pid-456"), + }, + input: &iaas.MachineType{ + Description: utils.Ptr("gp-medium"), + }, + expected: DataSourceModel{}, + expectError: true, + }, + { + name: "nil machineType should fail", + initial: DataSourceModel{}, + input: nil, + expected: DataSourceModel{}, + expectError: true, + }, + { + name: "empty extraSpecs should return null map", + initial: DataSourceModel{ + ProjectId: types.StringValue("pid-789"), + }, + input: &iaas.MachineType{ + Name: utils.Ptr("m1.noextras"), + Description: utils.Ptr("no extras"), + Disk: utils.Ptr(int64(10)), + Ram: utils.Ptr(int64(1024)), + Vcpus: utils.Ptr(int64(1)), + ExtraSpecs: &map[string]interface{}{}, + }, + expected: DataSourceModel{ + Id: types.StringValue("pid-789,m1.noextras"), + ProjectId: types.StringValue("pid-789"), + Name: types.StringValue("m1.noextras"), + Description: types.StringValue("no extras"), + Disk: types.Int64Value(10), + Ram: types.Int64Value(1024), + Vcpus: types.Int64Value(1), + ExtraSpecs: types.MapNull(types.StringType), + }, + expectError: false, + }, + { + name: "nil extrasSpecs should return null map", + initial: DataSourceModel{ + ProjectId: types.StringValue("pid-987"), + }, + input: &iaas.MachineType{ + Name: utils.Ptr("g1.nil"), + Description: utils.Ptr("missing extras"), + Disk: utils.Ptr(int64(40)), + Ram: utils.Ptr(int64(8096)), + Vcpus: utils.Ptr(int64(4)), + ExtraSpecs: nil, + }, + expected: DataSourceModel{ + Id: types.StringValue("pid-987,g1.nil"), + ProjectId: types.StringValue("pid-987"), + Name: types.StringValue("g1.nil"), + Description: types.StringValue("missing extras"), + Disk: types.Int64Value(40), + Ram: types.Int64Value(8096), + Vcpus: types.Int64Value(4), + ExtraSpecs: types.MapNull(types.StringType), + }, + expectError: false, + }, + { + name: "invalid extraSpecs with non-string values", + initial: DataSourceModel{ + ProjectId: types.StringValue("test-err"), + }, + input: &iaas.MachineType{ + Name: utils.Ptr("invalid"), + Description: utils.Ptr("bad map"), + Disk: utils.Ptr(int64(10)), + Ram: utils.Ptr(int64(4096)), + Vcpus: utils.Ptr(int64(2)), + ExtraSpecs: &map[string]interface{}{ + "cpu": "intel", + "burst": true, // not a string + "gen": 8, // not a string + }, + }, + expected: DataSourceModel{}, + expectError: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + err := mapDataSourceFields(context.Background(), tt.input, &tt.initial) + if tt.expectError { + if err == nil { + t.Errorf("expected error but got none") + } + return + } + + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + + diff := cmp.Diff(tt.expected, tt.initial) + if diff != "" { + t.Errorf("unexpected diff (-want +got):\n%s", diff) + } + + // Extra sanity check for proper ID format + if id := tt.initial.Id.ValueString(); !strings.HasPrefix(id, tt.initial.ProjectId.ValueString()+",") { + t.Errorf("unexpected ID format: got %q", id) + } + }) + } +} + +func TestSortMachineTypeByName(t *testing.T) { + tests := []struct { + name string + input []*iaas.MachineType + ascending bool + expected []string + expectError bool + }{ + { + name: "ascending order", + input: []*iaas.MachineType{{Name: utils.Ptr("zeta")}, {Name: utils.Ptr("alpha")}, {Name: utils.Ptr("gamma")}}, + ascending: true, + expected: []string{"alpha", "gamma", "zeta"}, + }, + { + name: "descending order", + input: []*iaas.MachineType{{Name: utils.Ptr("zeta")}, {Name: utils.Ptr("alpha")}, {Name: utils.Ptr("gamma")}}, + ascending: false, + expected: []string{"zeta", "gamma", "alpha"}, + }, + { + name: "handles nil names", + input: []*iaas.MachineType{{Name: utils.Ptr("beta")}, nil, {Name: nil}, {Name: utils.Ptr("alpha")}}, + ascending: true, + expected: []string{"alpha", "beta"}, + }, + { + name: "empty input", + input: []*iaas.MachineType{}, + ascending: true, + expected: nil, + expectError: false, + }, + { + name: "nil input", + input: nil, + ascending: true, + expectError: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + sorted, err := sortMachineTypeByName(tt.input, tt.ascending) + + if tt.expectError { + if err == nil { + t.Errorf("expected error but got none") + } + return + } + + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + + var result []string + for _, mt := range sorted { + if mt.Name != nil { + result = append(result, *mt.Name) + } + } + + if diff := cmp.Diff(tt.expected, result); diff != "" { + t.Errorf("unexpected sorted order (-want +got):\n%s", diff) + } + }) + } +} diff --git a/stackit/internal/services/iaas/testdata/datasource-machinetype.tf b/stackit/internal/services/iaas/testdata/datasource-machinetype.tf new file mode 100644 index 000000000..3475f34db --- /dev/null +++ b/stackit/internal/services/iaas/testdata/datasource-machinetype.tf @@ -0,0 +1,18 @@ +variable "project_id" {} + +data "stackit_machine_type" "two_vcpus_filter" { + project_id = var.project_id + filter = "vcpus==2" +} + +data "stackit_machine_type" "filter_sorted_ascending_false" { + project_id = var.project_id + filter = "vcpus >= 2 && ram >= 2048" + sort_ascending = false +} + +# returns warning +data "stackit_machine_type" "no_match" { + project_id = var.project_id + filter = "vcpus == 99" +} \ No newline at end of file diff --git a/stackit/provider.go b/stackit/provider.go index c7d0953bc..438711c71 100644 --- a/stackit/provider.go +++ b/stackit/provider.go @@ -27,6 +27,7 @@ import ( iaasAffinityGroup "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/services/iaas/affinitygroup" iaasImage "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/services/iaas/image" iaasKeyPair "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/services/iaas/keypair" + machineType "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/services/iaas/machinetype" iaasNetwork "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/services/iaas/network" iaasNetworkArea "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/services/iaas/networkarea" iaasNetworkAreaRoute "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/services/iaas/networkarearoute" @@ -474,6 +475,7 @@ func (p *Provider) DataSources(_ context.Context) []func() datasource.DataSource logMeInstance.NewInstanceDataSource, logMeCredential.NewCredentialDataSource, logAlertGroup.NewLogAlertGroupDataSource, + machineType.NewMachineTypeDataSource, mariaDBInstance.NewInstanceDataSource, mariaDBCredential.NewCredentialDataSource, mongoDBFlexInstance.NewInstanceDataSource,