package sqlserverFlexBetaFlavor import ( "context" "fmt" "github.com/hashicorp/terraform-plugin-framework/attr" "github.com/hashicorp/terraform-plugin-framework/datasource" "github.com/hashicorp/terraform-plugin-framework/datasource/schema" "github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-plugin-framework/types/basetypes" "github.com/hashicorp/terraform-plugin-log/tflog" "github.com/stackitcloud/stackit-sdk-go/core/config" "tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit/internal/conversion" "tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit/internal/core" "tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit/internal/utils" sqlserverflexbetaPkg "tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/pkg_gen/sqlserverflexbeta" sqlserverflexbetaGen "tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit/internal/services/sqlserverflexbeta/flavor/datasources_gen" ) // Ensure the implementation satisfies the expected interfaces. var ( _ datasource.DataSource = &flavorDataSource{} _ datasource.DataSourceWithConfigure = &flavorDataSource{} ) type FlavorModel struct { ProjectId types.String `tfsdk:"project_id"` Region types.String `tfsdk:"region"` StorageClass types.String `tfsdk:"storage_class"` Cpu types.Int64 `tfsdk:"cpu"` Description types.String `tfsdk:"description"` Id types.String `tfsdk:"id"` FlavorId types.String `tfsdk:"flavor_id"` MaxGb types.Int64 `tfsdk:"max_gb"` Memory types.Int64 `tfsdk:"ram"` MinGb types.Int64 `tfsdk:"min_gb"` NodeType types.String `tfsdk:"node_type"` StorageClasses types.List `tfsdk:"storage_classes"` } // NewFlavorDataSource is a helper function to simplify the provider implementation. func NewFlavorDataSource() datasource.DataSource { return &flavorDataSource{} } // flavorDataSource is the data source implementation. type flavorDataSource struct { client *sqlserverflexbetaPkg.APIClient providerData core.ProviderData } // Metadata returns the data source type name. func (r *flavorDataSource) Metadata(_ context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) { resp.TypeName = req.ProviderTypeName + "_sqlserverflexbeta_flavor" } // Configure adds the provider configured client to the data source. func (r *flavorDataSource) Configure(ctx context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) { var ok bool r.providerData, ok = conversion.ParseProviderData(ctx, req.ProviderData, &resp.Diagnostics) if !ok { return } apiClientConfigOptions := []config.ConfigurationOption{ config.WithCustomAuth(r.providerData.RoundTripper), utils.UserAgentConfigOption(r.providerData.Version), } if r.providerData.SQLServerFlexCustomEndpoint != "" { apiClientConfigOptions = append( apiClientConfigOptions, config.WithEndpoint(r.providerData.SQLServerFlexCustomEndpoint), ) } else { apiClientConfigOptions = append( apiClientConfigOptions, config.WithRegion(r.providerData.GetRegion()), ) } apiClient, err := sqlserverflexbetaPkg.NewAPIClient(apiClientConfigOptions...) if err != nil { resp.Diagnostics.AddError( "Error configuring API client", fmt.Sprintf( "Configuring client: %v. This is an error related to the provider configuration, not to the resource configuration", err, ), ) return } r.client = apiClient tflog.Info(ctx, "SQL Server Flex instance client configured") } func (r *flavorDataSource) Schema(ctx context.Context, _ datasource.SchemaRequest, resp *datasource.SchemaResponse) { resp.Schema = schema.Schema{ Attributes: map[string]schema.Attribute{ "project_id": schema.StringAttribute{ Required: true, Description: "The project ID of the flavor.", MarkdownDescription: "The project ID of the flavor.", }, "region": schema.StringAttribute{ Required: true, Description: "The region of the flavor.", MarkdownDescription: "The region of the flavor.", }, "cpu": schema.Int64Attribute{ Required: true, Description: "The cpu count of the instance.", MarkdownDescription: "The cpu count of the instance.", }, "ram": schema.Int64Attribute{ Required: true, Description: "The memory of the instance in Gibibyte.", MarkdownDescription: "The memory of the instance in Gibibyte.", }, "storage_class": schema.StringAttribute{ Required: true, Description: "The memory of the instance in Gibibyte.", MarkdownDescription: "The memory of the instance in Gibibyte.", }, "node_type": schema.StringAttribute{ Required: true, Description: "defines the nodeType it can be either single or HA", MarkdownDescription: "defines the nodeType it can be either single or HA", }, "flavor_id": schema.StringAttribute{ Computed: true, Description: "The id of the instance flavor.", MarkdownDescription: "The id of the instance flavor.", }, "description": schema.StringAttribute{ Computed: true, Description: "The flavor description.", MarkdownDescription: "The flavor description.", }, "id": schema.StringAttribute{ Computed: true, Description: "The id of the instance flavor.", MarkdownDescription: "The id of the instance flavor.", }, "max_gb": schema.Int64Attribute{ Computed: true, Description: "maximum storage which can be ordered for the flavor in Gigabyte.", MarkdownDescription: "maximum storage which can be ordered for the flavor in Gigabyte.", }, "min_gb": schema.Int64Attribute{ Computed: true, Description: "minimum storage which is required to order in Gigabyte.", MarkdownDescription: "minimum storage which is required to order in Gigabyte.", }, "storage_classes": schema.ListNestedAttribute{ NestedObject: schema.NestedAttributeObject{ Attributes: map[string]schema.Attribute{ "class": schema.StringAttribute{ Computed: true, }, "max_io_per_sec": schema.Int64Attribute{ Computed: true, }, "max_through_in_mb": schema.Int64Attribute{ Computed: true, }, }, CustomType: sqlserverflexbetaGen.StorageClassesType{ ObjectType: types.ObjectType{ AttrTypes: sqlserverflexbetaGen.StorageClassesValue{}.AttributeTypes(ctx), }, }, }, Computed: true, Description: "maximum storage which can be ordered for the flavor in Gigabyte.", MarkdownDescription: "maximum storage which can be ordered for the flavor in Gigabyte.", }, }, //Attributes: map[string]schema.Attribute{ // "project_id": schema.StringAttribute{ // Required: true, // Description: "The cpu count of the instance.", // MarkdownDescription: "The cpu count of the instance.", // }, // "region": schema.StringAttribute{ // Required: true, // Description: "The flavor description.", // MarkdownDescription: "The flavor description.", // }, // "cpu": schema.Int64Attribute{ // Required: true, // Description: "The cpu count of the instance.", // MarkdownDescription: "The cpu count of the instance.", // }, // "ram": schema.Int64Attribute{ // Required: true, // Description: "The memory of the instance in Gibibyte.", // MarkdownDescription: "The memory of the instance in Gibibyte.", // }, // "storage_class": schema.StringAttribute{ // Required: true, // Description: "The memory of the instance in Gibibyte.", // MarkdownDescription: "The memory of the instance in Gibibyte.", // }, // "description": schema.StringAttribute{ // Computed: true, // Description: "The flavor description.", // MarkdownDescription: "The flavor description.", // }, // "id": schema.StringAttribute{ // Computed: true, // Description: "The terraform id of the instance flavor.", // MarkdownDescription: "The terraform id of the instance flavor.", // }, // "flavor_id": schema.StringAttribute{ // Computed: true, // Description: "The flavor id of the instance flavor.", // MarkdownDescription: "The flavor id of the instance flavor.", // }, // "max_gb": schema.Int64Attribute{ // Computed: true, // Description: "maximum storage which can be ordered for the flavor in Gigabyte.", // MarkdownDescription: "maximum storage which can be ordered for the flavor in Gigabyte.", // }, // "min_gb": schema.Int64Attribute{ // Computed: true, // Description: "minimum storage which is required to order in Gigabyte.", // MarkdownDescription: "minimum storage which is required to order in Gigabyte.", // }, // "node_type": schema.StringAttribute{ // Required: true, // Description: "defines the nodeType it can be either single or replica", // MarkdownDescription: "defines the nodeType it can be either single or replica", // }, // "storage_classes": schema.ListNestedAttribute{ // Computed: true, // NestedObject: schema.NestedAttributeObject{ // Attributes: map[string]schema.Attribute{ // "class": schema.StringAttribute{ // Computed: true, // }, // "max_io_per_sec": schema.Int64Attribute{ // Computed: true, // }, // "max_through_in_mb": schema.Int64Attribute{ // Computed: true, // }, // }, // CustomType: sqlserverflexalphaGen.StorageClassesType{ // ObjectType: types.ObjectType{ // AttrTypes: sqlserverflexalphaGen.StorageClassesValue{}.AttributeTypes(ctx), // }, // }, // }, // }, // }, } } func (r *flavorDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { var model FlavorModel diags := req.Config.Get(ctx, &model) resp.Diagnostics.Append(diags...) if resp.Diagnostics.HasError() { return } ctx = core.InitProviderContext(ctx) projectId := model.ProjectId.ValueString() region := r.providerData.GetRegionWithOverride(model.Region) ctx = tflog.SetField(ctx, "project_id", projectId) ctx = tflog.SetField(ctx, "region", region) flavors, err := getAllFlavors(ctx, r.client, projectId, region) if err != nil { core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading flavors", fmt.Sprintf("getAllFlavors: %v", err)) return } var foundFlavors []sqlserverflexbetaPkg.ListFlavors for _, flavor := range flavors { if model.Cpu.ValueInt64() != *flavor.Cpu { continue } if model.Memory.ValueInt64() != *flavor.Memory { continue } if model.NodeType.ValueString() != *flavor.NodeType { continue } for _, sc := range *flavor.StorageClasses { if model.StorageClass.ValueString() != *sc.Class { continue } foundFlavors = append(foundFlavors, flavor) } } if len(foundFlavors) == 0 { resp.Diagnostics.AddError("get flavor", "could not find requested flavor") return } if len(foundFlavors) > 1 { resp.Diagnostics.AddError("get flavor", "found too many matching flavors") return } f := foundFlavors[0] model.Description = types.StringValue(*f.Description) model.Id = utils.BuildInternalTerraformId(model.ProjectId.ValueString(), region, *f.Id) model.FlavorId = types.StringValue(*f.Id) model.MaxGb = types.Int64Value(*f.MaxGB) model.MinGb = types.Int64Value(*f.MinGB) if f.StorageClasses == nil { model.StorageClasses = types.ListNull(sqlserverflexbetaGen.StorageClassesType{ ObjectType: basetypes.ObjectType{ AttrTypes: sqlserverflexbetaGen.StorageClassesValue{}.AttributeTypes(ctx), }, }) } else { var scList []attr.Value for _, sc := range *f.StorageClasses { scList = append( scList, sqlserverflexbetaGen.NewStorageClassesValueMust( sqlserverflexbetaGen.StorageClassesValue{}.AttributeTypes(ctx), map[string]attr.Value{ "class": types.StringValue(*sc.Class), "max_io_per_sec": types.Int64Value(*sc.MaxIoPerSec), "max_through_in_mb": types.Int64Value(*sc.MaxThroughInMb), }, ), ) } storageClassesList := types.ListValueMust( sqlserverflexbetaGen.StorageClassesType{ ObjectType: basetypes.ObjectType{ AttrTypes: sqlserverflexbetaGen.StorageClassesValue{}.AttributeTypes(ctx), }, }, scList, ) model.StorageClasses = storageClassesList } // Set refreshed state diags = resp.State.Set(ctx, model) resp.Diagnostics.Append(diags...) if resp.Diagnostics.HasError() { return } tflog.Info(ctx, "SQL Server Flex flavors read") }