feat: refactor data source models and update mapping functions for improved consistency

This commit is contained in:
Andre_Harms 2026-02-09 21:28:49 +01:00
parent f0e7c19cdf
commit 184e133a2a
34 changed files with 980 additions and 1017 deletions

View file

@ -19,12 +19,6 @@ import (
"tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/pkg_gen/postgresflexalpha" "tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/pkg_gen/postgresflexalpha"
) )
// DataSourceModel maps the data source schema data.
type DataSourceModel struct {
postgresflexalpha2.DatabaseModel
TerraformID types.String `tfsdk:"id"`
}
// Ensure the implementation satisfies the expected interfaces. // Ensure the implementation satisfies the expected interfaces.
var ( var (
_ datasource.DataSource = &databaseDataSource{} _ datasource.DataSource = &databaseDataSource{}
@ -35,6 +29,12 @@ func NewDatabaseDataSource() datasource.DataSource {
return &databaseDataSource{} return &databaseDataSource{}
} }
// dataSourceModel maps the data source schema data.
type dataSourceModel struct {
postgresflexalpha2.DatabaseModel
TerraformID types.String `tfsdk:"id"`
}
// databaseDataSource is the data source implementation. // databaseDataSource is the data source implementation.
type databaseDataSource struct { type databaseDataSource struct {
client *postgresflexalpha.APIClient client *postgresflexalpha.APIClient
@ -89,7 +89,7 @@ func (r *databaseDataSource) Read(
req datasource.ReadRequest, req datasource.ReadRequest,
resp *datasource.ReadResponse, resp *datasource.ReadResponse,
) { // nolint:gocritic // function signature required by Terraform ) { // nolint:gocritic // function signature required by Terraform
var model DataSourceModel var model dataSourceModel
diags := req.Config.Get(ctx, &model) diags := req.Config.Get(ctx, &model)
resp.Diagnostics.Append(diags...) resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() { if resp.Diagnostics.HasError() {
@ -141,7 +141,7 @@ func (r *databaseDataSource) Read(
// getDatabaseByNameOrID retrieves a single database by ensuring either a unique ID or name is provided. // getDatabaseByNameOrID retrieves a single database by ensuring either a unique ID or name is provided.
func (r *databaseDataSource) getDatabaseByNameOrID( func (r *databaseDataSource) getDatabaseByNameOrID(
ctx context.Context, ctx context.Context,
model *DataSourceModel, model *dataSourceModel,
projectId, region, instanceId string, projectId, region, instanceId string,
diags *diag.Diagnostics, diags *diag.Diagnostics,
) (*postgresflexalpha.ListDatabase, error) { ) (*postgresflexalpha.ListDatabase, error) {

View file

@ -9,10 +9,10 @@ import (
"tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit/internal/utils" "tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit/internal/utils"
) )
// mapFields maps fields from a ListDatabase API response to a ResourceModel for the data source. // mapFields maps fields from a ListDatabase API response to a resourceModel for the data source.
func mapFields( func mapFields(
source *postgresflexalpha.ListDatabase, source *postgresflexalpha.ListDatabase,
model *DataSourceModel, model *dataSourceModel,
region string, region string,
) error { ) error {
if source == nil { if source == nil {
@ -51,8 +51,8 @@ func mapFields(
return nil return nil
} }
// mapResourceFields maps fields from a ListDatabase API response to a ResourceModel for the resource. // mapResourceFields maps fields from a ListDatabase API response to a resourceModel for the resource.
func mapResourceFields(source *postgresflexalpha.ListDatabase, model *ResourceModel) error { func mapResourceFields(source *postgresflexalpha.ListDatabase, model *resourceModel) error {
if source == nil { if source == nil {
return fmt.Errorf("response is nil") return fmt.Errorf("response is nil")
} }
@ -80,7 +80,7 @@ func mapResourceFields(source *postgresflexalpha.ListDatabase, model *ResourceMo
} }
// toCreatePayload converts the resource model to an API create payload. // toCreatePayload converts the resource model to an API create payload.
func toCreatePayload(model *ResourceModel) (*postgresflexalpha.CreateDatabaseRequestPayload, error) { func toCreatePayload(model *resourceModel) (*postgresflexalpha.CreateDatabaseRequestPayload, error) {
if model == nil { if model == nil {
return nil, fmt.Errorf("nil model") return nil, fmt.Errorf("nil model")
} }

View file

@ -13,11 +13,11 @@ import (
func TestMapFields(t *testing.T) { func TestMapFields(t *testing.T) {
type given struct { type given struct {
source *postgresflexalpha.ListDatabase source *postgresflexalpha.ListDatabase
model *DataSourceModel model *dataSourceModel
region string region string
} }
type expected struct { type expected struct {
model *DataSourceModel model *dataSourceModel
err bool err bool
} }
@ -34,11 +34,11 @@ func TestMapFields(t *testing.T) {
Name: utils.Ptr("my-db"), Name: utils.Ptr("my-db"),
Owner: utils.Ptr("\"my-owner\""), Owner: utils.Ptr("\"my-owner\""),
}, },
model: &DataSourceModel{}, model: &dataSourceModel{},
region: "eu01", region: "eu01",
}, },
expected: expected{ expected: expected{
model: &DataSourceModel{ model: &dataSourceModel{
DatabaseModel: datasource.DatabaseModel{ DatabaseModel: datasource.DatabaseModel{
Id: types.Int64Value(1), Id: types.Int64Value(1),
Name: types.StringValue("my-db"), Name: types.StringValue("my-db"),
@ -59,7 +59,7 @@ func TestMapFields(t *testing.T) {
Id: utils.Ptr(int64(1)), Id: utils.Ptr(int64(1)),
Name: utils.Ptr("my-db"), Name: utils.Ptr("my-db"),
}, },
model: &DataSourceModel{ model: &dataSourceModel{
DatabaseModel: datasource.DatabaseModel{ DatabaseModel: datasource.DatabaseModel{
Id: types.Int64Value(1), Id: types.Int64Value(1),
ProjectId: types.StringValue("my-project"), ProjectId: types.StringValue("my-project"),
@ -69,7 +69,7 @@ func TestMapFields(t *testing.T) {
region: "eu01", region: "eu01",
}, },
expected: expected{ expected: expected{
model: &DataSourceModel{ model: &dataSourceModel{
DatabaseModel: datasource.DatabaseModel{ DatabaseModel: datasource.DatabaseModel{
Id: types.Int64Value(1), Id: types.Int64Value(1),
Name: types.StringValue("my-db"), Name: types.StringValue("my-db"),
@ -86,7 +86,7 @@ func TestMapFields(t *testing.T) {
name: "should fail on nil source", name: "should fail on nil source",
given: given{ given: given{
source: nil, source: nil,
model: &DataSourceModel{}, model: &dataSourceModel{},
}, },
expected: expected{err: true}, expected: expected{err: true},
}, },
@ -94,7 +94,7 @@ func TestMapFields(t *testing.T) {
name: "should fail on nil source ID", name: "should fail on nil source ID",
given: given{ given: given{
source: &postgresflexalpha.ListDatabase{Id: nil}, source: &postgresflexalpha.ListDatabase{Id: nil},
model: &DataSourceModel{}, model: &dataSourceModel{},
}, },
expected: expected{err: true}, expected: expected{err: true},
}, },
@ -128,10 +128,10 @@ func TestMapFields(t *testing.T) {
func TestMapResourceFields(t *testing.T) { func TestMapResourceFields(t *testing.T) {
type given struct { type given struct {
source *postgresflexalpha.ListDatabase source *postgresflexalpha.ListDatabase
model *ResourceModel model *resourceModel
} }
type expected struct { type expected struct {
model *ResourceModel model *resourceModel
err bool err bool
} }
@ -148,10 +148,10 @@ func TestMapResourceFields(t *testing.T) {
Name: utils.Ptr("my-db"), Name: utils.Ptr("my-db"),
Owner: utils.Ptr("\"my-owner\""), Owner: utils.Ptr("\"my-owner\""),
}, },
model: &ResourceModel{}, model: &resourceModel{},
}, },
expected: expected{ expected: expected{
model: &ResourceModel{ model: &resourceModel{
Id: types.Int64Value(1), Id: types.Int64Value(1),
Name: types.StringValue("my-db"), Name: types.StringValue("my-db"),
Owner: types.StringValue("my-owner"), Owner: types.StringValue("my-owner"),
@ -163,7 +163,7 @@ func TestMapResourceFields(t *testing.T) {
name: "should fail on nil source", name: "should fail on nil source",
given: given{ given: given{
source: nil, source: nil,
model: &ResourceModel{}, model: &resourceModel{},
}, },
expected: expected{err: true}, expected: expected{err: true},
}, },
@ -188,7 +188,7 @@ func TestMapResourceFields(t *testing.T) {
func TestToCreatePayload(t *testing.T) { func TestToCreatePayload(t *testing.T) {
type given struct { type given struct {
model *ResourceModel model *resourceModel
} }
type expected struct { type expected struct {
payload *postgresflexalpha.CreateDatabaseRequestPayload payload *postgresflexalpha.CreateDatabaseRequestPayload
@ -203,7 +203,7 @@ func TestToCreatePayload(t *testing.T) {
{ {
name: "should convert model to payload", name: "should convert model to payload",
given: given{ given: given{
model: &ResourceModel{ model: &resourceModel{
Name: types.StringValue("my-db"), Name: types.StringValue("my-db"),
Owner: types.StringValue("my-owner"), Owner: types.StringValue("my-owner"),
}, },

View file

@ -41,8 +41,13 @@ var (
extractErrorMessage = "Extracting identity data: %v" extractErrorMessage = "Extracting identity data: %v"
) )
// ResourceModel describes the resource data model. // NewDatabaseResource is a helper function to simplify the provider implementation.
type ResourceModel = postgresflexalpha2.DatabaseModel func NewDatabaseResource() resource.Resource {
return &databaseResource{}
}
// resourceModel describes the resource data model.
type resourceModel = postgresflexalpha2.DatabaseModel
// DatabaseResourceIdentityModel describes the resource's identity attributes. // DatabaseResourceIdentityModel describes the resource's identity attributes.
type DatabaseResourceIdentityModel struct { type DatabaseResourceIdentityModel struct {
@ -52,11 +57,6 @@ type DatabaseResourceIdentityModel struct {
DatabaseID types.Int64 `tfsdk:"database_id"` DatabaseID types.Int64 `tfsdk:"database_id"`
} }
// NewDatabaseResource is a helper function to simplify the provider implementation.
func NewDatabaseResource() resource.Resource {
return &databaseResource{}
}
// databaseResource is the resource implementation. // databaseResource is the resource implementation.
type databaseResource struct { type databaseResource struct {
client *postgresflexalpha.APIClient client *postgresflexalpha.APIClient
@ -69,7 +69,7 @@ func (r *databaseResource) ModifyPlan(
req resource.ModifyPlanRequest, req resource.ModifyPlanRequest,
resp *resource.ModifyPlanResponse, resp *resource.ModifyPlanResponse,
) { // nolint:gocritic // function signature required by Terraform ) { // nolint:gocritic // function signature required by Terraform
var configModel ResourceModel var configModel resourceModel
// skip initial empty configuration to avoid follow-up errors // skip initial empty configuration to avoid follow-up errors
if req.Config.Raw.IsNull() { if req.Config.Raw.IsNull() {
return return
@ -79,7 +79,7 @@ func (r *databaseResource) ModifyPlan(
return return
} }
var planModel ResourceModel var planModel resourceModel
resp.Diagnostics.Append(req.Plan.Get(ctx, &planModel)...) resp.Diagnostics.Append(req.Plan.Get(ctx, &planModel)...)
if resp.Diagnostics.HasError() { if resp.Diagnostics.HasError() {
return return
@ -199,7 +199,7 @@ func (r *databaseResource) Create(
req resource.CreateRequest, req resource.CreateRequest,
resp *resource.CreateResponse, resp *resource.CreateResponse,
) { // nolint:gocritic // function signature required by Terraform ) { // nolint:gocritic // function signature required by Terraform
var model ResourceModel var model resourceModel
diags := req.Plan.Get(ctx, &model) diags := req.Plan.Get(ctx, &model)
resp.Diagnostics.Append(diags...) resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() { if resp.Diagnostics.HasError() {
@ -309,7 +309,7 @@ func (r *databaseResource) Read(
req resource.ReadRequest, req resource.ReadRequest,
resp *resource.ReadResponse, resp *resource.ReadResponse,
) { // nolint:gocritic // function signature required by Terraform ) { // nolint:gocritic // function signature required by Terraform
var model ResourceModel var model resourceModel
diags := req.State.Get(ctx, &model) diags := req.State.Get(ctx, &model)
resp.Diagnostics.Append(diags...) resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() { if resp.Diagnostics.HasError() {
@ -380,7 +380,7 @@ func (r *databaseResource) Update(
req resource.UpdateRequest, req resource.UpdateRequest,
resp *resource.UpdateResponse, resp *resource.UpdateResponse,
) { ) {
var model ResourceModel var model resourceModel
diags := req.Plan.Get(ctx, &model) diags := req.Plan.Get(ctx, &model)
resp.Diagnostics.Append(diags...) resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() { if resp.Diagnostics.HasError() {
@ -418,7 +418,7 @@ func (r *databaseResource) Update(
ctx = tflog.SetField(ctx, "database_id", databaseId) ctx = tflog.SetField(ctx, "database_id", databaseId)
// Retrieve values from state // Retrieve values from state
var stateModel ResourceModel var stateModel resourceModel
diags = req.State.Get(ctx, &stateModel) diags = req.State.Get(ctx, &stateModel)
resp.Diagnostics.Append(diags...) resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() { if resp.Diagnostics.HasError() {
@ -483,7 +483,7 @@ func (r *databaseResource) Delete(
req resource.DeleteRequest, req resource.DeleteRequest,
resp *resource.DeleteResponse, resp *resource.DeleteResponse,
) { // nolint:gocritic // function signature required by Terraform ) { // nolint:gocritic // function signature required by Terraform
var model ResourceModel var model resourceModel
diags := req.State.Get(ctx, &model) diags := req.State.Get(ctx, &model)
resp.Diagnostics.Append(diags...) resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() { if resp.Diagnostics.HasError() {
@ -591,7 +591,7 @@ func (r *databaseResource) ImportState(
// extractIdentityData extracts essential identifiers from the resource model, falling back to the identity model. // extractIdentityData extracts essential identifiers from the resource model, falling back to the identity model.
func (r *databaseResource) extractIdentityData( func (r *databaseResource) extractIdentityData(
model ResourceModel, model resourceModel,
identity DatabaseResourceIdentityModel, identity DatabaseResourceIdentityModel,
) (projectId, region, instanceId string, databaseId int64, err error) { ) (projectId, region, instanceId string, databaseId int64, err error) {
if !model.DatabaseId.IsNull() && !model.DatabaseId.IsUnknown() { if !model.DatabaseId.IsNull() && !model.DatabaseId.IsUnknown() {

View file

@ -12,8 +12,8 @@ type mockRequest struct {
executeFunc func() (*postgresflex.GetFlavorsResponse, error) executeFunc func() (*postgresflex.GetFlavorsResponse, error)
} }
func (m *mockRequest) Page(_ int64) postgresflex.ApiGetFlavorsRequestRequest { return m } func (m *mockRequest) Page(_ int32) postgresflex.ApiGetFlavorsRequestRequest { return m }
func (m *mockRequest) Size(_ int64) postgresflex.ApiGetFlavorsRequestRequest { return m } func (m *mockRequest) Size(_ int32) postgresflex.ApiGetFlavorsRequestRequest { return m }
func (m *mockRequest) Sort(_ postgresflex.FlavorSort) postgresflex.ApiGetFlavorsRequestRequest { func (m *mockRequest) Sort(_ postgresflex.FlavorSort) postgresflex.ApiGetFlavorsRequestRequest {
return m return m
} }

View file

@ -21,12 +21,19 @@ func NewFlavorsDataSource() datasource.DataSource {
return &flavorsDataSource{} return &flavorsDataSource{}
} }
// dataSourceModel maps the data source schema data.
type dataSourceModel = postgresflexalphaGen.FlavorsModel
type flavorsDataSource struct { type flavorsDataSource struct {
client *postgresflexalpha.APIClient client *postgresflexalpha.APIClient
providerData core.ProviderData providerData core.ProviderData
} }
func (d *flavorsDataSource) Metadata(_ context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) { func (d *flavorsDataSource) Metadata(
_ context.Context,
req datasource.MetadataRequest,
resp *datasource.MetadataResponse,
) {
resp.TypeName = req.ProviderTypeName + "_postgresflexalpha_flavors" resp.TypeName = req.ProviderTypeName + "_postgresflexalpha_flavors"
} }
@ -35,7 +42,11 @@ func (d *flavorsDataSource) Schema(ctx context.Context, _ datasource.SchemaReque
} }
// Configure adds the provider configured client to the data source. // Configure adds the provider configured client to the data source.
func (d *flavorsDataSource) Configure(ctx context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) { func (d *flavorsDataSource) Configure(
ctx context.Context,
req datasource.ConfigureRequest,
resp *datasource.ConfigureResponse,
) {
var ok bool var ok bool
d.providerData, ok = conversion.ParseProviderData(ctx, req.ProviderData, &resp.Diagnostics) d.providerData, ok = conversion.ParseProviderData(ctx, req.ProviderData, &resp.Diagnostics)
if !ok { if !ok {
@ -51,7 +62,7 @@ func (d *flavorsDataSource) Configure(ctx context.Context, req datasource.Config
} }
func (d *flavorsDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { func (d *flavorsDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) {
var data postgresflexalphaGen.FlavorsModel var data dataSourceModel
// Read Terraform configuration data into the model // Read Terraform configuration data into the model
resp.Diagnostics.Append(req.Config.Get(ctx, &data)...) resp.Diagnostics.Append(req.Config.Get(ctx, &data)...)

View file

@ -5,6 +5,7 @@ import (
"fmt" "fmt"
"net/http" "net/http"
"github.com/hashicorp/terraform-plugin-framework/types"
"tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/pkg_gen/postgresflexalpha" "tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/pkg_gen/postgresflexalpha"
"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/conversion"
postgresflexalpha2 "tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit/internal/services/postgresflexalpha/instance/datasources_gen" postgresflexalpha2 "tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit/internal/services/postgresflexalpha/instance/datasources_gen"
@ -26,6 +27,12 @@ func NewInstanceDataSource() datasource.DataSource {
return &instanceDataSource{} return &instanceDataSource{}
} }
// dataSourceModel maps the data source schema data.
type dataSourceModel struct {
postgresflexalpha2.InstanceModel
TerraformID types.String `tfsdk:"id"`
}
// instanceDataSource is the data source implementation. // instanceDataSource is the data source implementation.
type instanceDataSource struct { type instanceDataSource struct {
client *postgresflexalpha.APIClient client *postgresflexalpha.APIClient
@ -33,12 +40,20 @@ type instanceDataSource struct {
} }
// Metadata returns the data source type name. // Metadata returns the data source type name.
func (r *instanceDataSource) Metadata(_ context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) { func (r *instanceDataSource) Metadata(
_ context.Context,
req datasource.MetadataRequest,
resp *datasource.MetadataResponse,
) {
resp.TypeName = req.ProviderTypeName + "_postgresflexalpha_instance" resp.TypeName = req.ProviderTypeName + "_postgresflexalpha_instance"
} }
// Configure adds the provider configured client to the data source. // Configure adds the provider configured client to the data source.
func (r *instanceDataSource) Configure(ctx context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) { func (r *instanceDataSource) Configure(
ctx context.Context,
req datasource.ConfigureRequest,
resp *datasource.ConfigureResponse,
) {
var ok bool var ok bool
r.providerData, ok = conversion.ParseProviderData(ctx, req.ProviderData, &resp.Diagnostics) r.providerData, ok = conversion.ParseProviderData(ctx, req.ProviderData, &resp.Diagnostics)
if !ok { if !ok {
@ -59,8 +74,12 @@ func (r *instanceDataSource) Schema(ctx context.Context, _ datasource.SchemaRequ
} }
// Read refreshes the Terraform state with the latest data. // Read refreshes the Terraform state with the latest data.
func (r *instanceDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { // nolint:gocritic // function signature required by Terraform func (r *instanceDataSource) Read(
var model postgresflexalpha2.InstanceModel ctx context.Context,
req datasource.ReadRequest,
resp *datasource.ReadResponse,
) { // nolint:gocritic // function signature required by Terraform
var model dataSourceModel
diags := req.Config.Get(ctx, &model) diags := req.Config.Get(ctx, &model)
resp.Diagnostics.Append(diags...) resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() { if resp.Diagnostics.HasError() {

View file

@ -14,26 +14,32 @@ import (
"tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit/internal/utils" "tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit/internal/utils"
) )
func mapGetInstanceResponseToModel(ctx context.Context, m *postgresflexalpharesource.InstanceModel, resp *postgresflex.GetInstanceResponse) error { func mapGetInstanceResponseToModel(
tflog.Debug(ctx, ">>>> MSH DEBUG <<<<", map[string]interface{}{ ctx context.Context,
"id": m.Id.ValueString(), m *postgresflexalpharesource.InstanceModel,
"instance_id": m.InstanceId.ValueString(), resp *postgresflex.GetInstanceResponse,
"backup_schedule": m.BackupSchedule.ValueString(), ) error {
"flavor_id": m.FlavorId.ValueString(), tflog.Debug(
"encryption.kek_key_id": m.Encryption.KekKeyId.ValueString(), ctx, ">>>> MSH DEBUG <<<<", map[string]interface{}{
"encryption.kek_key_ring_id": m.Encryption.KekKeyRingId.ValueString(), "id": m.Id.ValueString(),
"encryption.kek_key_version": m.Encryption.KekKeyVersion.ValueString(), "instance_id": m.InstanceId.ValueString(),
"encryption.service_account": m.Encryption.ServiceAccount.ValueString(), "backup_schedule": m.BackupSchedule.ValueString(),
"is_deletable": m.IsDeletable.ValueBool(), "flavor_id": m.FlavorId.ValueString(),
"name": m.Name.ValueString(), "encryption.kek_key_id": m.Encryption.KekKeyId.ValueString(),
"status": m.Status.ValueString(), "encryption.kek_key_ring_id": m.Encryption.KekKeyRingId.ValueString(),
"retention_days": m.RetentionDays.ValueInt64(), "encryption.kek_key_version": m.Encryption.KekKeyVersion.ValueString(),
"replicas": m.Replicas.ValueInt64(), "encryption.service_account": m.Encryption.ServiceAccount.ValueString(),
"network.instance_address": m.Network.InstanceAddress.ValueString(), "is_deletable": m.IsDeletable.ValueBool(),
"network.router_address": m.Network.RouterAddress.ValueString(), "name": m.Name.ValueString(),
"version": m.Version.ValueString(), "status": m.Status.ValueString(),
"network.acl": m.Network.Acl.String(), "retention_days": m.RetentionDays.ValueInt64(),
}) "replicas": m.Replicas.ValueInt64(),
"network.instance_address": m.Network.InstanceAddress.ValueString(),
"network.router_address": m.Network.RouterAddress.ValueString(),
"version": m.Version.ValueString(),
"network.acl": m.Network.Acl.String(),
},
)
m.BackupSchedule = types.StringValue(resp.GetBackupSchedule()) m.BackupSchedule = types.StringValue(resp.GetBackupSchedule())
m.Encryption = postgresflexalpharesource.NewEncryptionValueNull() m.Encryption = postgresflexalpharesource.NewEncryptionValueNull()
@ -61,7 +67,11 @@ func mapGetInstanceResponseToModel(ctx context.Context, m *postgresflexalphareso
m.FlavorId = types.StringValue(resp.GetFlavorId()) m.FlavorId = types.StringValue(resp.GetFlavorId())
if m.Id.IsNull() || m.Id.IsUnknown() { if m.Id.IsNull() || m.Id.IsUnknown() {
m.Id = utils.BuildInternalTerraformId(m.ProjectId.ValueString(), m.Region.ValueString(), m.InstanceId.ValueString()) m.Id = utils.BuildInternalTerraformId(
m.ProjectId.ValueString(),
m.Region.ValueString(),
m.InstanceId.ValueString(),
)
} }
m.InstanceId = types.StringPointerValue(resp.Id) m.InstanceId = types.StringPointerValue(resp.Id)
@ -121,7 +131,11 @@ func mapGetInstanceResponseToModel(ctx context.Context, m *postgresflexalphareso
return nil return nil
} }
func mapGetDataInstanceResponseToModel(ctx context.Context, m *postgresflexalphadatasource.InstanceModel, resp *postgresflex.GetInstanceResponse) error { func mapGetDataInstanceResponseToModel(
ctx context.Context,
m *dataSourceModel,
resp *postgresflex.GetInstanceResponse,
) error {
m.BackupSchedule = types.StringValue(resp.GetBackupSchedule()) m.BackupSchedule = types.StringValue(resp.GetBackupSchedule())
handleEncryption(m, resp) handleEncryption(m, resp)
m.ConnectionInfo.Host = types.StringValue(resp.ConnectionInfo.GetHost()) m.ConnectionInfo.Host = types.StringValue(resp.ConnectionInfo.GetHost())
@ -155,7 +169,7 @@ func mapGetDataInstanceResponseToModel(ctx context.Context, m *postgresflexalpha
return nil return nil
} }
func handleNetwork(ctx context.Context, m *postgresflexalphadatasource.InstanceModel, resp *postgresflex.GetInstanceResponse) error { func handleNetwork(ctx context.Context, m *dataSourceModel, resp *postgresflex.GetInstanceResponse) error {
netAcl, diags := types.ListValueFrom(ctx, types.StringType, resp.Network.GetAcl()) netAcl, diags := types.ListValueFrom(ctx, types.StringType, resp.Network.GetAcl())
if diags.HasError() { if diags.HasError() {
return fmt.Errorf("failed converting network acl from response") return fmt.Errorf("failed converting network acl from response")
@ -187,7 +201,7 @@ func handleNetwork(ctx context.Context, m *postgresflexalphadatasource.InstanceM
return nil return nil
} }
func handleEncryption(m *postgresflexalphadatasource.InstanceModel, resp *postgresflex.GetInstanceResponse) { func handleEncryption(m *dataSourceModel, resp *postgresflex.GetInstanceResponse) {
keyId := "" keyId := ""
if keyIdVal, ok := resp.Encryption.GetKekKeyIdOk(); ok { if keyIdVal, ok := resp.Encryption.GetKekKeyIdOk(); ok {
keyId = keyIdVal keyId = keyIdVal

View file

@ -23,8 +23,6 @@ import (
wait "tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit/internal/wait/postgresflexalpha" wait "tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit/internal/wait/postgresflexalpha"
) )
const packageName = "postgresflexalpha"
// Ensure the implementation satisfies the expected interfaces. // Ensure the implementation satisfies the expected interfaces.
var ( var (
_ resource.Resource = &instanceResource{} _ resource.Resource = &instanceResource{}
@ -40,11 +38,8 @@ func NewInstanceResource() resource.Resource {
return &instanceResource{} return &instanceResource{}
} }
// instanceResource is the resource implementation. // resourceModel describes the resource data model.
type instanceResource struct { type resourceModel = postgresflexalpha.InstanceModel
client *postgresflex.APIClient
providerData core.ProviderData
}
type InstanceResourceIdentityModel struct { type InstanceResourceIdentityModel struct {
ProjectID types.String `tfsdk:"project_id"` ProjectID types.String `tfsdk:"project_id"`
@ -52,8 +47,18 @@ type InstanceResourceIdentityModel struct {
InstanceID types.String `tfsdk:"instance_id"` InstanceID types.String `tfsdk:"instance_id"`
} }
func (r *instanceResource) ValidateConfig(ctx context.Context, req resource.ValidateConfigRequest, resp *resource.ValidateConfigResponse) { // instanceResource is the resource implementation.
var data postgresflexalpha.InstanceModel type instanceResource struct {
client *postgresflex.APIClient
providerData core.ProviderData
}
func (r *instanceResource) ValidateConfig(
ctx context.Context,
req resource.ValidateConfigRequest,
resp *resource.ValidateConfigResponse,
) {
var data resourceModel
resp.Diagnostics.Append(req.Config.Get(ctx, &data)...) resp.Diagnostics.Append(req.Config.Get(ctx, &data)...)
if resp.Diagnostics.HasError() { if resp.Diagnostics.HasError() {
@ -72,7 +77,11 @@ func (r *instanceResource) ValidateConfig(ctx context.Context, req resource.Vali
// ModifyPlan implements resource.ResourceWithModifyPlan. // ModifyPlan implements resource.ResourceWithModifyPlan.
// Use the modifier to set the effective region in the current plan. // Use the modifier to set the effective region in the current plan.
func (r *instanceResource) ModifyPlan(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) { // nolint:gocritic // function signature required by Terraform func (r *instanceResource) ModifyPlan(
ctx context.Context,
req resource.ModifyPlanRequest,
resp *resource.ModifyPlanResponse,
) { // nolint:gocritic // function signature required by Terraform
var configModel postgresflexalpha.InstanceModel var configModel postgresflexalpha.InstanceModel
// skip initial empty configuration to avoid follow-up errors // skip initial empty configuration to avoid follow-up errors
if req.Config.Raw.IsNull() { if req.Config.Raw.IsNull() {
@ -149,7 +158,11 @@ func (r *instanceResource) Schema(ctx context.Context, _ resource.SchemaRequest,
resp.Schema = schema resp.Schema = schema
} }
func (r *instanceResource) IdentitySchema(_ context.Context, _ resource.IdentitySchemaRequest, resp *resource.IdentitySchemaResponse) { func (r *instanceResource) IdentitySchema(
_ context.Context,
_ resource.IdentitySchemaRequest,
resp *resource.IdentitySchemaResponse,
) {
resp.IdentitySchema = identityschema.Schema{ resp.IdentitySchema = identityschema.Schema{
Attributes: map[string]identityschema.Attribute{ Attributes: map[string]identityschema.Attribute{
"project_id": identityschema.StringAttribute{ "project_id": identityschema.StringAttribute{
@ -171,7 +184,7 @@ func (r *instanceResource) Create(
req resource.CreateRequest, req resource.CreateRequest,
resp *resource.CreateResponse, resp *resource.CreateResponse,
) { // nolint:gocritic // function signature required by Terraform ) { // nolint:gocritic // function signature required by Terraform
var model postgresflexalpha.InstanceModel var model resourceModel
diags := req.Plan.Get(ctx, &model) diags := req.Plan.Get(ctx, &model)
resp.Diagnostics.Append(diags...) resp.Diagnostics.Append(diags...)
@ -201,7 +214,11 @@ func (r *instanceResource) Create(
payload := modelToCreateInstancePayload(netAcl, model, replVal) payload := modelToCreateInstancePayload(netAcl, model, replVal)
// Create new instance // Create new instance
createResp, err := r.client.CreateInstanceRequest(ctx, projectId, region).CreateInstanceRequestPayload(payload).Execute() createResp, err := r.client.CreateInstanceRequest(
ctx,
projectId,
region,
).CreateInstanceRequestPayload(payload).Execute()
if err != nil { if err != nil {
core.LogAndAddError(ctx, &resp.Diagnostics, "error creating instance", fmt.Sprintf("Calling API: %v", err)) core.LogAndAddError(ctx, &resp.Diagnostics, "error creating instance", fmt.Sprintf("Calling API: %v", err))
return return
@ -227,13 +244,23 @@ func (r *instanceResource) Create(
waitResp, err := wait.CreateInstanceWaitHandler(ctx, r.client, projectId, region, instanceId).WaitWithContext(ctx) waitResp, err := wait.CreateInstanceWaitHandler(ctx, r.client, projectId, region, instanceId).WaitWithContext(ctx)
if err != nil { if err != nil {
core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating instance", fmt.Sprintf("Wait handler error: %v", err)) core.LogAndAddError(
ctx,
&resp.Diagnostics,
"Error creating instance",
fmt.Sprintf("Wait handler error: %v", err),
)
return return
} }
err = mapGetInstanceResponseToModel(ctx, &model, waitResp) err = mapGetInstanceResponseToModel(ctx, &model, waitResp)
if err != nil { if err != nil {
core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating instance", fmt.Sprintf("Error creating model: %v", err)) core.LogAndAddError(
ctx,
&resp.Diagnostics,
"Error creating instance",
fmt.Sprintf("Error creating model: %v", err),
)
return return
} }
@ -246,7 +273,11 @@ func (r *instanceResource) Create(
tflog.Info(ctx, "Postgres Flex instance created") tflog.Info(ctx, "Postgres Flex instance created")
} }
func modelToCreateInstancePayload(netAcl []string, model postgresflexalpha.InstanceModel, replVal int32) postgresflex.CreateInstanceRequestPayload { func modelToCreateInstancePayload(
netAcl []string,
model postgresflexalpha.InstanceModel,
replVal int32,
) postgresflex.CreateInstanceRequestPayload {
var enc *postgresflex.InstanceEncryption var enc *postgresflex.InstanceEncryption
if !model.Encryption.IsNull() && !model.Encryption.IsUnknown() { if !model.Encryption.IsNull() && !model.Encryption.IsUnknown() {
enc = &postgresflex.InstanceEncryption{ enc = &postgresflex.InstanceEncryption{
@ -279,10 +310,14 @@ func modelToCreateInstancePayload(netAcl []string, model postgresflexalpha.Insta
} }
// Read refreshes the Terraform state with the latest data. // Read refreshes the Terraform state with the latest data.
func (r *instanceResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { // nolint:gocritic // function signature required by Terraform func (r *instanceResource) Read(
ctx context.Context,
req resource.ReadRequest,
resp *resource.ReadResponse,
) { // nolint:gocritic // function signature required by Terraform
functionErrorSummary := "read instance failed" functionErrorSummary := "read instance failed"
var model postgresflexalpha.InstanceModel var model resourceModel
diags := req.State.Get(ctx, &model) diags := req.State.Get(ctx, &model)
resp.Diagnostics.Append(diags...) resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() { if resp.Diagnostics.HasError() {
@ -371,7 +406,12 @@ func (r *instanceResource) Read(ctx context.Context, req resource.ReadRequest, r
err = mapGetInstanceResponseToModel(ctx, &model, instanceResp) err = mapGetInstanceResponseToModel(ctx, &model, instanceResp)
if err != nil { if err != nil {
core.LogAndAddError(ctx, &resp.Diagnostics, functionErrorSummary, fmt.Sprintf("Processing API payload: %v", err)) core.LogAndAddError(
ctx,
&resp.Diagnostics,
functionErrorSummary,
fmt.Sprintf("Processing API payload: %v", err),
)
return return
} }
@ -396,8 +436,12 @@ func (r *instanceResource) Read(ctx context.Context, req resource.ReadRequest, r
} }
// Update updates the resource and sets the updated Terraform state on success. // Update updates the resource and sets the updated Terraform state on success.
func (r *instanceResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { // nolint:gocritic // function signature required by Terraform func (r *instanceResource) Update(
var model postgresflexalpha.InstanceModel ctx context.Context,
req resource.UpdateRequest,
resp *resource.UpdateResponse,
) { // nolint:gocritic // function signature required by Terraform
var model resourceModel
diags := req.Plan.Get(ctx, &model) diags := req.Plan.Get(ctx, &model)
resp.Diagnostics.Append(diags...) resp.Diagnostics.Append(diags...)
@ -475,15 +519,31 @@ func (r *instanceResource) Update(ctx context.Context, req resource.UpdateReques
ctx = core.LogResponse(ctx) ctx = core.LogResponse(ctx)
waitResp, err := wait.PartialUpdateInstanceWaitHandler(ctx, r.client, projectId, region, instanceId).WaitWithContext(ctx) waitResp, err := wait.PartialUpdateInstanceWaitHandler(
ctx,
r.client,
projectId,
region,
instanceId,
).WaitWithContext(ctx)
if err != nil { if err != nil {
core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating instance", fmt.Sprintf("Instance update waiting: %v", err)) core.LogAndAddError(
ctx,
&resp.Diagnostics,
"Error updating instance",
fmt.Sprintf("Instance update waiting: %v", err),
)
return return
} }
err = mapGetInstanceResponseToModel(ctx, &model, waitResp) err = mapGetInstanceResponseToModel(ctx, &model, waitResp)
if err != nil { if err != nil {
core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating instance", fmt.Sprintf("Processing API payload: %v", err)) core.LogAndAddError(
ctx,
&resp.Diagnostics,
"Error updating instance",
fmt.Sprintf("Processing API payload: %v", err),
)
return return
} }
@ -496,8 +556,12 @@ func (r *instanceResource) Update(ctx context.Context, req resource.UpdateReques
} }
// Delete deletes the resource and removes the Terraform state on success. // Delete deletes the resource and removes the Terraform state on success.
func (r *instanceResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { // nolint:gocritic // function signature required by Terraform func (r *instanceResource) Delete(
var model postgresflexalpha.InstanceModel ctx context.Context,
req resource.DeleteRequest,
resp *resource.DeleteResponse,
) { // nolint:gocritic // function signature required by Terraform
var model resourceModel
diags := req.State.Get(ctx, &model) diags := req.State.Get(ctx, &model)
resp.Diagnostics.Append(diags...) resp.Diagnostics.Append(diags...)
@ -538,16 +602,24 @@ func (r *instanceResource) Delete(ctx context.Context, req resource.DeleteReques
// ImportState imports a resource into the Terraform state on success. // ImportState imports a resource into the Terraform state on success.
// The expected format of the resource import identifier is: project_id,region,instance_id // The expected format of the resource import identifier is: project_id,region,instance_id
func (r *instanceResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { func (r *instanceResource) ImportState(
ctx context.Context,
req resource.ImportStateRequest,
resp *resource.ImportStateResponse,
) {
ctx = core.InitProviderContext(ctx) ctx = core.InitProviderContext(ctx)
if req.ID != "" { if req.ID != "" {
idParts := strings.Split(req.ID, core.Separator) idParts := strings.Split(req.ID, core.Separator)
if len(idParts) != 3 || idParts[0] == "" || idParts[1] == "" || idParts[2] == "" { if len(idParts) != 3 || idParts[0] == "" || idParts[1] == "" || idParts[2] == "" {
core.LogAndAddError(ctx, &resp.Diagnostics, core.LogAndAddError(
ctx, &resp.Diagnostics,
"Error importing instance", "Error importing instance",
fmt.Sprintf("Expected import identifier with format: [project_id],[region],[instance_id] Got: %q", req.ID), fmt.Sprintf(
"Expected import identifier with format: [project_id],[region],[instance_id] Got: %q",
req.ID,
),
) )
return return
} }
@ -573,10 +645,23 @@ func (r *instanceResource) ImportState(ctx context.Context, req resource.ImportS
identityData.Region.ValueString(), identityData.Region.ValueString(),
identityData.InstanceID.ValueString(), identityData.InstanceID.ValueString(),
), ),
)...) )...,
resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("project_id"), identityData.ProjectID.ValueString())...) )
resp.Diagnostics.Append(
resp.State.SetAttribute(
ctx,
path.Root("project_id"),
identityData.ProjectID.ValueString(),
)...,
)
resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("region"), identityData.Region.ValueString())...) resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("region"), identityData.Region.ValueString())...)
resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("instance_id"), identityData.InstanceID.ValueString())...) resp.Diagnostics.Append(
resp.State.SetAttribute(
ctx,
path.Root("instance_id"),
identityData.InstanceID.ValueString(),
)...,
)
tflog.Info(ctx, "Postgres Flex instance state imported") tflog.Info(ctx, "Postgres Flex instance state imported")
} }

View file

@ -25,17 +25,17 @@ var (
_ datasource.DataSource = &userDataSource{} _ datasource.DataSource = &userDataSource{}
) )
// DataSourceModel maps the data source schema data.
type DataSourceModel struct {
postgresflexalpha.UserModel
TerraformID types.String `tfsdk:"id"`
}
// NewUserDataSource is a helper function to simplify the provider implementation. // NewUserDataSource is a helper function to simplify the provider implementation.
func NewUserDataSource() datasource.DataSource { func NewUserDataSource() datasource.DataSource {
return &userDataSource{} return &userDataSource{}
} }
// dataSourceModel maps the data source schema data.
type dataSourceModel struct {
postgresflexalpha.UserModel
TerraformID types.String `tfsdk:"id"`
}
// userDataSource is the data source implementation. // userDataSource is the data source implementation.
type userDataSource struct { type userDataSource struct {
client *postgresflex.APIClient client *postgresflex.APIClient
@ -90,7 +90,7 @@ func (r *userDataSource) Read(
req datasource.ReadRequest, req datasource.ReadRequest,
resp *datasource.ReadResponse, resp *datasource.ReadResponse,
) { // nolint:gocritic // function signature required by Terraform ) { // nolint:gocritic // function signature required by Terraform
var model DataSourceModel var model dataSourceModel
diags := req.Config.Get(ctx, &model) diags := req.Config.Get(ctx, &model)
resp.Diagnostics.Append(diags...) resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() { if resp.Diagnostics.HasError() {

View file

@ -13,7 +13,7 @@ import (
) )
// mapDataSourceFields maps API response to data source model, preserving existing ID. // mapDataSourceFields maps API response to data source model, preserving existing ID.
func mapDataSourceFields(userResp *postgresflex.GetUserResponse, model *DataSourceModel, region string) error { func mapDataSourceFields(userResp *postgresflex.GetUserResponse, model *dataSourceModel, region string) error {
if userResp == nil { if userResp == nil {
return fmt.Errorf("response is nil") return fmt.Errorf("response is nil")
} }
@ -68,7 +68,7 @@ func toPayloadRoles(roles *[]string) *[]postgresflex.UserRole {
} }
// toUpdatePayload creates an API update payload from the resource model. // toUpdatePayload creates an API update payload from the resource model.
func toUpdatePayload(model *ResourceModel, roles *[]string) ( func toUpdatePayload(model *resourceModel, roles *[]string) (
*postgresflex.UpdateUserRequestPayload, *postgresflex.UpdateUserRequestPayload,
error, error,
) { ) {
@ -86,7 +86,7 @@ func toUpdatePayload(model *ResourceModel, roles *[]string) (
} }
// toCreatePayload creates an API create payload from the resource model. // toCreatePayload creates an API create payload from the resource model.
func toCreatePayload(model *ResourceModel, roles *[]string) (*postgresflex.CreateUserRequestPayload, error) { func toCreatePayload(model *resourceModel, roles *[]string) (*postgresflex.CreateUserRequestPayload, error) {
if model == nil { if model == nil {
return nil, fmt.Errorf("nil model") return nil, fmt.Errorf("nil model")
} }
@ -101,7 +101,7 @@ func toCreatePayload(model *ResourceModel, roles *[]string) (*postgresflex.Creat
} }
// mapResourceFields maps API response to the resource model, preserving existing ID. // mapResourceFields maps API response to the resource model, preserving existing ID.
func mapResourceFields(userResp *postgresflex.GetUserResponse, model *ResourceModel, region string) error { func mapResourceFields(userResp *postgresflex.GetUserResponse, model *resourceModel, region string) error {
if userResp == nil { if userResp == nil {
return fmt.Errorf("response is nil") return fmt.Errorf("response is nil")
} }
@ -118,9 +118,7 @@ func mapResourceFields(userResp *postgresflex.GetUserResponse, model *ResourceMo
} else { } else {
return fmt.Errorf("user id not present") return fmt.Errorf("user id not present")
} }
model.TerraformID = utils.BuildInternalTerraformId(
model.ProjectId.ValueString(), region, model.InstanceId.ValueString(), strconv.FormatInt(userId, 10),
)
model.Id = types.Int64Value(userId) model.Id = types.Int64Value(userId)
model.UserId = types.Int64Value(userId) model.UserId = types.Int64Value(userId)
model.Name = types.StringPointerValue(user.Name) model.Name = types.StringPointerValue(user.Name)

View file

@ -9,7 +9,6 @@ import (
"github.com/stackitcloud/stackit-sdk-go/core/utils" "github.com/stackitcloud/stackit-sdk-go/core/utils"
postgresflex "tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/pkg_gen/postgresflexalpha" postgresflex "tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/pkg_gen/postgresflexalpha"
data "tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit/internal/services/postgresflexalpha/user/datasources_gen" data "tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit/internal/services/postgresflexalpha/user/datasources_gen"
resource "tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit/internal/services/postgresflexalpha/user/resources_gen"
) )
func TestMapDataSourceFields(t *testing.T) { func TestMapDataSourceFields(t *testing.T) {
@ -18,14 +17,14 @@ func TestMapDataSourceFields(t *testing.T) {
description string description string
input *postgresflex.GetUserResponse input *postgresflex.GetUserResponse
region string region string
expected DataSourceModel expected dataSourceModel
isValid bool isValid bool
}{ }{
{ {
"default_values", "default_values",
&postgresflex.GetUserResponse{}, &postgresflex.GetUserResponse{},
testRegion, testRegion,
DataSourceModel{ dataSourceModel{
UserModel: data.UserModel{ UserModel: data.UserModel{
Id: types.Int64Value(1), Id: types.Int64Value(1),
UserId: types.Int64Value(1), UserId: types.Int64Value(1),
@ -51,7 +50,7 @@ func TestMapDataSourceFields(t *testing.T) {
Name: utils.Ptr("username"), Name: utils.Ptr("username"),
}, },
testRegion, testRegion,
DataSourceModel{ dataSourceModel{
UserModel: data.UserModel{ UserModel: data.UserModel{
Id: types.Int64Value(1), Id: types.Int64Value(1),
@ -84,7 +83,7 @@ func TestMapDataSourceFields(t *testing.T) {
Status: utils.Ptr("status"), Status: utils.Ptr("status"),
}, },
testRegion, testRegion,
DataSourceModel{ dataSourceModel{
UserModel: data.UserModel{ UserModel: data.UserModel{
Id: types.Int64Value(1), Id: types.Int64Value(1),
UserId: types.Int64Value(1), UserId: types.Int64Value(1),
@ -103,28 +102,28 @@ func TestMapDataSourceFields(t *testing.T) {
"nil_response", "nil_response",
nil, nil,
testRegion, testRegion,
DataSourceModel{}, dataSourceModel{},
false, false,
}, },
{ {
"nil_response_2", "nil_response_2",
&postgresflex.GetUserResponse{}, &postgresflex.GetUserResponse{},
testRegion, testRegion,
DataSourceModel{}, dataSourceModel{},
false, false,
}, },
{ {
"no_resource_id", "no_resource_id",
&postgresflex.GetUserResponse{}, &postgresflex.GetUserResponse{},
testRegion, testRegion,
DataSourceModel{}, dataSourceModel{},
false, false,
}, },
} }
for _, tt := range tests { for _, tt := range tests {
t.Run( t.Run(
tt.description, func(t *testing.T) { tt.description, func(t *testing.T) {
state := &DataSourceModel{ state := &dataSourceModel{
UserModel: data.UserModel{ UserModel: data.UserModel{
ProjectId: tt.expected.ProjectId, ProjectId: tt.expected.ProjectId,
InstanceId: tt.expected.InstanceId, InstanceId: tt.expected.InstanceId,
@ -155,7 +154,7 @@ func TestMapFieldsCreate(t *testing.T) {
description string description string
input *postgresflex.GetUserResponse input *postgresflex.GetUserResponse
region string region string
expected ResourceModel expected resourceModel
isValid bool isValid bool
}{ }{
{ {
@ -164,19 +163,16 @@ func TestMapFieldsCreate(t *testing.T) {
Id: utils.Ptr(int64(1)), Id: utils.Ptr(int64(1)),
}, },
testRegion, testRegion,
ResourceModel{ resourceModel{
UserModel: resource.UserModel{ UserId: types.Int64Value(1),
UserId: types.Int64Value(1), InstanceId: types.StringValue("iid"),
InstanceId: types.StringValue("iid"), ProjectId: types.StringValue("pid"),
ProjectId: types.StringValue("pid"), Name: types.StringNull(),
Name: types.StringNull(), Roles: types.List(types.SetNull(types.StringType)),
Roles: types.List(types.SetNull(types.StringType)), Password: types.StringNull(),
Password: types.StringNull(), Region: types.StringValue(testRegion),
Region: types.StringValue(testRegion), Status: types.StringNull(),
Status: types.StringNull(), ConnectionString: types.StringNull(),
ConnectionString: types.StringNull(),
},
TerraformID: types.StringValue("pid,region,iid,1"),
}, },
true, true,
}, },
@ -188,19 +184,16 @@ func TestMapFieldsCreate(t *testing.T) {
Status: utils.Ptr("status"), Status: utils.Ptr("status"),
}, },
testRegion, testRegion,
ResourceModel{ resourceModel{
UserModel: resource.UserModel{ UserId: types.Int64Value(1),
UserId: types.Int64Value(1), InstanceId: types.StringValue("iid"),
InstanceId: types.StringValue("iid"), ProjectId: types.StringValue("pid"),
ProjectId: types.StringValue("pid"), Name: types.StringValue("username"),
Name: types.StringValue("username"), Roles: types.List(types.SetNull(types.StringType)),
Roles: types.List(types.SetNull(types.StringType)), Password: types.StringNull(),
Password: types.StringNull(), Region: types.StringValue(testRegion),
Region: types.StringValue(testRegion), Status: types.StringValue("status"),
Status: types.StringValue("status"), ConnectionString: types.StringValue("connection_string"),
ConnectionString: types.StringValue("connection_string"),
},
TerraformID: types.StringValue("pid,region,iid,1"),
}, },
true, true,
}, },
@ -212,19 +205,16 @@ func TestMapFieldsCreate(t *testing.T) {
Status: nil, Status: nil,
}, },
testRegion, testRegion,
ResourceModel{ resourceModel{
UserModel: resource.UserModel{ UserId: types.Int64Value(1),
UserId: types.Int64Value(1), InstanceId: types.StringValue("iid"),
InstanceId: types.StringValue("iid"), ProjectId: types.StringValue("pid"),
ProjectId: types.StringValue("pid"), Name: types.StringNull(),
Name: types.StringNull(), Roles: types.List(types.SetNull(types.StringType)),
Roles: types.List(types.SetNull(types.StringType)), Password: types.StringNull(),
Password: types.StringNull(), Region: types.StringValue(testRegion),
Region: types.StringValue(testRegion), Status: types.StringNull(),
Status: types.StringNull(), ConnectionString: types.StringNull(),
ConnectionString: types.StringNull(),
},
TerraformID: types.StringValue("pid,region,iid,1"),
}, },
true, true,
}, },
@ -232,32 +222,30 @@ func TestMapFieldsCreate(t *testing.T) {
"nil_response", "nil_response",
nil, nil,
testRegion, testRegion,
ResourceModel{}, resourceModel{},
false, false,
}, },
{ {
"nil_response_2", "nil_response_2",
&postgresflex.GetUserResponse{}, &postgresflex.GetUserResponse{},
testRegion, testRegion,
ResourceModel{}, resourceModel{},
false, false,
}, },
{ {
"no_resource_id", "no_resource_id",
&postgresflex.GetUserResponse{}, &postgresflex.GetUserResponse{},
testRegion, testRegion,
ResourceModel{}, resourceModel{},
false, false,
}, },
} }
for _, tt := range tests { for _, tt := range tests {
t.Run( t.Run(
tt.description, func(t *testing.T) { tt.description, func(t *testing.T) {
state := &ResourceModel{ state := &resourceModel{
UserModel: resource.UserModel{ ProjectId: tt.expected.ProjectId,
ProjectId: tt.expected.ProjectId, InstanceId: tt.expected.InstanceId,
InstanceId: tt.expected.InstanceId,
},
} }
err := mapResourceFields(tt.input, state, tt.region) err := mapResourceFields(tt.input, state, tt.region)
@ -284,7 +272,7 @@ func TestMapFields(t *testing.T) {
description string description string
input *postgresflex.GetUserResponse input *postgresflex.GetUserResponse
region string region string
expected ResourceModel expected resourceModel
isValid bool isValid bool
}{ }{
{ {
@ -293,19 +281,16 @@ func TestMapFields(t *testing.T) {
Id: utils.Ptr(int64(1)), Id: utils.Ptr(int64(1)),
}, },
testRegion, testRegion,
ResourceModel{ resourceModel{
UserModel: resource.UserModel{ Id: types.Int64Value(1),
Id: types.Int64Value(1), UserId: types.Int64Value(int64(1)),
UserId: types.Int64Value(int64(1)), InstanceId: types.StringValue("iid"),
InstanceId: types.StringValue("iid"), ProjectId: types.StringValue("pid"),
ProjectId: types.StringValue("pid"), Name: types.StringNull(),
Name: types.StringNull(), Roles: types.List(types.SetNull(types.StringType)),
Roles: types.List(types.SetNull(types.StringType)), Region: types.StringValue(testRegion),
Region: types.StringValue(testRegion), Status: types.StringNull(),
Status: types.StringNull(), ConnectionString: types.StringNull(),
ConnectionString: types.StringNull(),
},
TerraformID: types.StringValue("pid,region,iid,1"),
}, },
true, true,
}, },
@ -321,27 +306,24 @@ func TestMapFields(t *testing.T) {
Name: utils.Ptr("username"), Name: utils.Ptr("username"),
}, },
testRegion, testRegion,
ResourceModel{ resourceModel{
UserModel: resource.UserModel{ Id: types.Int64Value(1),
Id: types.Int64Value(1), UserId: types.Int64Value(1),
UserId: types.Int64Value(1), InstanceId: types.StringValue("iid"),
InstanceId: types.StringValue("iid"), ProjectId: types.StringValue("pid"),
ProjectId: types.StringValue("pid"), Name: types.StringValue("username"),
Name: types.StringValue("username"), Roles: types.List(
Roles: types.List( types.SetValueMust(
types.SetValueMust( types.StringType, []attr.Value{
types.StringType, []attr.Value{ types.StringValue("role_1"),
types.StringValue("role_1"), types.StringValue("role_2"),
types.StringValue("role_2"), types.StringValue(""),
types.StringValue(""), },
},
),
), ),
Region: types.StringValue(testRegion), ),
Status: types.StringNull(), Region: types.StringValue(testRegion),
ConnectionString: types.StringNull(), Status: types.StringNull(),
}, ConnectionString: types.StringNull(),
TerraformID: types.StringValue("pid,region,iid,1"),
}, },
true, true,
}, },
@ -352,19 +334,16 @@ func TestMapFields(t *testing.T) {
Name: nil, Name: nil,
}, },
testRegion, testRegion,
ResourceModel{ resourceModel{
UserModel: resource.UserModel{ Id: types.Int64Value(1),
Id: types.Int64Value(1), UserId: types.Int64Value(1),
UserId: types.Int64Value(1), InstanceId: types.StringValue("iid"),
InstanceId: types.StringValue("iid"), ProjectId: types.StringValue("pid"),
ProjectId: types.StringValue("pid"), Name: types.StringNull(),
Name: types.StringNull(), Roles: types.List(types.SetNull(types.StringType)),
Roles: types.List(types.SetNull(types.StringType)), Region: types.StringValue(testRegion),
Region: types.StringValue(testRegion), Status: types.StringNull(),
Status: types.StringNull(), ConnectionString: types.StringNull(),
ConnectionString: types.StringNull(),
},
TerraformID: types.StringValue("pid,region,iid,1"),
}, },
true, true,
}, },
@ -372,32 +351,30 @@ func TestMapFields(t *testing.T) {
"nil_response", "nil_response",
nil, nil,
testRegion, testRegion,
ResourceModel{}, resourceModel{},
false, false,
}, },
{ {
"nil_response_2", "nil_response_2",
&postgresflex.GetUserResponse{}, &postgresflex.GetUserResponse{},
testRegion, testRegion,
ResourceModel{}, resourceModel{},
false, false,
}, },
{ {
"no_resource_id", "no_resource_id",
&postgresflex.GetUserResponse{}, &postgresflex.GetUserResponse{},
testRegion, testRegion,
ResourceModel{}, resourceModel{},
false, false,
}, },
} }
for _, tt := range tests { for _, tt := range tests {
t.Run( t.Run(
tt.description, func(t *testing.T) { tt.description, func(t *testing.T) {
state := &ResourceModel{ state := &resourceModel{
UserModel: resource.UserModel{ ProjectId: tt.expected.ProjectId,
ProjectId: tt.expected.ProjectId, InstanceId: tt.expected.InstanceId,
InstanceId: tt.expected.InstanceId,
},
} }
err := mapResourceFields(tt.input, state, tt.region) err := mapResourceFields(tt.input, state, tt.region)
if !tt.isValid && err == nil { if !tt.isValid && err == nil {
@ -420,14 +397,14 @@ func TestMapFields(t *testing.T) {
func TestToCreatePayload(t *testing.T) { func TestToCreatePayload(t *testing.T) {
tests := []struct { tests := []struct {
description string description string
input *ResourceModel input *resourceModel
inputRoles *[]string inputRoles *[]string
expected *postgresflex.CreateUserRequestPayload expected *postgresflex.CreateUserRequestPayload
isValid bool isValid bool
}{ }{
{ {
"default_values", "default_values",
&ResourceModel{}, &resourceModel{},
&[]string{}, &[]string{},
&postgresflex.CreateUserRequestPayload{ &postgresflex.CreateUserRequestPayload{
Name: nil, Name: nil,
@ -437,10 +414,8 @@ func TestToCreatePayload(t *testing.T) {
}, },
{ {
"simple_values", "simple_values",
&ResourceModel{ &resourceModel{
UserModel: resource.UserModel{ Name: types.StringValue("username"),
Name: types.StringValue("username"),
},
}, },
&[]string{ &[]string{
"role_1", "role_1",
@ -457,10 +432,8 @@ func TestToCreatePayload(t *testing.T) {
}, },
{ {
"null_fields_and_int_conversions", "null_fields_and_int_conversions",
&ResourceModel{ &resourceModel{
UserModel: resource.UserModel{ Name: types.StringNull(),
Name: types.StringNull(),
},
}, },
&[]string{ &[]string{
"", "",
@ -482,7 +455,7 @@ func TestToCreatePayload(t *testing.T) {
}, },
{ {
"nil_roles", "nil_roles",
&ResourceModel{}, &resourceModel{},
nil, nil,
nil, nil,
false, false,
@ -512,14 +485,14 @@ func TestToCreatePayload(t *testing.T) {
func TestToUpdatePayload(t *testing.T) { func TestToUpdatePayload(t *testing.T) {
tests := []struct { tests := []struct {
description string description string
input *ResourceModel input *resourceModel
inputRoles *[]string inputRoles *[]string
expected *postgresflex.UpdateUserRequestPayload expected *postgresflex.UpdateUserRequestPayload
isValid bool isValid bool
}{ }{
{ {
"default_values", "default_values",
&ResourceModel{}, &resourceModel{},
&[]string{}, &[]string{},
&postgresflex.UpdateUserRequestPayload{ &postgresflex.UpdateUserRequestPayload{
Roles: &[]postgresflex.UserRole{}, Roles: &[]postgresflex.UserRole{},
@ -528,10 +501,8 @@ func TestToUpdatePayload(t *testing.T) {
}, },
{ {
"default_values", "default_values",
&ResourceModel{ &resourceModel{
UserModel: resource.UserModel{ Name: types.StringValue("username"),
Name: types.StringValue("username"),
},
}, },
&[]string{ &[]string{
"role_1", "role_1",
@ -548,10 +519,8 @@ func TestToUpdatePayload(t *testing.T) {
}, },
{ {
"null_fields_and_int_conversions", "null_fields_and_int_conversions",
&ResourceModel{ &resourceModel{
UserModel: resource.UserModel{ Name: types.StringNull(),
Name: types.StringNull(),
},
}, },
&[]string{ &[]string{
"", "",
@ -572,7 +541,7 @@ func TestToUpdatePayload(t *testing.T) {
}, },
{ {
"nil_roles", "nil_roles",
&ResourceModel{}, &resourceModel{},
nil, nil,
nil, nil,
false, false,

View file

@ -41,12 +41,14 @@ var (
extractErrorMessage = "Extracting identity data: %v" extractErrorMessage = "Extracting identity data: %v"
) )
// ResourceModel represents the Terraform resource state for a PostgreSQL Flex user. // NewUserResource is a helper function to simplify the provider implementation.
type ResourceModel struct { func NewUserResource() resource.Resource {
postgresflexalpha.UserModel return &userResource{}
TerraformID types.String `tfsdk:"id"`
} }
// resourceModel represents the Terraform resource state for a PostgreSQL Flex user.
type resourceModel = postgresflexalpha.UserModel
// UserResourceIdentityModel describes the resource's identity attributes. // UserResourceIdentityModel describes the resource's identity attributes.
type UserResourceIdentityModel struct { type UserResourceIdentityModel struct {
ProjectID types.String `tfsdk:"project_id"` ProjectID types.String `tfsdk:"project_id"`
@ -55,11 +57,6 @@ type UserResourceIdentityModel struct {
UserID types.Int64 `tfsdk:"database_id"` UserID types.Int64 `tfsdk:"database_id"`
} }
// NewUserResource is a helper function to simplify the provider implementation.
func NewUserResource() resource.Resource {
return &userResource{}
}
// userResource implements the resource handling for a PostgreSQL Flex user. // userResource implements the resource handling for a PostgreSQL Flex user.
type userResource struct { type userResource struct {
client *postgresflex.APIClient client *postgresflex.APIClient
@ -73,7 +70,7 @@ func (r *userResource) ModifyPlan(
req resource.ModifyPlanRequest, req resource.ModifyPlanRequest,
resp *resource.ModifyPlanResponse, resp *resource.ModifyPlanResponse,
) { // nolint:gocritic // function signature required by Terraform ) { // nolint:gocritic // function signature required by Terraform
var configModel ResourceModel var configModel resourceModel
// skip initial empty configuration to avoid follow-up errors // skip initial empty configuration to avoid follow-up errors
if req.Config.Raw.IsNull() { if req.Config.Raw.IsNull() {
return return
@ -83,7 +80,7 @@ func (r *userResource) ModifyPlan(
return return
} }
var planModel ResourceModel var planModel resourceModel
resp.Diagnostics.Append(req.Plan.Get(ctx, &planModel)...) resp.Diagnostics.Append(req.Plan.Get(ctx, &planModel)...)
if resp.Diagnostics.HasError() { if resp.Diagnostics.HasError() {
return return
@ -153,7 +150,7 @@ func (r *userResource) Create(
req resource.CreateRequest, req resource.CreateRequest,
resp *resource.CreateResponse, resp *resource.CreateResponse,
) { // nolint:gocritic // function signature required by Terraform ) { // nolint:gocritic // function signature required by Terraform
var model ResourceModel var model resourceModel
diags := req.Plan.Get(ctx, &model) diags := req.Plan.Get(ctx, &model)
resp.Diagnostics.Append(diags...) resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() { if resp.Diagnostics.HasError() {
@ -252,7 +249,7 @@ func (r *userResource) Read(
req resource.ReadRequest, req resource.ReadRequest,
resp *resource.ReadResponse, resp *resource.ReadResponse,
) { // nolint:gocritic // function signature required by Terraform ) { // nolint:gocritic // function signature required by Terraform
var model ResourceModel var model resourceModel
diags := req.State.Get(ctx, &model) diags := req.State.Get(ctx, &model)
resp.Diagnostics.Append(diags...) resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() { if resp.Diagnostics.HasError() {
@ -312,7 +309,7 @@ func (r *userResource) Update(
req resource.UpdateRequest, req resource.UpdateRequest,
resp *resource.UpdateResponse, resp *resource.UpdateResponse,
) { // nolint:gocritic // function signature required by Terraform ) { // nolint:gocritic // function signature required by Terraform
var model ResourceModel var model resourceModel
diags := req.Plan.Get(ctx, &model) diags := req.Plan.Get(ctx, &model)
resp.Diagnostics.Append(diags...) resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() { if resp.Diagnostics.HasError() {
@ -342,7 +339,7 @@ func (r *userResource) Update(
ctx = core.InitProviderContext(ctx) ctx = core.InitProviderContext(ctx)
// Retrieve values from state // Retrieve values from state
var stateModel ResourceModel var stateModel resourceModel
diags = req.State.Get(ctx, &stateModel) diags = req.State.Get(ctx, &stateModel)
resp.Diagnostics.Append(diags...) resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() { if resp.Diagnostics.HasError() {
@ -414,7 +411,7 @@ func (r *userResource) Delete(
req resource.DeleteRequest, req resource.DeleteRequest,
resp *resource.DeleteResponse, resp *resource.DeleteResponse,
) { // nolint:gocritic // function signature required by Terraform ) { // nolint:gocritic // function signature required by Terraform
var model ResourceModel var model resourceModel
diags := req.State.Get(ctx, &model) diags := req.State.Get(ctx, &model)
resp.Diagnostics.Append(diags...) resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() { if resp.Diagnostics.HasError() {
@ -559,7 +556,7 @@ func (r *userResource) ImportState(
tflog.Info(ctx, "postgresflexalpha user state imported") tflog.Info(ctx, "postgresflexalpha user state imported")
} }
func mapFields(userResp *postgresflex.GetUserResponse, model *ResourceModel, region string) error { func mapFields(userResp *postgresflex.GetUserResponse, model *resourceModel, region string) error {
if userResp == nil { if userResp == nil {
return fmt.Errorf("response is nil") return fmt.Errorf("response is nil")
} }
@ -576,9 +573,7 @@ func mapFields(userResp *postgresflex.GetUserResponse, model *ResourceModel, reg
} else { } else {
return fmt.Errorf("user id not present") return fmt.Errorf("user id not present")
} }
model.TerraformID = utils.BuildInternalTerraformId(
model.ProjectId.ValueString(), region, model.InstanceId.ValueString(), strconv.FormatInt(userId, 10),
)
model.UserId = types.Int64Value(userId) model.UserId = types.Int64Value(userId)
model.Name = types.StringPointerValue(user.Name) model.Name = types.StringPointerValue(user.Name)
@ -602,7 +597,7 @@ func mapFields(userResp *postgresflex.GetUserResponse, model *ResourceModel, reg
// getUserResource refreshes the resource state by calling the API and mapping the response to the model. // getUserResource refreshes the resource state by calling the API and mapping the response to the model.
// Returns true if the resource state was successfully refreshed, false if the resource does not exist. // Returns true if the resource state was successfully refreshed, false if the resource does not exist.
func (r *userResource) getUserResource(ctx context.Context, model *ResourceModel, arg *clientArg) (bool, error) { func (r *userResource) getUserResource(ctx context.Context, model *resourceModel, arg *clientArg) (bool, error) {
if arg.userId > math.MaxInt32 { if arg.userId > math.MaxInt32 {
return false, errors.New("error in type conversion: int value too large (userId)") return false, errors.New("error in type conversion: int value too large (userId)")
@ -638,7 +633,7 @@ type clientArg struct {
// extractIdentityData extracts essential identifiers from the resource model, falling back to the identity model. // extractIdentityData extracts essential identifiers from the resource model, falling back to the identity model.
func (r *userResource) extractIdentityData( func (r *userResource) extractIdentityData(
model ResourceModel, model resourceModel,
identity UserResourceIdentityModel, identity UserResourceIdentityModel,
) (*clientArg, error) { ) (*clientArg, error) {

View file

@ -4,6 +4,8 @@ import (
"context" "context"
"github.com/hashicorp/terraform-plugin-framework/datasource" "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-log/tflog" "github.com/hashicorp/terraform-plugin-log/tflog"
"tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/pkg_gen/sqlserverflexalpha" "tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/pkg_gen/sqlserverflexalpha"
"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/conversion"
@ -12,6 +14,12 @@ import (
sqlserverflexUtils "tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit/internal/services/sqlserverflexalpha/utils" sqlserverflexUtils "tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit/internal/services/sqlserverflexalpha/utils"
) )
// dataSourceModel maps the data source schema data.
type dataSourceModel struct {
sqlserverflexalphaGen.DatabaseModel
TerraformID types.String `tfsdk:"id"`
}
var _ datasource.DataSource = (*databaseDataSource)(nil) var _ datasource.DataSource = (*databaseDataSource)(nil)
func NewDatabaseDataSource() datasource.DataSource { func NewDatabaseDataSource() datasource.DataSource {
@ -23,16 +31,31 @@ type databaseDataSource struct {
providerData core.ProviderData providerData core.ProviderData
} }
func (d *databaseDataSource) Metadata(_ context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) { func (d *databaseDataSource) Metadata(
_ context.Context,
req datasource.MetadataRequest,
resp *datasource.MetadataResponse,
) {
resp.TypeName = req.ProviderTypeName + "_sqlserverflexalpha_database" resp.TypeName = req.ProviderTypeName + "_sqlserverflexalpha_database"
} }
func (d *databaseDataSource) Schema(ctx context.Context, _ datasource.SchemaRequest, resp *datasource.SchemaResponse) { func (d *databaseDataSource) Schema(ctx context.Context, _ datasource.SchemaRequest, resp *datasource.SchemaResponse) {
resp.Schema = sqlserverflexalphaGen.DatabaseDataSourceSchema(ctx) s := sqlserverflexalphaGen.DatabaseDataSourceSchema(ctx)
s.Attributes["id"] = schema.StringAttribute{
Description: "Terraform's internal resource ID. It is structured as \\\"`project_id`,`region`,`instance_id`," +
"`database_id`\\\".\",",
Computed: true,
}
resp.Schema = s
} }
// Configure adds the provider configured client to the data source. // Configure adds the provider configured client to the data source.
func (d *databaseDataSource) Configure(ctx context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) { func (d *databaseDataSource) Configure(
ctx context.Context,
req datasource.ConfigureRequest,
resp *datasource.ConfigureResponse,
) {
var ok bool var ok bool
d.providerData, ok = conversion.ParseProviderData(ctx, req.ProviderData, &resp.Diagnostics) d.providerData, ok = conversion.ParseProviderData(ctx, req.ProviderData, &resp.Diagnostics)
if !ok { if !ok {
@ -48,7 +71,7 @@ func (d *databaseDataSource) Configure(ctx context.Context, req datasource.Confi
} }
func (d *databaseDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { func (d *databaseDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) {
var data sqlserverflexalphaGen.DatabaseModel var data dataSourceModel
// Read Terraform configuration data into the model // Read Terraform configuration data into the model
resp.Diagnostics.Append(req.Config.Get(ctx, &data)...) resp.Diagnostics.Append(req.Config.Get(ctx, &data)...)

View file

@ -25,6 +25,9 @@ var (
_ resource.ResourceWithModifyPlan = &databaseResource{} _ resource.ResourceWithModifyPlan = &databaseResource{}
) )
// resourceModel describes the resource data model.
type resourceModel = sqlserverflexalphaGen.DatabaseModel
func NewDatabaseResource() resource.Resource { func NewDatabaseResource() resource.Resource {
return &databaseResource{} return &databaseResource{}
} }
@ -59,7 +62,10 @@ func (r *databaseResource) Configure(
utils.UserAgentConfigOption(r.providerData.Version), utils.UserAgentConfigOption(r.providerData.Version),
} }
if r.providerData.PostgresFlexCustomEndpoint != "" { if r.providerData.PostgresFlexCustomEndpoint != "" {
apiClientConfigOptions = append(apiClientConfigOptions, config.WithEndpoint(r.providerData.PostgresFlexCustomEndpoint)) apiClientConfigOptions = append(
apiClientConfigOptions,
config.WithEndpoint(r.providerData.PostgresFlexCustomEndpoint),
)
} else { } else {
apiClientConfigOptions = append(apiClientConfigOptions, config.WithRegion(r.providerData.GetRegion())) apiClientConfigOptions = append(apiClientConfigOptions, config.WithRegion(r.providerData.GetRegion()))
} }
@ -67,7 +73,10 @@ func (r *databaseResource) Configure(
if err != nil { if err != nil {
resp.Diagnostics.AddError( resp.Diagnostics.AddError(
"Error configuring API client", "Error configuring API client",
fmt.Sprintf("Configuring client: %v. This is an error related to the provider configuration, not to the resource configuration", err), fmt.Sprintf(
"Configuring client: %v. This is an error related to the provider configuration, not to the resource configuration",
err,
),
) )
return return
} }
@ -97,7 +106,7 @@ func (r *databaseResource) Create(ctx context.Context, req resource.CreateReques
} }
func (r *databaseResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { func (r *databaseResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
var data sqlserverflexalphaGen.DatabaseModel var data resourceModel
// Read Terraform prior state data into the model // Read Terraform prior state data into the model
resp.Diagnostics.Append(req.State.Get(ctx, &data)...) resp.Diagnostics.Append(req.State.Get(ctx, &data)...)
@ -115,7 +124,7 @@ func (r *databaseResource) Read(ctx context.Context, req resource.ReadRequest, r
} }
func (r *databaseResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { func (r *databaseResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
var data sqlserverflexalphaGen.DatabaseModel var data resourceModel
// Read Terraform plan data into the model // Read Terraform plan data into the model
resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...) resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...)

View file

@ -26,6 +26,11 @@ var (
_ datasource.DataSourceWithConfigure = &flavorDataSource{} _ datasource.DataSourceWithConfigure = &flavorDataSource{}
) )
// NewFlavorDataSource is a helper function to simplify the provider implementation.
func NewFlavorDataSource() datasource.DataSource {
return &flavorDataSource{}
}
type FlavorModel struct { type FlavorModel struct {
ProjectId types.String `tfsdk:"project_id"` ProjectId types.String `tfsdk:"project_id"`
Region types.String `tfsdk:"region"` Region types.String `tfsdk:"region"`
@ -41,11 +46,6 @@ type FlavorModel struct {
StorageClasses types.List `tfsdk:"storage_classes"` 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. // flavorDataSource is the data source implementation.
type flavorDataSource struct { type flavorDataSource struct {
client *sqlserverflexalpha.APIClient client *sqlserverflexalpha.APIClient
@ -53,12 +53,20 @@ type flavorDataSource struct {
} }
// Metadata returns the data source type name. // Metadata returns the data source type name.
func (r *flavorDataSource) Metadata(_ context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) { func (r *flavorDataSource) Metadata(
_ context.Context,
req datasource.MetadataRequest,
resp *datasource.MetadataResponse,
) {
resp.TypeName = req.ProviderTypeName + "_sqlserverflexalpha_flavor" resp.TypeName = req.ProviderTypeName + "_sqlserverflexalpha_flavor"
} }
// Configure adds the provider configured client to the data source. // Configure adds the provider configured client to the data source.
func (r *flavorDataSource) Configure(ctx context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) { func (r *flavorDataSource) Configure(
ctx context.Context,
req datasource.ConfigureRequest,
resp *datasource.ConfigureResponse,
) {
var ok bool var ok bool
r.providerData, ok = conversion.ParseProviderData(ctx, req.ProviderData, &resp.Diagnostics) r.providerData, ok = conversion.ParseProviderData(ctx, req.ProviderData, &resp.Diagnostics)
if !ok { if !ok {
@ -212,11 +220,13 @@ func (r *flavorDataSource) Read(ctx context.Context, req datasource.ReadRequest,
model.MinGb = types.Int64Value(*f.MinGB) model.MinGb = types.Int64Value(*f.MinGB)
if f.StorageClasses == nil { if f.StorageClasses == nil {
model.StorageClasses = types.ListNull(sqlserverflexalphaGen.StorageClassesType{ model.StorageClasses = types.ListNull(
ObjectType: basetypes.ObjectType{ sqlserverflexalphaGen.StorageClassesType{
AttrTypes: sqlserverflexalphaGen.StorageClassesValue{}.AttributeTypes(ctx), ObjectType: basetypes.ObjectType{
AttrTypes: sqlserverflexalphaGen.StorageClassesValue{}.AttributeTypes(ctx),
},
}, },
}) )
} else { } else {
var scList []attr.Value var scList []attr.Value
for _, sc := range *f.StorageClasses { for _, sc := range *f.StorageClasses {

View file

@ -13,8 +13,12 @@ import (
sqlserverflexalphaGen "tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit/internal/services/sqlserverflexalpha/flavors/datasources_gen" sqlserverflexalphaGen "tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit/internal/services/sqlserverflexalpha/flavors/datasources_gen"
) )
// dataSourceModel maps the data source schema data.
type dataSourceModel = sqlserverflexalphaGen.FlavorsModel
var _ datasource.DataSource = (*flavorsDataSource)(nil) var _ datasource.DataSource = (*flavorsDataSource)(nil)
// TODO: Use NewFlavorsDataSource when datasource is implemented
func NewFlavorsDataSource() datasource.DataSource { func NewFlavorsDataSource() datasource.DataSource {
return &flavorsDataSource{} return &flavorsDataSource{}
} }
@ -24,7 +28,11 @@ type flavorsDataSource struct {
providerData core.ProviderData providerData core.ProviderData
} }
func (d *flavorsDataSource) Metadata(_ context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) { func (d *flavorsDataSource) Metadata(
_ context.Context,
req datasource.MetadataRequest,
resp *datasource.MetadataResponse,
) {
resp.TypeName = req.ProviderTypeName + "_sqlserverflexalpha_flavors" resp.TypeName = req.ProviderTypeName + "_sqlserverflexalpha_flavors"
} }
@ -33,7 +41,11 @@ func (d *flavorsDataSource) Schema(ctx context.Context, _ datasource.SchemaReque
} }
// Configure adds the provider configured client to the data source. // Configure adds the provider configured client to the data source.
func (d *flavorsDataSource) Configure(ctx context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) { func (d *flavorsDataSource) Configure(
ctx context.Context,
req datasource.ConfigureRequest,
resp *datasource.ConfigureResponse,
) {
var ok bool var ok bool
d.providerData, ok = conversion.ParseProviderData(ctx, req.ProviderData, &resp.Diagnostics) d.providerData, ok = conversion.ParseProviderData(ctx, req.ProviderData, &resp.Diagnostics)
if !ok { if !ok {
@ -49,7 +61,7 @@ func (d *flavorsDataSource) Configure(ctx context.Context, req datasource.Config
} }
func (d *flavorsDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { func (d *flavorsDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) {
var data sqlserverflexalphaGen.FlavorsModel var data dataSourceModel
// Read Terraform configuration data into the model // Read Terraform configuration data into the model
resp.Diagnostics.Append(req.Config.Get(ctx, &data)...) resp.Diagnostics.Append(req.Config.Get(ctx, &data)...)

View file

@ -7,6 +7,8 @@ import (
"fmt" "fmt"
"net/http" "net/http"
"github.com/hashicorp/terraform-plugin-framework/datasource/schema"
"github.com/hashicorp/terraform-plugin-framework/types"
"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/conversion"
sqlserverflexalpha "tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit/internal/services/sqlserverflexalpha/instance/datasources_gen" sqlserverflexalpha "tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit/internal/services/sqlserverflexalpha/instance/datasources_gen"
sqlserverflexalpha2 "tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit/internal/services/sqlserverflexalpha/instance/resources_gen" sqlserverflexalpha2 "tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit/internal/services/sqlserverflexalpha/instance/resources_gen"
@ -20,6 +22,12 @@ import (
"tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit/internal/utils" "tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit/internal/utils"
) )
// dataSourceModel maps the data source schema data.
type dataSourceModel struct {
sqlserverflexalpha2.InstanceModel
TerraformID types.String `tfsdk:"id"`
}
// Ensure the implementation satisfies the expected interfaces. // Ensure the implementation satisfies the expected interfaces.
var ( var (
_ datasource.DataSource = &instanceDataSource{} _ datasource.DataSource = &instanceDataSource{}
@ -37,12 +45,20 @@ type instanceDataSource struct {
} }
// Metadata returns the data source type name. // Metadata returns the data source type name.
func (r *instanceDataSource) Metadata(_ context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) { func (r *instanceDataSource) Metadata(
_ context.Context,
req datasource.MetadataRequest,
resp *datasource.MetadataResponse,
) {
resp.TypeName = req.ProviderTypeName + "_sqlserverflexalpha_instance" resp.TypeName = req.ProviderTypeName + "_sqlserverflexalpha_instance"
} }
// Configure adds the provider configured client to the data source. // Configure adds the provider configured client to the data source.
func (r *instanceDataSource) Configure(ctx context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) { func (r *instanceDataSource) Configure(
ctx context.Context,
req datasource.ConfigureRequest,
resp *datasource.ConfigureResponse,
) {
var ok bool var ok bool
r.providerData, ok = conversion.ParseProviderData(ctx, req.ProviderData, &resp.Diagnostics) r.providerData, ok = conversion.ParseProviderData(ctx, req.ProviderData, &resp.Diagnostics)
if !ok { if !ok {
@ -59,167 +75,22 @@ func (r *instanceDataSource) Configure(ctx context.Context, req datasource.Confi
// Schema defines the schema for the data source. // Schema defines the schema for the data source.
func (r *instanceDataSource) Schema(ctx context.Context, _ datasource.SchemaRequest, resp *datasource.SchemaResponse) { func (r *instanceDataSource) Schema(ctx context.Context, _ datasource.SchemaRequest, resp *datasource.SchemaResponse) {
//descriptions := map[string]string{ s := sqlserverflexalpha.InstanceDataSourceSchema(ctx)
// "main": "SQLServer Flex ALPHA instance resource schema. Must have a `region` specified in the provider configuration.", s.Attributes["id"] = schema.StringAttribute{
// "id": "Terraform's internal resource ID. It is structured as \"`project_id`,`region`,`instance_id`\".", Description: "Terraform's internal resource ID. It is structured as \\\"`project_id`,`region`,`instance_id`\\\".",
// "instance_id": "ID of the SQLServer Flex instance.", Computed: true,
// "project_id": "STACKIT project ID to which the instance is associated.", }
// "name": "Instance name.",
// "access_scope": "The access scope of the instance. (e.g. SNA)",
// "acl": "The Access Control List (ACL) for the SQLServer Flex instance.",
// "backup_schedule": `The backup schedule. Should follow the cron scheduling system format (e.g. "0 0 * * *")`,
// "region": "The resource region. If not defined, the provider region is used.",
// "encryption": "The encryption block.",
// "network": "The network block.",
// "keyring_id": "STACKIT KMS - KeyRing ID of the encryption key to use.",
// "key_id": "STACKIT KMS - Key ID of the encryption key to use.",
// "key_version": "STACKIT KMS - Key version to use in the encryption key.",
// "service:account": "STACKIT KMS - service account to use in the encryption key.",
// "instance_address": "The returned instance IP address of the SQLServer Flex instance.",
// "router_address": "The returned router IP address of the SQLServer Flex instance.",
//}
resp.Schema = sqlserverflexalpha.InstanceDataSourceSchema(ctx) resp.Schema = s
//resp.Schema = schema.Schema{
// Description: descriptions["main"],
// Attributes: map[string]schema.Attribute{
// "id": schema.StringAttribute{
// Description: descriptions["id"],
// Computed: true,
// },
// "instance_id": schema.StringAttribute{
// Description: descriptions["instance_id"],
// Required: true,
// Validators: []validator.String{
// validate.UUID(),
// validate.NoSeparator(),
// },
// },
// "project_id": schema.StringAttribute{
// Description: descriptions["project_id"],
// Required: true,
// Validators: []validator.String{
// validate.UUID(),
// validate.NoSeparator(),
// },
// },
// "name": schema.StringAttribute{
// Description: descriptions["name"],
// Computed: true,
// },
// "backup_schedule": schema.StringAttribute{
// Description: descriptions["backup_schedule"],
// Computed: true,
// },
// "is_deletable": schema.BoolAttribute{
// Description: descriptions["is_deletable"],
// Computed: true,
// },
// "flavor": schema.SingleNestedAttribute{
// Computed: true,
// Attributes: map[string]schema.Attribute{
// "id": schema.StringAttribute{
// Computed: true,
// },
// "description": schema.StringAttribute{
// Computed: true,
// },
// "cpu": schema.Int64Attribute{
// Computed: true,
// },
// "ram": schema.Int64Attribute{
// Computed: true,
// },
// "node_type": schema.StringAttribute{
// Computed: true,
// },
// },
// },
// "replicas": schema.Int64Attribute{
// Computed: true,
// },
// "storage": schema.SingleNestedAttribute{
// Computed: true,
// Attributes: map[string]schema.Attribute{
// "class": schema.StringAttribute{
// Computed: true,
// },
// "size": schema.Int64Attribute{
// Computed: true,
// },
// },
// },
// "version": schema.StringAttribute{
// Computed: true,
// },
// "status": schema.StringAttribute{
// Computed: true,
// },
// "edition": schema.StringAttribute{
// Computed: true,
// },
// "retention_days": schema.Int64Attribute{
// Computed: true,
// },
// "region": schema.StringAttribute{
// // the region cannot be found, so it has to be passed
// Optional: true,
// Description: descriptions["region"],
// },
// "encryption": schema.SingleNestedAttribute{
// Computed: true,
// Attributes: map[string]schema.Attribute{
// "key_id": schema.StringAttribute{
// Description: descriptions["key_id"],
// Computed: true,
// },
// "key_version": schema.StringAttribute{
// Description: descriptions["key_version"],
// Computed: true,
// },
// "keyring_id": schema.StringAttribute{
// Description: descriptions["keyring_id"],
// Computed: true,
// },
// "service_account": schema.StringAttribute{
// Description: descriptions["service_account"],
// Computed: true,
// },
// },
// Description: descriptions["encryption"],
// },
// "network": schema.SingleNestedAttribute{
// Computed: true,
// Attributes: map[string]schema.Attribute{
// "access_scope": schema.StringAttribute{
// Description: descriptions["access_scope"],
// Computed: true,
// },
// "instance_address": schema.StringAttribute{
// Description: descriptions["instance_address"],
// Computed: true,
// },
// "router_address": schema.StringAttribute{
// Description: descriptions["router_address"],
// Computed: true,
// },
// "acl": schema.ListAttribute{
// Description: descriptions["acl"],
// ElementType: types.StringType,
// Computed: true,
// },
// },
// Description: descriptions["network"],
// },
// },
//}
} }
// Read refreshes the Terraform state with the latest data. // Read refreshes the Terraform state with the latest data.
func (r *instanceDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { // nolint:gocritic // function signature required by Terraform func (r *instanceDataSource) Read(
//var model sqlserverflexalpha2.InstanceModel ctx context.Context,
var model sqlserverflexalpha2.InstanceModel req datasource.ReadRequest,
resp *datasource.ReadResponse,
) { // nolint:gocritic // function signature required by Terraform
var model dataSourceModel
diags := req.Config.Get(ctx, &model) diags := req.Config.Get(ctx, &model)
resp.Diagnostics.Append(diags...) resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() { if resp.Diagnostics.HasError() {
@ -279,10 +150,15 @@ func (r *instanceDataSource) Read(ctx context.Context, req datasource.ReadReques
// } // }
//} //}
err = mapResponseToModel(ctx, instanceResp, &model, resp.Diagnostics) err = mapFields(ctx, instanceResp, &model, resp.Diagnostics)
//err = mapFields(ctx, instanceResp, &model, storage, encryption, network, region) //err = mapFields(ctx, instanceResp, &model, storage, encryption, network, region)
if err != nil { if err != nil {
core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading instance", fmt.Sprintf("Processing API payload: %v", err)) core.LogAndAddError(
ctx,
&resp.Diagnostics,
"Error reading instance",
fmt.Sprintf("Processing API payload: %v", err),
)
return return
} }
// Set refreshed state // Set refreshed state

View file

@ -14,26 +14,21 @@ import (
sqlserverflexResGen "tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit/internal/services/sqlserverflexalpha/instance/resources_gen" sqlserverflexResGen "tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit/internal/services/sqlserverflexalpha/instance/resources_gen"
) )
func mapResponseToModel( // instanceModel is a type constraint for models that can be mapped from a GetInstanceResponse.
type instanceModel interface {
*dataSourceModel | *resourceModel
}
func mapFields[T instanceModel](
ctx context.Context, ctx context.Context,
resp *sqlserverflex.GetInstanceResponse, resp *sqlserverflex.GetInstanceResponse,
m *sqlserverflexResGen.InstanceModel, m T,
tfDiags diag.Diagnostics, tfDiags diag.Diagnostics,
) error { ) error {
m.BackupSchedule = types.StringValue(resp.GetBackupSchedule())
m.Edition = types.StringValue(string(resp.GetEdition()))
m.Encryption = handleEncryption(m, resp)
m.FlavorId = types.StringValue(resp.GetFlavorId())
m.Id = types.StringValue(resp.GetId())
m.InstanceId = types.StringValue(resp.GetId())
m.IsDeletable = types.BoolValue(resp.GetIsDeletable())
m.Name = types.StringValue(resp.GetName())
netAcl, diags := types.ListValueFrom(ctx, types.StringType, resp.Network.GetAcl()) netAcl, diags := types.ListValueFrom(ctx, types.StringType, resp.Network.GetAcl())
tfDiags.Append(diags...) tfDiags.Append(diags...)
if diags.HasError() { if diags.HasError() {
return fmt.Errorf( return fmt.Errorf("error converting network acl response value")
"error converting network acl response value",
)
} }
net, diags := sqlserverflexResGen.NewNetworkValue( net, diags := sqlserverflexResGen.NewNetworkValue(
sqlserverflexResGen.NetworkValue{}.AttributeTypes(ctx), sqlserverflexResGen.NetworkValue{}.AttributeTypes(ctx),
@ -46,22 +41,8 @@ func mapResponseToModel(
) )
tfDiags.Append(diags...) tfDiags.Append(diags...)
if diags.HasError() { if diags.HasError() {
return fmt.Errorf( return fmt.Errorf("error converting network response value")
"error converting network response value",
"access_scope",
types.StringValue(string(resp.Network.GetAccessScope())),
"acl",
netAcl,
"instance_address",
types.StringValue(resp.Network.GetInstanceAddress()),
"router_address",
types.StringValue(resp.Network.GetRouterAddress()),
)
} }
m.Network = net
m.Replicas = types.Int64Value(int64(resp.GetReplicas()))
m.RetentionDays = types.Int64Value(resp.GetRetentionDays())
m.Status = types.StringValue(string(resp.GetStatus()))
stor, diags := sqlserverflexResGen.NewStorageValue( stor, diags := sqlserverflexResGen.NewStorageValue(
sqlserverflexResGen.StorageValue{}.AttributeTypes(ctx), sqlserverflexResGen.StorageValue{}.AttributeTypes(ctx),
@ -74,14 +55,47 @@ func mapResponseToModel(
if diags.HasError() { if diags.HasError() {
return fmt.Errorf("error converting storage response value") return fmt.Errorf("error converting storage response value")
} }
m.Storage = stor
m.Version = types.StringValue(string(resp.GetVersion())) // The interface conversion is safe due to the type constraint.
model := any(m)
if rm, ok := model.(*resourceModel); ok {
rm.BackupSchedule = types.StringValue(resp.GetBackupSchedule())
rm.Edition = types.StringValue(string(resp.GetEdition()))
rm.Encryption = handleEncryption(rm.Encryption, resp)
rm.FlavorId = types.StringValue(resp.GetFlavorId())
rm.Id = types.StringValue(resp.GetId())
rm.InstanceId = types.StringValue(resp.GetId())
rm.IsDeletable = types.BoolValue(resp.GetIsDeletable())
rm.Name = types.StringValue(resp.GetName())
rm.Network = net
rm.Replicas = types.Int64Value(int64(resp.GetReplicas()))
rm.RetentionDays = types.Int64Value(resp.GetRetentionDays())
rm.Status = types.StringValue(string(resp.GetStatus()))
rm.Storage = stor
rm.Version = types.StringValue(string(resp.GetVersion()))
} else if dm, ok := model.(*dataSourceModel); ok {
dm.BackupSchedule = types.StringValue(resp.GetBackupSchedule())
dm.Edition = types.StringValue(string(resp.GetEdition()))
dm.Encryption = handleEncryption(dm.Encryption, resp)
dm.FlavorId = types.StringValue(resp.GetFlavorId())
dm.Id = types.StringValue(resp.GetId())
dm.InstanceId = types.StringValue(resp.GetId())
dm.IsDeletable = types.BoolValue(resp.GetIsDeletable())
dm.Name = types.StringValue(resp.GetName())
dm.Network = net
dm.Replicas = types.Int64Value(int64(resp.GetReplicas()))
dm.RetentionDays = types.Int64Value(resp.GetRetentionDays())
dm.Status = types.StringValue(string(resp.GetStatus()))
dm.Storage = stor
dm.Version = types.StringValue(string(resp.GetVersion()))
}
return nil return nil
} }
func handleEncryption( func handleEncryption(
m *sqlserverflexResGen.InstanceModel, encryptionValue sqlserverflexResGen.EncryptionValue,
resp *sqlserverflex.GetInstanceResponse, resp *sqlserverflex.GetInstanceResponse,
) sqlserverflexResGen.EncryptionValue { ) sqlserverflexResGen.EncryptionValue {
if !resp.HasEncryption() || if !resp.HasEncryption() ||
@ -91,10 +105,10 @@ func handleEncryption(
resp.Encryption.KekKeyVersion == nil || resp.Encryption.KekKeyVersion == nil ||
resp.Encryption.ServiceAccount == nil { resp.Encryption.ServiceAccount == nil {
if m.Encryption.IsNull() || m.Encryption.IsUnknown() { if encryptionValue.IsNull() || encryptionValue.IsUnknown() {
return sqlserverflexResGen.NewEncryptionValueNull() return sqlserverflexResGen.NewEncryptionValueNull()
} }
return m.Encryption return encryptionValue
} }
enc := sqlserverflexResGen.NewEncryptionValueNull() enc := sqlserverflexResGen.NewEncryptionValueNull()

View file

@ -37,23 +37,26 @@ var (
_ resource.ResourceWithIdentity = &instanceResource{} _ resource.ResourceWithIdentity = &instanceResource{}
) )
// NewInstanceResource is a helper function to simplify the provider implementation.
func NewInstanceResource() resource.Resource {
return &instanceResource{}
}
//nolint:unused // TODO: remove if not needed later //nolint:unused // TODO: remove if not needed later
var validNodeTypes []string = []string{ var validNodeTypes []string = []string{
"Single", "Single",
"Replica", "Replica",
} }
// resourceModel describes the resource data model.
type resourceModel = sqlserverflexalpha2.InstanceModel
type InstanceResourceIdentityModel struct { type InstanceResourceIdentityModel struct {
ProjectID types.String `tfsdk:"project_id"` ProjectID types.String `tfsdk:"project_id"`
Region types.String `tfsdk:"region"` Region types.String `tfsdk:"region"`
InstanceID types.String `tfsdk:"instance_id"` InstanceID types.String `tfsdk:"instance_id"`
} }
// NewInstanceResource is a helper function to simplify the provider implementation.
func NewInstanceResource() resource.Resource {
return &instanceResource{}
}
// instanceResource is the resource implementation. // instanceResource is the resource implementation.
type instanceResource struct { type instanceResource struct {
client *sqlserverflexalpha.APIClient client *sqlserverflexalpha.APIClient
@ -140,27 +143,6 @@ var modifiersFileByte []byte
// Schema defines the schema for the resource. // Schema defines the schema for the resource.
func (r *instanceResource) Schema(ctx context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) { func (r *instanceResource) Schema(ctx context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) {
//descriptions := map[string]string{
// "main": "SQLServer Flex ALPHA instance resource schema. Must have a `region` specified in the provider configuration.",
// "id": "Terraform's internal resource ID. It is structured as \"`project_id`,`region`,`instance_id`\".",
// "instance_id": "ID of the SQLServer Flex instance.",
// "project_id": "STACKIT project ID to which the instance is associated.",
// "name": "Instance name.",
// "access_scope": "The access scope of the instance. (SNA | PUBLIC)",
// "flavor_id": "The flavor ID of the instance.",
// "acl": "The Access Control List (ACL) for the SQLServer Flex instance.",
// "backup_schedule": `The backup schedule. Should follow the cron scheduling system format (e.g. "0 0 * * *")`,
// "region": "The resource region. If not defined, the provider region is used.",
// "encryption": "The encryption block.",
// "replicas": "The number of replicas of the SQLServer Flex instance.",
// "network": "The network block.",
// "keyring_id": "STACKIT KMS - KeyRing ID of the encryption key to use.",
// "key_id": "STACKIT KMS - Key ID of the encryption key to use.",
// "key_version": "STACKIT KMS - Key version to use in the encryption key.",
// "service:account": "STACKIT KMS - service account to use in the encryption key.",
// "instance_address": "The returned instance IP address of the SQLServer Flex instance.",
// "router_address": "The returned router IP address of the SQLServer Flex instance.",
//}
schema := sqlserverflexalpha2.InstanceResourceSchema(ctx) schema := sqlserverflexalpha2.InstanceResourceSchema(ctx)
@ -176,234 +158,13 @@ func (r *instanceResource) Schema(ctx context.Context, _ resource.SchemaRequest,
return return
} }
resp.Schema = schema resp.Schema = schema
//resp.Schema = schema.Schema{
// Description: descriptions["main"],
// Attributes: map[string]schema.Attribute{
// "id": schema.StringAttribute{
// Description: descriptions["id"],
// Computed: true,
// PlanModifiers: []planmodifier.String{
// stringplanmodifier.UseStateForUnknown(),
// },
// },
// "instance_id": schema.StringAttribute{
// Description: descriptions["instance_id"],
// Computed: true,
// PlanModifiers: []planmodifier.String{
// stringplanmodifier.UseStateForUnknown(),
// },
// Validators: []validator.String{
// validate.UUID(),
// validate.NoSeparator(),
// },
// },
// "project_id": schema.StringAttribute{
// Description: descriptions["project_id"],
// Required: true,
// PlanModifiers: []planmodifier.String{
// stringplanmodifier.RequiresReplace(),
// },
// Validators: []validator.String{
// validate.UUID(),
// validate.NoSeparator(),
// },
// },
// "name": schema.StringAttribute{
// Description: descriptions["name"],
// Required: true,
// Validators: []validator.String{
// stringvalidator.LengthAtLeast(1),
// stringvalidator.RegexMatches(
// regexp.MustCompile("^[a-z]([-a-z0-9]*[a-z0-9])?$"),
// "must start with a letter, must have lower case letters, numbers or hyphens, and no hyphen at the end",
// ),
// },
// },
// "backup_schedule": schema.StringAttribute{
// Description: descriptions["backup_schedule"],
// Optional: true,
// Computed: true,
// PlanModifiers: []planmodifier.String{
// stringplanmodifier.UseStateForUnknown(),
// },
// },
// "is_deletable": schema.BoolAttribute{
// Description: descriptions["is_deletable"],
// Optional: true,
// Computed: true,
// PlanModifiers: []planmodifier.Bool{
// boolplanmodifier.UseStateForUnknown(),
// },
// },
// "flavor_id": schema.StringAttribute{
// PlanModifiers: []planmodifier.String{
// stringplanmodifier.RequiresReplace(),
// stringplanmodifier.UseStateForUnknown(),
// },
// Required: true,
// },
// "replicas": schema.Int64Attribute{
// Computed: true,
// PlanModifiers: []planmodifier.Int64{
// int64planmodifier.UseStateForUnknown(),
// },
// },
// "storage": schema.SingleNestedAttribute{
// Optional: true,
// Computed: true,
// PlanModifiers: []planmodifier.Object{
// objectplanmodifier.UseStateForUnknown(),
// },
// Attributes: map[string]schema.Attribute{
// "class": schema.StringAttribute{
// Optional: true,
// Computed: true,
// PlanModifiers: []planmodifier.String{
// stringplanmodifier.RequiresReplace(),
// stringplanmodifier.UseStateForUnknown(),
// },
// },
// "size": schema.Int64Attribute{
// Optional: true,
// Computed: true,
// PlanModifiers: []planmodifier.Int64{
// int64planmodifier.UseStateForUnknown(),
// },
// },
// },
// },
// "version": schema.StringAttribute{
// Optional: true,
// Computed: true,
// PlanModifiers: []planmodifier.String{
// stringplanmodifier.RequiresReplace(),
// stringplanmodifier.UseStateForUnknown(),
// },
// },
// "edition": schema.StringAttribute{
// Computed: true,
// PlanModifiers: []planmodifier.String{
// stringplanmodifier.RequiresReplace(),
// stringplanmodifier.UseStateForUnknown(),
// },
// },
// "retention_days": schema.Int64Attribute{
// Optional: true,
// Computed: true,
// PlanModifiers: []planmodifier.Int64{
// int64planmodifier.UseStateForUnknown(),
// },
// },
// "region": schema.StringAttribute{
// Optional: true,
// // must be computed to allow for storing the override value from the provider
// Computed: true,
// Description: descriptions["region"],
// PlanModifiers: []planmodifier.String{
// stringplanmodifier.RequiresReplace(),
// },
// },
// "status": schema.StringAttribute{
// Optional: true,
// // must be computed to allow for storing the override value from the provider
// Computed: true,
// Description: descriptions["status"],
// },
// "encryption": schema.SingleNestedAttribute{
// Optional: true,
// PlanModifiers: []planmodifier.Object{
// objectplanmodifier.RequiresReplace(),
// objectplanmodifier.UseStateForUnknown(),
// },
// Attributes: map[string]schema.Attribute{
// "key_id": schema.StringAttribute{
// Description: descriptions["key_id"],
// Required: true,
// PlanModifiers: []planmodifier.String{
// stringplanmodifier.RequiresReplace(),
// },
// Validators: []validator.String{
// validate.NoSeparator(),
// },
// },
// "key_version": schema.StringAttribute{
// Description: descriptions["key_version"],
// Required: true,
// PlanModifiers: []planmodifier.String{
// stringplanmodifier.RequiresReplace(),
// },
// Validators: []validator.String{
// validate.NoSeparator(),
// },
// },
// "keyring_id": schema.StringAttribute{
// Description: descriptions["keyring_id"],
// Required: true,
// PlanModifiers: []planmodifier.String{
// stringplanmodifier.RequiresReplace(),
// },
// Validators: []validator.String{
// validate.NoSeparator(),
// },
// },
// "service_account": schema.StringAttribute{
// Description: descriptions["service_account"],
// Required: true,
// PlanModifiers: []planmodifier.String{
// stringplanmodifier.RequiresReplace(),
// },
// Validators: []validator.String{
// validate.NoSeparator(),
// },
// },
// },
// Description: descriptions["encryption"],
// },
// "network": schema.SingleNestedAttribute{
// Required: true,
// Attributes: map[string]schema.Attribute{
// "access_scope": schema.StringAttribute{
// Description: descriptions["access_scope"],
// Required: true,
// PlanModifiers: []planmodifier.String{
// stringplanmodifier.RequiresReplace(),
// stringplanmodifier.UseStateForUnknown(),
// },
// Validators: []validator.String{
// validate.NoSeparator(),
// },
// },
// "acl": schema.ListAttribute{
// Description: descriptions["acl"],
// ElementType: types.StringType,
// Required: true,
// PlanModifiers: []planmodifier.List{
// listplanmodifier.UseStateForUnknown(),
// },
// },
// "instance_address": schema.StringAttribute{
// Description: descriptions["instance_address"],
// Computed: true,
// PlanModifiers: []planmodifier.String{
// stringplanmodifier.UseStateForUnknown(),
// },
// },
// "router_address": schema.StringAttribute{
// Description: descriptions["router_address"],
// Computed: true,
// PlanModifiers: []planmodifier.String{
// stringplanmodifier.UseStateForUnknown(),
// },
// },
// },
// Description: descriptions["network"],
// },
// },
//}
} }
func (r *instanceResource) IdentitySchema(_ context.Context, _ resource.IdentitySchemaRequest, resp *resource.IdentitySchemaResponse) { func (r *instanceResource) IdentitySchema(
_ context.Context,
_ resource.IdentitySchemaRequest,
resp *resource.IdentitySchemaResponse,
) {
resp.IdentitySchema = identityschema.Schema{ resp.IdentitySchema = identityschema.Schema{
Attributes: map[string]identityschema.Attribute{ Attributes: map[string]identityschema.Attribute{
"project_id": identityschema.StringAttribute{ "project_id": identityschema.StringAttribute{
@ -425,7 +186,7 @@ func (r *instanceResource) Create(
req resource.CreateRequest, req resource.CreateRequest,
resp *resource.CreateResponse, resp *resource.CreateResponse,
) { // nolint:gocritic // function signature required by Terraform ) { // nolint:gocritic // function signature required by Terraform
var model sqlserverflexalpha2.InstanceModel var model resourceModel
diags := req.Plan.Get(ctx, &model) diags := req.Plan.Get(ctx, &model)
resp.Diagnostics.Append(diags...) resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() { if resp.Diagnostics.HasError() {
@ -528,7 +289,7 @@ func (r *instanceResource) Create(
// Map response body to schema // Map response body to schema
// err = mapFields(ctx, waitResp, &model, storage, encryption, network, region) // err = mapFields(ctx, waitResp, &model, storage, encryption, network, region)
err = mapResponseToModel(ctx, waitResp, &model, resp.Diagnostics) err = mapFields(ctx, waitResp, &model, resp.Diagnostics)
if err != nil { if err != nil {
core.LogAndAddError( core.LogAndAddError(
ctx, ctx,
@ -554,7 +315,7 @@ func (r *instanceResource) Read(
req resource.ReadRequest, req resource.ReadRequest,
resp *resource.ReadResponse, resp *resource.ReadResponse,
) { // nolint:gocritic // function signature required by Terraform ) { // nolint:gocritic // function signature required by Terraform
var model sqlserverflexalpha2.InstanceModel var model resourceModel
diags := req.State.Get(ctx, &model) diags := req.State.Get(ctx, &model)
resp.Diagnostics.Append(diags...) resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() { if resp.Diagnostics.HasError() {
@ -592,7 +353,7 @@ func (r *instanceResource) Read(
ctx = core.LogResponse(ctx) ctx = core.LogResponse(ctx)
// Map response body to schema // Map response body to schema
err = mapResponseToModel(ctx, instanceResp, &model, resp.Diagnostics) err = mapFields(ctx, instanceResp, &model, resp.Diagnostics)
if err != nil { if err != nil {
core.LogAndAddError( core.LogAndAddError(
ctx, ctx,
@ -629,7 +390,7 @@ func (r *instanceResource) Update(
resp *resource.UpdateResponse, resp *resource.UpdateResponse,
) { // nolint:gocritic // function signature required by Terraform ) { // nolint:gocritic // function signature required by Terraform
// Retrieve values from plan // Retrieve values from plan
var model sqlserverflexalpha2.InstanceModel var model resourceModel
diags := req.Plan.Get(ctx, &model) diags := req.Plan.Get(ctx, &model)
resp.Diagnostics.Append(diags...) resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() { if resp.Diagnostics.HasError() {
@ -683,7 +444,7 @@ func (r *instanceResource) Update(
} }
// Map response body to schema // Map response body to schema
err = mapResponseToModel(ctx, waitResp, &model, resp.Diagnostics) err = mapFields(ctx, waitResp, &model, resp.Diagnostics)
// err = mapFields(ctx, waitResp, &model, storage, encryption, network, region) // err = mapFields(ctx, waitResp, &model, storage, encryption, network, region)
if err != nil { if err != nil {
core.LogAndAddError( core.LogAndAddError(
@ -709,7 +470,7 @@ func (r *instanceResource) Delete(
resp *resource.DeleteResponse, resp *resource.DeleteResponse,
) { // nolint:gocritic // function signature required by Terraform ) { // nolint:gocritic // function signature required by Terraform
// Retrieve values from state // Retrieve values from state
var model sqlserverflexalpha2.InstanceModel var model resourceModel
diags := req.State.Get(ctx, &model) diags := req.State.Get(ctx, &model)
resp.Diagnostics.Append(diags...) resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() { if resp.Diagnostics.HasError() {

View file

@ -28,7 +28,12 @@ var (
_ datasource.DataSource = &userDataSource{} _ datasource.DataSource = &userDataSource{}
) )
type DataSourceModel struct { // NewUserDataSource is a helper function to simplify the provider implementation.
func NewUserDataSource() datasource.DataSource {
return &userDataSource{}
}
type dataSourceModel struct {
Id types.String `tfsdk:"id"` // needed by TF Id types.String `tfsdk:"id"` // needed by TF
UserId types.Int64 `tfsdk:"user_id"` UserId types.Int64 `tfsdk:"user_id"`
InstanceId types.String `tfsdk:"instance_id"` InstanceId types.String `tfsdk:"instance_id"`
@ -42,11 +47,6 @@ type DataSourceModel struct {
DefaultDatabase types.String `tfsdk:"default_database"` DefaultDatabase types.String `tfsdk:"default_database"`
} }
// NewUserDataSource is a helper function to simplify the provider implementation.
func NewUserDataSource() datasource.DataSource {
return &userDataSource{}
}
// userDataSource is the data source implementation. // userDataSource is the data source implementation.
type userDataSource struct { type userDataSource struct {
client *sqlserverflexalpha.APIClient client *sqlserverflexalpha.APIClient
@ -164,7 +164,7 @@ func (r *userDataSource) Read(
req datasource.ReadRequest, req datasource.ReadRequest,
resp *datasource.ReadResponse, resp *datasource.ReadResponse,
) { // nolint:gocritic // function signature required by Terraform ) { // nolint:gocritic // function signature required by Terraform
var model DataSourceModel var model dataSourceModel
diags := req.Config.Get(ctx, &model) diags := req.Config.Get(ctx, &model)
resp.Diagnostics.Append(diags...) resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() { if resp.Diagnostics.HasError() {
@ -226,7 +226,7 @@ func (r *userDataSource) Read(
tflog.Info(ctx, "SQLServer Flex instance read") tflog.Info(ctx, "SQLServer Flex instance read")
} }
func mapDataSourceFields(userResp *sqlserverflexalpha.GetUserResponse, model *DataSourceModel, region string) error { func mapDataSourceFields(userResp *sqlserverflexalpha.GetUserResponse, model *dataSourceModel, region string) error {
if userResp == nil { if userResp == nil {
return fmt.Errorf("response is nil") return fmt.Errorf("response is nil")
} }

View file

@ -16,14 +16,14 @@ func TestMapDataSourceFields(t *testing.T) {
description string description string
input *sqlserverflexalpha.GetUserResponse input *sqlserverflexalpha.GetUserResponse
region string region string
expected DataSourceModel expected dataSourceModel
isValid bool isValid bool
}{ }{
{ {
"default_values", "default_values",
&sqlserverflexalpha.GetUserResponse{}, &sqlserverflexalpha.GetUserResponse{},
testRegion, testRegion,
DataSourceModel{ dataSourceModel{
Id: types.StringValue("pid,region,iid,1"), Id: types.StringValue("pid,region,iid,1"),
UserId: types.Int64Value(1), UserId: types.Int64Value(1),
InstanceId: types.StringValue("iid"), InstanceId: types.StringValue("iid"),
@ -54,7 +54,7 @@ func TestMapDataSourceFields(t *testing.T) {
DefaultDatabase: utils.Ptr("default_db"), DefaultDatabase: utils.Ptr("default_db"),
}, },
testRegion, testRegion,
DataSourceModel{ dataSourceModel{
Id: types.StringValue("pid,region,iid,1"), Id: types.StringValue("pid,region,iid,1"),
UserId: types.Int64Value(1), UserId: types.Int64Value(1),
InstanceId: types.StringValue("iid"), InstanceId: types.StringValue("iid"),
@ -85,7 +85,7 @@ func TestMapDataSourceFields(t *testing.T) {
Port: utils.Ptr(int64(2123456789)), Port: utils.Ptr(int64(2123456789)),
}, },
testRegion, testRegion,
DataSourceModel{ dataSourceModel{
Id: types.StringValue("pid,region,iid,1"), Id: types.StringValue("pid,region,iid,1"),
UserId: types.Int64Value(1), UserId: types.Int64Value(1),
InstanceId: types.StringValue("iid"), InstanceId: types.StringValue("iid"),
@ -102,28 +102,28 @@ func TestMapDataSourceFields(t *testing.T) {
"nil_response", "nil_response",
nil, nil,
testRegion, testRegion,
DataSourceModel{}, dataSourceModel{},
false, false,
}, },
{ {
"nil_response_2", "nil_response_2",
&sqlserverflexalpha.GetUserResponse{}, &sqlserverflexalpha.GetUserResponse{},
testRegion, testRegion,
DataSourceModel{}, dataSourceModel{},
false, false,
}, },
{ {
"no_resource_id", "no_resource_id",
&sqlserverflexalpha.GetUserResponse{}, &sqlserverflexalpha.GetUserResponse{},
testRegion, testRegion,
DataSourceModel{}, dataSourceModel{},
false, false,
}, },
} }
for _, tt := range tests { for _, tt := range tests {
t.Run( t.Run(
tt.description, func(t *testing.T) { tt.description, func(t *testing.T) {
state := &DataSourceModel{ state := &dataSourceModel{
ProjectId: tt.expected.ProjectId, ProjectId: tt.expected.ProjectId,
InstanceId: tt.expected.InstanceId, InstanceId: tt.expected.InstanceId,
UserId: tt.expected.UserId, UserId: tt.expected.UserId,

View file

@ -5,11 +5,11 @@ import (
"errors" "errors"
"fmt" "fmt"
"net/http" "net/http"
"strconv"
"strings" "strings"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/int64planmodifier" "github.com/hashicorp/terraform-plugin-framework/resource/schema/int64planmodifier"
"tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/pkg_gen/sqlserverflexalpha" "tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/pkg_gen/sqlserverflexalpha"
sqlserverflexalphagen "tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit/internal/services/sqlserverflexalpha/user/resources_gen"
sqlserverflexalphaUtils "tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit/internal/services/sqlserverflexalpha/utils" sqlserverflexalphaUtils "tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit/internal/services/sqlserverflexalpha/utils"
sqlserverflexalphaWait "tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit/internal/wait/sqlserverflexalpha" sqlserverflexalphaWait "tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit/internal/wait/sqlserverflexalpha"
@ -39,26 +39,14 @@ var (
_ resource.ResourceWithModifyPlan = &userResource{} _ resource.ResourceWithModifyPlan = &userResource{}
) )
type Model struct {
Id types.String `tfsdk:"id"` // needed by TF
UserId types.Int64 `tfsdk:"user_id"`
InstanceId types.String `tfsdk:"instance_id"`
ProjectId types.String `tfsdk:"project_id"`
Username types.String `tfsdk:"username"`
Roles types.Set `tfsdk:"roles"`
Password types.String `tfsdk:"password"`
Host types.String `tfsdk:"host"`
Port types.Int64 `tfsdk:"port"`
Region types.String `tfsdk:"region"`
Status types.String `tfsdk:"status"`
DefaultDatabase types.String `tfsdk:"default_database"`
}
// NewUserResource is a helper function to simplify the provider implementation. // NewUserResource is a helper function to simplify the provider implementation.
func NewUserResource() resource.Resource { func NewUserResource() resource.Resource {
return &userResource{} return &userResource{}
} }
// resourceModel describes the resource data model.
type resourceModel = sqlserverflexalphagen.UserModel
// userResource is the resource implementation. // userResource is the resource implementation.
type userResource struct { type userResource struct {
client *sqlserverflexalpha.APIClient client *sqlserverflexalpha.APIClient
@ -93,7 +81,7 @@ func (r *userResource) ModifyPlan(
req resource.ModifyPlanRequest, req resource.ModifyPlanRequest,
resp *resource.ModifyPlanResponse, resp *resource.ModifyPlanResponse,
) { // nolint:gocritic // function signature required by Terraform ) { // nolint:gocritic // function signature required by Terraform
var configModel Model var configModel resourceModel
// skip initial empty configuration to avoid follow-up errors // skip initial empty configuration to avoid follow-up errors
if req.Config.Raw.IsNull() { if req.Config.Raw.IsNull() {
return return
@ -103,7 +91,7 @@ func (r *userResource) ModifyPlan(
return return
} }
var planModel Model var planModel resourceModel
resp.Diagnostics.Append(req.Plan.Get(ctx, &planModel)...) resp.Diagnostics.Append(req.Plan.Get(ctx, &planModel)...)
if resp.Diagnostics.HasError() { if resp.Diagnostics.HasError() {
return return
@ -229,7 +217,7 @@ func (r *userResource) Create(
req resource.CreateRequest, req resource.CreateRequest,
resp *resource.CreateResponse, resp *resource.CreateResponse,
) { // nolint:gocritic // function signature required by Terraform ) { // nolint:gocritic // function signature required by Terraform
var model Model var model resourceModel
diags := req.Plan.Get(ctx, &model) diags := req.Plan.Get(ctx, &model)
resp.Diagnostics.Append(diags...) resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() { if resp.Diagnostics.HasError() {
@ -313,7 +301,7 @@ func (r *userResource) Read(
req resource.ReadRequest, req resource.ReadRequest,
resp *resource.ReadResponse, resp *resource.ReadResponse,
) { // nolint:gocritic // function signature required by Terraform ) { // nolint:gocritic // function signature required by Terraform
var model Model var model resourceModel
diags := req.State.Get(ctx, &model) diags := req.State.Get(ctx, &model)
resp.Diagnostics.Append(diags...) resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() { if resp.Diagnostics.HasError() {
@ -387,7 +375,7 @@ func (r *userResource) Delete(
resp *resource.DeleteResponse, resp *resource.DeleteResponse,
) { // nolint:gocritic // function signature required by Terraform ) { // nolint:gocritic // function signature required by Terraform
// Retrieve values from plan // Retrieve values from plan
var model Model var model resourceModel
diags := req.State.Get(ctx, &model) diags := req.State.Get(ctx, &model)
resp.Diagnostics.Append(diags...) resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() { if resp.Diagnostics.HasError() {
@ -455,7 +443,7 @@ func (r *userResource) ImportState(
tflog.Info(ctx, "SQLServer Flex user state imported") tflog.Info(ctx, "SQLServer Flex user state imported")
} }
func mapFieldsCreate(userResp *sqlserverflexalpha.CreateUserResponse, model *Model, region string) error { func mapFieldsCreate(userResp *sqlserverflexalpha.CreateUserResponse, model *resourceModel, region string) error {
if userResp == nil { if userResp == nil {
return fmt.Errorf("response is nil") return fmt.Errorf("response is nil")
} }
@ -468,12 +456,6 @@ func mapFieldsCreate(userResp *sqlserverflexalpha.CreateUserResponse, model *Mod
return fmt.Errorf("user id not present") return fmt.Errorf("user id not present")
} }
userId := *user.Id userId := *user.Id
model.Id = utils.BuildInternalTerraformId(
model.ProjectId.ValueString(),
region,
model.InstanceId.ValueString(),
strconv.FormatInt(userId, 10),
)
model.UserId = types.Int64Value(userId) model.UserId = types.Int64Value(userId)
model.Username = types.StringPointerValue(user.Username) model.Username = types.StringPointerValue(user.Username)
@ -491,11 +473,11 @@ func mapFieldsCreate(userResp *sqlserverflexalpha.CreateUserResponse, model *Mod
if diags.HasError() { if diags.HasError() {
return fmt.Errorf("failed to map roles: %w", core.DiagsToError(diags)) return fmt.Errorf("failed to map roles: %w", core.DiagsToError(diags))
} }
model.Roles = rolesSet model.Roles = types.List(rolesSet)
} }
if model.Roles.IsNull() || model.Roles.IsUnknown() { if model.Roles.IsNull() || model.Roles.IsUnknown() {
model.Roles = types.SetNull(types.StringType) model.Roles = types.List(types.SetNull(types.StringType))
} }
model.Host = types.StringPointerValue(user.Host) model.Host = types.StringPointerValue(user.Host)
@ -507,7 +489,7 @@ func mapFieldsCreate(userResp *sqlserverflexalpha.CreateUserResponse, model *Mod
return nil return nil
} }
func mapFields(userResp *sqlserverflexalpha.GetUserResponse, model *Model, region string) error { func mapFields(userResp *sqlserverflexalpha.GetUserResponse, model *resourceModel, region string) error {
if userResp == nil { if userResp == nil {
return fmt.Errorf("response is nil") return fmt.Errorf("response is nil")
} }
@ -524,12 +506,7 @@ func mapFields(userResp *sqlserverflexalpha.GetUserResponse, model *Model, regio
} else { } else {
return fmt.Errorf("user id not present") return fmt.Errorf("user id not present")
} }
model.Id = utils.BuildInternalTerraformId(
model.ProjectId.ValueString(),
region,
model.InstanceId.ValueString(),
strconv.FormatInt(userId, 10),
)
model.UserId = types.Int64Value(userId) model.UserId = types.Int64Value(userId)
model.Username = types.StringPointerValue(user.Username) model.Username = types.StringPointerValue(user.Username)
@ -542,11 +519,11 @@ func mapFields(userResp *sqlserverflexalpha.GetUserResponse, model *Model, regio
if diags.HasError() { if diags.HasError() {
return fmt.Errorf("failed to map roles: %w", core.DiagsToError(diags)) return fmt.Errorf("failed to map roles: %w", core.DiagsToError(diags))
} }
model.Roles = rolesSet model.Roles = types.List(rolesSet)
} }
if model.Roles.IsNull() || model.Roles.IsUnknown() { if model.Roles.IsNull() || model.Roles.IsUnknown() {
model.Roles = types.SetNull(types.StringType) model.Roles = types.List(types.SetNull(types.StringType))
} }
model.Host = types.StringPointerValue(user.Host) model.Host = types.StringPointerValue(user.Host)
@ -556,7 +533,7 @@ func mapFields(userResp *sqlserverflexalpha.GetUserResponse, model *Model, regio
} }
func toCreatePayload( func toCreatePayload(
model *Model, model *resourceModel,
roles []sqlserverflexalpha.UserRole, roles []sqlserverflexalpha.UserRole,
) (*sqlserverflexalpha.CreateUserRequestPayload, error) { ) (*sqlserverflexalpha.CreateUserRequestPayload, error) {
if model == nil { if model == nil {

View file

@ -16,7 +16,7 @@ func TestMapFieldsCreate(t *testing.T) {
description string description string
input *sqlserverflexalpha.CreateUserResponse input *sqlserverflexalpha.CreateUserResponse
region string region string
expected Model expected resourceModel
isValid bool isValid bool
}{ }{
{ {
@ -26,13 +26,13 @@ func TestMapFieldsCreate(t *testing.T) {
Password: utils.Ptr(""), Password: utils.Ptr(""),
}, },
testRegion, testRegion,
Model{ resourceModel{
Id: types.StringValue("pid,region,iid,1"), Id: types.Int64Value(1),
UserId: types.Int64Value(1), UserId: types.Int64Value(1),
InstanceId: types.StringValue("iid"), InstanceId: types.StringValue("iid"),
ProjectId: types.StringValue("pid"), ProjectId: types.StringValue("pid"),
Username: types.StringNull(), Username: types.StringNull(),
Roles: types.SetNull(types.StringType), Roles: types.List(types.SetNull(types.StringType)),
Password: types.StringValue(""), Password: types.StringValue(""),
Host: types.StringNull(), Host: types.StringNull(),
Port: types.Int64Null(), Port: types.Int64Null(),
@ -57,18 +57,20 @@ func TestMapFieldsCreate(t *testing.T) {
DefaultDatabase: utils.Ptr("default_db"), DefaultDatabase: utils.Ptr("default_db"),
}, },
testRegion, testRegion,
Model{ resourceModel{
Id: types.StringValue("pid,region,iid,2"), Id: types.Int64Value(2),
UserId: types.Int64Value(2), UserId: types.Int64Value(2),
InstanceId: types.StringValue("iid"), InstanceId: types.StringValue("iid"),
ProjectId: types.StringValue("pid"), ProjectId: types.StringValue("pid"),
Username: types.StringValue("username"), Username: types.StringValue("username"),
Roles: types.SetValueMust( Roles: types.List(
types.StringType, []attr.Value{ types.SetValueMust(
types.StringValue("role_1"), types.StringType, []attr.Value{
types.StringValue("role_2"), types.StringValue("role_1"),
types.StringValue(""), types.StringValue("role_2"),
}, types.StringValue(""),
},
),
), ),
Password: types.StringValue("password"), Password: types.StringValue("password"),
Host: types.StringValue("host"), Host: types.StringValue("host"),
@ -90,13 +92,13 @@ func TestMapFieldsCreate(t *testing.T) {
Port: utils.Ptr(int64(2123456789)), Port: utils.Ptr(int64(2123456789)),
}, },
testRegion, testRegion,
Model{ resourceModel{
Id: types.StringValue("pid,region,iid,3"), Id: types.Int64Value(3),
UserId: types.Int64Value(3), UserId: types.Int64Value(3),
InstanceId: types.StringValue("iid"), InstanceId: types.StringValue("iid"),
ProjectId: types.StringValue("pid"), ProjectId: types.StringValue("pid"),
Username: types.StringNull(), Username: types.StringNull(),
Roles: types.SetValueMust(types.StringType, []attr.Value{}), Roles: types.List(types.SetValueMust(types.StringType, []attr.Value{})),
Password: types.StringValue(""), Password: types.StringValue(""),
Host: types.StringNull(), Host: types.StringNull(),
Port: types.Int64Value(2123456789), Port: types.Int64Value(2123456789),
@ -110,21 +112,21 @@ func TestMapFieldsCreate(t *testing.T) {
"nil_response", "nil_response",
nil, nil,
testRegion, testRegion,
Model{}, resourceModel{},
false, false,
}, },
{ {
"nil_response_2", "nil_response_2",
&sqlserverflexalpha.CreateUserResponse{}, &sqlserverflexalpha.CreateUserResponse{},
testRegion, testRegion,
Model{}, resourceModel{},
false, false,
}, },
{ {
"no_resource_id", "no_resource_id",
&sqlserverflexalpha.CreateUserResponse{}, &sqlserverflexalpha.CreateUserResponse{},
testRegion, testRegion,
Model{}, resourceModel{},
false, false,
}, },
{ {
@ -133,14 +135,14 @@ func TestMapFieldsCreate(t *testing.T) {
Id: utils.Ptr(int64(1)), Id: utils.Ptr(int64(1)),
}, },
testRegion, testRegion,
Model{}, resourceModel{},
false, false,
}, },
} }
for _, tt := range tests { for _, tt := range tests {
t.Run( t.Run(
tt.description, func(t *testing.T) { tt.description, func(t *testing.T) {
state := &Model{ state := &resourceModel{
ProjectId: tt.expected.ProjectId, ProjectId: tt.expected.ProjectId,
InstanceId: tt.expected.InstanceId, InstanceId: tt.expected.InstanceId,
} }
@ -168,20 +170,20 @@ func TestMapFields(t *testing.T) {
description string description string
input *sqlserverflexalpha.GetUserResponse input *sqlserverflexalpha.GetUserResponse
region string region string
expected Model expected resourceModel
isValid bool isValid bool
}{ }{
{ {
"default_values", "default_values",
&sqlserverflexalpha.GetUserResponse{}, &sqlserverflexalpha.GetUserResponse{},
testRegion, testRegion,
Model{ resourceModel{
Id: types.StringValue("pid,region,iid,1"), Id: types.Int64Value(1),
UserId: types.Int64Value(1), UserId: types.Int64Value(1),
InstanceId: types.StringValue("iid"), InstanceId: types.StringValue("iid"),
ProjectId: types.StringValue("pid"), ProjectId: types.StringValue("pid"),
Username: types.StringNull(), Username: types.StringNull(),
Roles: types.SetNull(types.StringType), Roles: types.List(types.SetNull(types.StringType)),
Host: types.StringNull(), Host: types.StringNull(),
Port: types.Int64Null(), Port: types.Int64Null(),
Region: types.StringValue(testRegion), Region: types.StringValue(testRegion),
@ -201,18 +203,20 @@ func TestMapFields(t *testing.T) {
Port: utils.Ptr(int64(1234)), Port: utils.Ptr(int64(1234)),
}, },
testRegion, testRegion,
Model{ resourceModel{
Id: types.StringValue("pid,region,iid,2"), Id: types.Int64Value(2),
UserId: types.Int64Value(2), UserId: types.Int64Value(2),
InstanceId: types.StringValue("iid"), InstanceId: types.StringValue("iid"),
ProjectId: types.StringValue("pid"), ProjectId: types.StringValue("pid"),
Username: types.StringValue("username"), Username: types.StringValue("username"),
Roles: types.SetValueMust( Roles: types.List(
types.StringType, []attr.Value{ types.SetValueMust(
types.StringValue("role_1"), types.StringType, []attr.Value{
types.StringValue("role_2"), types.StringValue("role_1"),
types.StringValue(""), types.StringValue("role_2"),
}, types.StringValue(""),
},
),
), ),
Host: types.StringValue("host"), Host: types.StringValue("host"),
Port: types.Int64Value(1234), Port: types.Int64Value(1234),
@ -230,13 +234,13 @@ func TestMapFields(t *testing.T) {
Port: utils.Ptr(int64(2123456789)), Port: utils.Ptr(int64(2123456789)),
}, },
testRegion, testRegion,
Model{ resourceModel{
Id: types.StringValue("pid,region,iid,1"), Id: types.Int64Value(1),
UserId: types.Int64Value(1), UserId: types.Int64Value(1),
InstanceId: types.StringValue("iid"), InstanceId: types.StringValue("iid"),
ProjectId: types.StringValue("pid"), ProjectId: types.StringValue("pid"),
Username: types.StringNull(), Username: types.StringNull(),
Roles: types.SetValueMust(types.StringType, []attr.Value{}), Roles: types.List(types.SetValueMust(types.StringType, []attr.Value{})),
Host: types.StringNull(), Host: types.StringNull(),
Port: types.Int64Value(2123456789), Port: types.Int64Value(2123456789),
Region: types.StringValue(testRegion), Region: types.StringValue(testRegion),
@ -247,28 +251,28 @@ func TestMapFields(t *testing.T) {
"nil_response", "nil_response",
nil, nil,
testRegion, testRegion,
Model{}, resourceModel{},
false, false,
}, },
{ {
"nil_response_2", "nil_response_2",
&sqlserverflexalpha.GetUserResponse{}, &sqlserverflexalpha.GetUserResponse{},
testRegion, testRegion,
Model{}, resourceModel{},
false, false,
}, },
{ {
"no_resource_id", "no_resource_id",
&sqlserverflexalpha.GetUserResponse{}, &sqlserverflexalpha.GetUserResponse{},
testRegion, testRegion,
Model{}, resourceModel{},
false, false,
}, },
} }
for _, tt := range tests { for _, tt := range tests {
t.Run( t.Run(
tt.description, func(t *testing.T) { tt.description, func(t *testing.T) {
state := &Model{ state := &resourceModel{
ProjectId: tt.expected.ProjectId, ProjectId: tt.expected.ProjectId,
InstanceId: tt.expected.InstanceId, InstanceId: tt.expected.InstanceId,
UserId: tt.expected.UserId, UserId: tt.expected.UserId,
@ -294,14 +298,14 @@ func TestMapFields(t *testing.T) {
func TestToCreatePayload(t *testing.T) { func TestToCreatePayload(t *testing.T) {
tests := []struct { tests := []struct {
description string description string
input *Model input *resourceModel
inputRoles []sqlserverflexalpha.UserRole inputRoles []sqlserverflexalpha.UserRole
expected *sqlserverflexalpha.CreateUserRequestPayload expected *sqlserverflexalpha.CreateUserRequestPayload
isValid bool isValid bool
}{ }{
{ {
"default_values", "default_values",
&Model{}, &resourceModel{},
[]sqlserverflexalpha.UserRole{}, []sqlserverflexalpha.UserRole{},
&sqlserverflexalpha.CreateUserRequestPayload{ &sqlserverflexalpha.CreateUserRequestPayload{
Roles: &[]sqlserverflexalpha.UserRole{}, Roles: &[]sqlserverflexalpha.UserRole{},
@ -311,7 +315,7 @@ func TestToCreatePayload(t *testing.T) {
}, },
{ {
"default_values", "default_values",
&Model{ &resourceModel{
Username: types.StringValue("username"), Username: types.StringValue("username"),
}, },
[]sqlserverflexalpha.UserRole{ []sqlserverflexalpha.UserRole{
@ -329,7 +333,7 @@ func TestToCreatePayload(t *testing.T) {
}, },
{ {
"null_fields_and_int_conversions", "null_fields_and_int_conversions",
&Model{ &resourceModel{
Username: types.StringNull(), Username: types.StringNull(),
}, },
[]sqlserverflexalpha.UserRole{ []sqlserverflexalpha.UserRole{
@ -352,7 +356,7 @@ func TestToCreatePayload(t *testing.T) {
}, },
{ {
"nil_roles", "nil_roles",
&Model{ &resourceModel{
Username: types.StringValue("username"), Username: types.StringValue("username"),
}, },
[]sqlserverflexalpha.UserRole{}, []sqlserverflexalpha.UserRole{},

View file

@ -26,17 +26,21 @@ func NewDatabaseDataSource() datasource.DataSource {
return &databaseDataSource{} return &databaseDataSource{}
} }
type dataSourceModel struct {
sqlserverflexbetaGen.DatabaseModel
TfId types.String `tfsdk:"id"`
}
type databaseDataSource struct { type databaseDataSource struct {
client *sqlserverflexbetaPkg.APIClient client *sqlserverflexbetaPkg.APIClient
providerData core.ProviderData providerData core.ProviderData
} }
type dsModel struct { func (d *databaseDataSource) Metadata(
sqlserverflexbetaGen.DatabaseModel _ context.Context,
TfId types.String `tfsdk:"id"` req datasource.MetadataRequest,
} resp *datasource.MetadataResponse,
) {
func (d *databaseDataSource) Metadata(_ context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) {
resp.TypeName = req.ProviderTypeName + "_sqlserverflexbeta_database" resp.TypeName = req.ProviderTypeName + "_sqlserverflexbeta_database"
} }
@ -92,7 +96,7 @@ func (d *databaseDataSource) Configure(
} }
func (d *databaseDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { func (d *databaseDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) {
var data dsModel var data dataSourceModel
readErr := "Read DB error" readErr := "Read DB error"
// Read Terraform configuration data into the model // Read Terraform configuration data into the model

View file

@ -35,6 +35,9 @@ func NewDatabaseResource() resource.Resource {
return &databaseResource{} return &databaseResource{}
} }
// resourceModel describes the resource data model.
type resourceModel = sqlserverflexbetaResGen.DatabaseModel
type databaseResource struct { type databaseResource struct {
client *sqlserverflexbeta.APIClient client *sqlserverflexbeta.APIClient
providerData core.ProviderData providerData core.ProviderData
@ -47,7 +50,11 @@ type DatabaseResourceIdentityModel struct {
DatabaseName types.String `tfsdk:"database_name"` DatabaseName types.String `tfsdk:"database_name"`
} }
func (r *databaseResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { func (r *databaseResource) Metadata(
ctx context.Context,
req resource.MetadataRequest,
resp *resource.MetadataResponse,
) {
resp.TypeName = req.ProviderTypeName + "_sqlserverflexbeta_database" resp.TypeName = req.ProviderTypeName + "_sqlserverflexbeta_database"
} }
@ -55,7 +62,11 @@ func (r *databaseResource) Schema(ctx context.Context, req resource.SchemaReques
resp.Schema = sqlserverflexbetaResGen.DatabaseResourceSchema(ctx) resp.Schema = sqlserverflexbetaResGen.DatabaseResourceSchema(ctx)
} }
func (r *databaseResource) IdentitySchema(_ context.Context, _ resource.IdentitySchemaRequest, resp *resource.IdentitySchemaResponse) { func (r *databaseResource) IdentitySchema(
_ context.Context,
_ resource.IdentitySchemaRequest,
resp *resource.IdentitySchemaResponse,
) {
resp.IdentitySchema = identityschema.Schema{ resp.IdentitySchema = identityschema.Schema{
Attributes: map[string]identityschema.Attribute{ Attributes: map[string]identityschema.Attribute{
"project_id": identityschema.StringAttribute{ "project_id": identityschema.StringAttribute{
@ -91,7 +102,10 @@ func (r *databaseResource) Configure(
utils.UserAgentConfigOption(r.providerData.Version), utils.UserAgentConfigOption(r.providerData.Version),
} }
if r.providerData.SQLServerFlexCustomEndpoint != "" { if r.providerData.SQLServerFlexCustomEndpoint != "" {
apiClientConfigOptions = append(apiClientConfigOptions, config.WithEndpoint(r.providerData.SQLServerFlexCustomEndpoint)) apiClientConfigOptions = append(
apiClientConfigOptions,
config.WithEndpoint(r.providerData.SQLServerFlexCustomEndpoint),
)
} else { } else {
apiClientConfigOptions = append(apiClientConfigOptions, config.WithRegion(r.providerData.GetRegion())) apiClientConfigOptions = append(apiClientConfigOptions, config.WithRegion(r.providerData.GetRegion()))
} }
@ -111,7 +125,7 @@ func (r *databaseResource) Configure(
} }
func (r *databaseResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { func (r *databaseResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
var data sqlserverflexbetaResGen.DatabaseModel var data resourceModel
createErr := "DB create error" createErr := "DB create error"
// Read Terraform plan data into the model // Read Terraform plan data into the model
@ -243,7 +257,7 @@ func (r *databaseResource) Create(ctx context.Context, req resource.CreateReques
} }
func (r *databaseResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { func (r *databaseResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
var data sqlserverflexbetaResGen.DatabaseModel var data resourceModel
readErr := "[Database Read]" readErr := "[Database Read]"
// Read Terraform prior state data into the model // Read Terraform prior state data into the model
@ -298,7 +312,7 @@ func (r *databaseResource) Read(ctx context.Context, req resource.ReadRequest, r
} }
func (r *databaseResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { func (r *databaseResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
var data sqlserverflexbetaResGen.DatabaseModel var data resourceModel
// Read Terraform prior state data into the model // Read Terraform prior state data into the model
resp.Diagnostics.Append(req.State.Get(ctx, &data)...) resp.Diagnostics.Append(req.State.Get(ctx, &data)...)
@ -329,7 +343,7 @@ func (r *databaseResource) Update(ctx context.Context, req resource.UpdateReques
} }
func (r *databaseResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { func (r *databaseResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
var data sqlserverflexbetaResGen.DatabaseModel var data resourceModel
// Read Terraform prior state data into the model // Read Terraform prior state data into the model
resp.Diagnostics.Append(req.State.Get(ctx, &data)...) resp.Diagnostics.Append(req.State.Get(ctx, &data)...)
@ -422,9 +436,13 @@ func (r *databaseResource) ImportState(
idParts := strings.Split(req.ID, core.Separator) idParts := strings.Split(req.ID, core.Separator)
if len(idParts) != 4 || idParts[0] == "" || idParts[1] == "" || idParts[2] == "" || idParts[3] == "" { if len(idParts) != 4 || idParts[0] == "" || idParts[1] == "" || idParts[2] == "" || idParts[3] == "" {
core.LogAndAddError(ctx, &resp.Diagnostics, core.LogAndAddError(
ctx, &resp.Diagnostics,
"Error importing database", "Error importing database",
fmt.Sprintf("Expected import identifier with format: [project_id],[region],[instance_id],[database_name] Got: %q", req.ID), fmt.Sprintf(
"Expected import identifier with format: [project_id],[region],[instance_id],[database_name] Got: %q",
req.ID,
),
) )
return return
} }
@ -455,10 +473,28 @@ func (r *databaseResource) ImportState(
return return
} }
resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("project_id"), identityData.ProjectID.ValueString())...) resp.Diagnostics.Append(
resp.State.SetAttribute(
ctx,
path.Root("project_id"),
identityData.ProjectID.ValueString(),
)...,
)
resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("region"), identityData.Region.ValueString())...) resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("region"), identityData.Region.ValueString())...)
resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("instance_id"), identityData.InstanceID.ValueString())...) resp.Diagnostics.Append(
resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("database_name"), identityData.DatabaseName.ValueString())...) resp.State.SetAttribute(
ctx,
path.Root("instance_id"),
identityData.InstanceID.ValueString(),
)...,
)
resp.Diagnostics.Append(
resp.State.SetAttribute(
ctx,
path.Root("database_name"),
identityData.DatabaseName.ValueString(),
)...,
)
resp.Diagnostics.Append(resp.Identity.Set(ctx, &identityData)...) resp.Diagnostics.Append(resp.Identity.Set(ctx, &identityData)...)
if resp.Diagnostics.HasError() { if resp.Diagnostics.HasError() {

View file

@ -14,9 +14,9 @@ import (
"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/core"
"tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit/internal/utils" "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" 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/flavors/datasources_gen" sqlserverflexbetaGen "tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit/internal/services/sqlserverflexbeta/flavors/datasources_gen"
) )
var _ datasource.DataSource = (*flavorsDataSource)(nil) var _ datasource.DataSource = (*flavorsDataSource)(nil)
@ -27,27 +27,31 @@ func NewFlavorsDataSource() datasource.DataSource {
return &flavorsDataSource{} return &flavorsDataSource{}
} }
type dsModel struct { type dataSourceModel struct {
sqlserverflexbetaGen.FlavorsModel sqlserverflexbetaGen.FlavorsModel
TfId types.String `tfsdk:"id"` TerraformId types.String `tfsdk:"id"`
} }
type flavorsDataSource struct{ type flavorsDataSource struct {
client *sqlserverflexbetaPkg.APIClient client *sqlserverflexbetaPkg.APIClient
providerData core.ProviderData providerData core.ProviderData
} }
func (d *flavorsDataSource) Metadata(_ context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) { func (d *flavorsDataSource) Metadata(
_ context.Context,
req datasource.MetadataRequest,
resp *datasource.MetadataResponse,
) {
resp.TypeName = req.ProviderTypeName + "_sqlserverflexbeta_flavors" resp.TypeName = req.ProviderTypeName + "_sqlserverflexbeta_flavors"
} }
func (d *flavorsDataSource) Schema(ctx context.Context, _ datasource.SchemaRequest, resp *datasource.SchemaResponse) { func (d *flavorsDataSource) Schema(ctx context.Context, _ datasource.SchemaRequest, resp *datasource.SchemaResponse) {
resp.Schema = sqlserverflexbetaGen.FlavorsDataSourceSchema(ctx) resp.Schema = sqlserverflexbetaGen.FlavorsDataSourceSchema(ctx)
resp.Schema.Attributes["id"] = schema.StringAttribute{ resp.Schema.Attributes["id"] = schema.StringAttribute{
Computed: true, Computed: true,
Description: "The terraform internal identifier.", Description: "The terraform internal identifier.",
MarkdownDescription: "The terraform internal identifier.", MarkdownDescription: "The terraform internal identifier.",
} }
} }
// Configure adds the provider configured client to the data source. // Configure adds the provider configured client to the data source.
@ -66,10 +70,10 @@ func (d *flavorsDataSource) Configure(
config.WithCustomAuth(d.providerData.RoundTripper), config.WithCustomAuth(d.providerData.RoundTripper),
utils.UserAgentConfigOption(d.providerData.Version), utils.UserAgentConfigOption(d.providerData.Version),
} }
if d.providerData.SqlserverflexbetaCustomEndpoint != "" { if d.providerData.SQLServerFlexCustomEndpoint != "" {
apiClientConfigOptions = append( apiClientConfigOptions = append(
apiClientConfigOptions, apiClientConfigOptions,
config.WithEndpoint(d.providerData.SqlserverflexbetaCustomEndpoint), config.WithEndpoint(d.providerData.SQLServerFlexCustomEndpoint),
) )
} else { } else {
apiClientConfigOptions = append( apiClientConfigOptions = append(
@ -93,7 +97,7 @@ func (d *flavorsDataSource) Configure(
} }
func (d *flavorsDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { func (d *flavorsDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) {
var data dsModel var data dataSourceModel
// Read Terraform configuration data into the model // Read Terraform configuration data into the model
resp.Diagnostics.Append(req.Config.Get(ctx, &data)...) resp.Diagnostics.Append(req.Config.Get(ctx, &data)...)
@ -106,7 +110,8 @@ func (d *flavorsDataSource) Read(ctx context.Context, req datasource.ReadRequest
projectId := data.ProjectId.ValueString() projectId := data.ProjectId.ValueString()
region := d.providerData.GetRegionWithOverride(data.Region) region := d.providerData.GetRegionWithOverride(data.Region)
flavorsId := data.FlavorsId.ValueString() // TODO: implement right identifier for flavors
flavorsId := data.FlavorsModel.Flavors
ctx = tflog.SetField(ctx, "project_id", projectId) ctx = tflog.SetField(ctx, "project_id", projectId)
ctx = tflog.SetField(ctx, "region", region) ctx = tflog.SetField(ctx, "region", region)
@ -114,8 +119,8 @@ func (d *flavorsDataSource) Read(ctx context.Context, req datasource.ReadRequest
// TODO: implement needed fields // TODO: implement needed fields
ctx = tflog.SetField(ctx, "flavors_id", flavorsId) ctx = tflog.SetField(ctx, "flavors_id", flavorsId)
// TODO: refactor to correct implementation // TODO: refactor to correct implementation
flavorsResp, err := d.client.GetFlavorsRequest(ctx, projectId, region, flavorsId).Execute() _, err := d.client.GetFlavorsRequest(ctx, projectId, region).Execute()
if err != nil { if err != nil {
utils.LogError( utils.LogError(
ctx, ctx,
@ -133,17 +138,17 @@ func (d *flavorsDataSource) Read(ctx context.Context, req datasource.ReadRequest
ctx = core.LogResponse(ctx) ctx = core.LogResponse(ctx)
// TODO: refactor to correct implementation of internal tf id
data.TfId = utils.BuildInternalTerraformId(projectId, region, ..) data.TerraformId = utils.BuildInternalTerraformId(projectId, region)
// TODO: fill remaining fields // TODO: fill remaining fields
// data.Flavors = types.Sometype(apiResponse.GetFlavors()) // data.Flavors = types.Sometype(apiResponse.GetFlavors())
// data.Page = types.Sometype(apiResponse.GetPage()) // data.Page = types.Sometype(apiResponse.GetPage())
// data.Pagination = types.Sometype(apiResponse.GetPagination()) // data.Pagination = types.Sometype(apiResponse.GetPagination())
// data.ProjectId = types.Sometype(apiResponse.GetProjectId()) // data.ProjectId = types.Sometype(apiResponse.GetProjectId())
// data.Region = types.Sometype(apiResponse.GetRegion()) // data.Region = types.Sometype(apiResponse.GetRegion())
// data.Size = types.Sometype(apiResponse.GetSize()) // data.Size = types.Sometype(apiResponse.GetSize())
// data.Sort = types.Sometype(apiResponse.GetSort())// Save data into Terraform state // data.Sort = types.Sometype(apiResponse.GetSort())// Save data into Terraform state
resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
tflog.Info(ctx, fmt.Sprintf("%s read successful", errorPrefix)) tflog.Info(ctx, fmt.Sprintf("%s read successful", errorPrefix))

View file

@ -6,6 +6,7 @@ import (
"net/http" "net/http"
"github.com/hashicorp/terraform-plugin-framework/datasource" "github.com/hashicorp/terraform-plugin-framework/datasource"
"github.com/hashicorp/terraform-plugin-framework/types"
"github.com/hashicorp/terraform-plugin-log/tflog" "github.com/hashicorp/terraform-plugin-log/tflog"
"github.com/stackitcloud/stackit-sdk-go/core/config" "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/conversion"
@ -25,12 +26,22 @@ func NewInstanceDataSource() datasource.DataSource {
return &instanceDataSource{} return &instanceDataSource{}
} }
// dataSourceModel maps the data source schema data.
type dataSourceModel struct {
sqlserverflexbetaGen.InstanceModel
TerraformID types.String `tfsdk:"id"`
}
type instanceDataSource struct { type instanceDataSource struct {
client *sqlserverflexbetaPkg.APIClient client *sqlserverflexbetaPkg.APIClient
providerData core.ProviderData providerData core.ProviderData
} }
func (d *instanceDataSource) Metadata(_ context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) { func (d *instanceDataSource) Metadata(
_ context.Context,
req datasource.MetadataRequest,
resp *datasource.MetadataResponse,
) {
resp.TypeName = req.ProviderTypeName + "_sqlserverflexbeta_instance" resp.TypeName = req.ProviderTypeName + "_sqlserverflexbeta_instance"
} }
@ -81,7 +92,7 @@ func (d *instanceDataSource) Configure(
} }
func (d *instanceDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { func (d *instanceDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) {
var data sqlserverflexbetaGen.InstanceModel var data dataSourceModel
// Read Terraform configuration data into the model // Read Terraform configuration data into the model
resp.Diagnostics.Append(req.Config.Get(ctx, &data)...) resp.Diagnostics.Append(req.Config.Get(ctx, &data)...)

View file

@ -84,7 +84,7 @@ func mapResponseToModel(
func mapDataResponseToModel( func mapDataResponseToModel(
ctx context.Context, ctx context.Context,
resp *sqlserverflexbeta.GetInstanceResponse, resp *sqlserverflexbeta.GetInstanceResponse,
m *sqlserverflexbetaDataGen.InstanceModel, m *dataSourceModel,
tfDiags diag.Diagnostics, tfDiags diag.Diagnostics,
) error { ) error {
m.BackupSchedule = types.StringValue(resp.GetBackupSchedule()) m.BackupSchedule = types.StringValue(resp.GetBackupSchedule())
@ -181,7 +181,7 @@ func handleEncryption(
} }
func handleDSEncryption( func handleDSEncryption(
m *sqlserverflexbetaDataGen.InstanceModel, m *dataSourceModel,
resp *sqlserverflexbeta.GetInstanceResponse, resp *sqlserverflexbeta.GetInstanceResponse,
) sqlserverflexbetaDataGen.EncryptionValue { ) sqlserverflexbetaDataGen.EncryptionValue {
if !resp.HasEncryption() || if !resp.HasEncryption() ||

View file

@ -43,13 +43,20 @@ type instanceResource struct {
providerData core.ProviderData providerData core.ProviderData
} }
// resourceModel describes the resource data model.
type resourceModel = sqlserverflexbetaResGen.InstanceModel
type InstanceResourceIdentityModel struct { type InstanceResourceIdentityModel struct {
ProjectID types.String `tfsdk:"project_id"` ProjectID types.String `tfsdk:"project_id"`
Region types.String `tfsdk:"region"` Region types.String `tfsdk:"region"`
InstanceID types.String `tfsdk:"instance_id"` InstanceID types.String `tfsdk:"instance_id"`
} }
func (r *instanceResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { func (r *instanceResource) Metadata(
ctx context.Context,
req resource.MetadataRequest,
resp *resource.MetadataResponse,
) {
resp.TypeName = req.ProviderTypeName + "_sqlserverflexbeta_instance" resp.TypeName = req.ProviderTypeName + "_sqlserverflexbeta_instance"
} }
@ -57,7 +64,11 @@ func (r *instanceResource) Schema(ctx context.Context, req resource.SchemaReques
resp.Schema = sqlserverflexbetaResGen.InstanceResourceSchema(ctx) resp.Schema = sqlserverflexbetaResGen.InstanceResourceSchema(ctx)
} }
func (r *instanceResource) IdentitySchema(_ context.Context, _ resource.IdentitySchemaRequest, resp *resource.IdentitySchemaResponse) { func (r *instanceResource) IdentitySchema(
_ context.Context,
_ resource.IdentitySchemaRequest,
resp *resource.IdentitySchemaResponse,
) {
resp.IdentitySchema = identityschema.Schema{ resp.IdentitySchema = identityschema.Schema{
Attributes: map[string]identityschema.Attribute{ Attributes: map[string]identityschema.Attribute{
"project_id": identityschema.StringAttribute{ "project_id": identityschema.StringAttribute{
@ -90,7 +101,10 @@ func (r *instanceResource) Configure(
utils.UserAgentConfigOption(r.providerData.Version), utils.UserAgentConfigOption(r.providerData.Version),
} }
if r.providerData.SQLServerFlexCustomEndpoint != "" { if r.providerData.SQLServerFlexCustomEndpoint != "" {
apiClientConfigOptions = append(apiClientConfigOptions, config.WithEndpoint(r.providerData.SQLServerFlexCustomEndpoint)) apiClientConfigOptions = append(
apiClientConfigOptions,
config.WithEndpoint(r.providerData.SQLServerFlexCustomEndpoint),
)
} else { } else {
apiClientConfigOptions = append(apiClientConfigOptions, config.WithRegion(r.providerData.GetRegion())) apiClientConfigOptions = append(apiClientConfigOptions, config.WithRegion(r.providerData.GetRegion()))
} }
@ -121,7 +135,7 @@ func (r *instanceResource) ModifyPlan(
if req.Config.Raw.IsNull() { if req.Config.Raw.IsNull() {
return return
} }
var configModel sqlserverflexbetaResGen.InstanceModel var configModel resourceModel
resp.Diagnostics.Append(req.Config.Get(ctx, &configModel)...) resp.Diagnostics.Append(req.Config.Get(ctx, &configModel)...)
if resp.Diagnostics.HasError() { if resp.Diagnostics.HasError() {
return return
@ -151,7 +165,7 @@ func (r *instanceResource) ModifyPlan(
var modifiersFileByte []byte var modifiersFileByte []byte
func (r *instanceResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { func (r *instanceResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
var data sqlserverflexbetaResGen.InstanceModel var data resourceModel
crateErr := "[SQL Server Flex BETA - Create] error" crateErr := "[SQL Server Flex BETA - Create] error"
// Read Terraform plan data into the model // Read Terraform plan data into the model
@ -257,7 +271,7 @@ func (r *instanceResource) Create(ctx context.Context, req resource.CreateReques
} }
func (r *instanceResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { func (r *instanceResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
var data sqlserverflexbetaResGen.InstanceModel var data resourceModel
// Read Terraform prior state data into the model // Read Terraform prior state data into the model
resp.Diagnostics.Append(req.State.Get(ctx, &data)...) resp.Diagnostics.Append(req.State.Get(ctx, &data)...)
@ -324,7 +338,7 @@ func (r *instanceResource) Read(ctx context.Context, req resource.ReadRequest, r
} }
func (r *instanceResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { func (r *instanceResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
var data sqlserverflexbetaResGen.InstanceModel var data resourceModel
updateInstanceError := "Error updating instance" updateInstanceError := "Error updating instance"
resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...) resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...)
@ -411,7 +425,7 @@ func (r *instanceResource) Update(ctx context.Context, req resource.UpdateReques
} }
func (r *instanceResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { func (r *instanceResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
var data sqlserverflexbetaResGen.InstanceModel var data resourceModel
// Read Terraform prior state data into the model // Read Terraform prior state data into the model
resp.Diagnostics.Append(req.State.Get(ctx, &data)...) resp.Diagnostics.Append(req.State.Get(ctx, &data)...)
@ -484,9 +498,13 @@ func (r *instanceResource) ImportState(
idParts := strings.Split(req.ID, core.Separator) idParts := strings.Split(req.ID, core.Separator)
if len(idParts) != 3 || idParts[0] == "" || idParts[1] == "" || idParts[2] == "" { if len(idParts) != 3 || idParts[0] == "" || idParts[1] == "" || idParts[2] == "" {
core.LogAndAddError(ctx, &resp.Diagnostics, core.LogAndAddError(
ctx, &resp.Diagnostics,
"Error importing instance", "Error importing instance",
fmt.Sprintf("Expected import identifier with format: [project_id],[region],[instance_id] Got: %q", req.ID), fmt.Sprintf(
"Expected import identifier with format: [project_id],[region],[instance_id] Got: %q",
req.ID,
),
) )
return return
} }
@ -512,10 +530,23 @@ func (r *instanceResource) ImportState(
identityData.Region.ValueString(), identityData.Region.ValueString(),
identityData.InstanceID.ValueString(), identityData.InstanceID.ValueString(),
), ),
)...) )...,
resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("project_id"), identityData.ProjectID.ValueString())...) )
resp.Diagnostics.Append(
resp.State.SetAttribute(
ctx,
path.Root("project_id"),
identityData.ProjectID.ValueString(),
)...,
)
resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("region"), identityData.Region.ValueString())...) resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("region"), identityData.Region.ValueString())...)
resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("instance_id"), identityData.InstanceID.ValueString())...) resp.Diagnostics.Append(
resp.State.SetAttribute(
ctx,
path.Root("instance_id"),
identityData.InstanceID.ValueString(),
)...,
)
tflog.Info(ctx, "Sqlserverflexbeta instance state imported") tflog.Info(ctx, "Sqlserverflexbeta instance state imported")
} }

View file

@ -6,6 +6,7 @@ import (
"net/http" "net/http"
"github.com/hashicorp/terraform-plugin-framework/datasource" "github.com/hashicorp/terraform-plugin-framework/datasource"
"github.com/hashicorp/terraform-plugin-framework/types"
"github.com/hashicorp/terraform-plugin-log/tflog" "github.com/hashicorp/terraform-plugin-log/tflog"
"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/core"
"tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit/internal/utils" "tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit/internal/utils"
@ -25,12 +26,30 @@ func NewUserDataSource() datasource.DataSource {
return &userDataSource{} return &userDataSource{}
} }
type dataSourceModel struct {
DefaultDatabase types.String `tfsdk:"default_database"`
Host types.String `tfsdk:"host"`
Id types.Int64 `tfsdk:"id"`
InstanceId types.String `tfsdk:"instance_id"`
Port types.Int64 `tfsdk:"port"`
ProjectId types.String `tfsdk:"project_id"`
Region types.String `tfsdk:"region"`
Roles types.List `tfsdk:"roles"`
Status types.String `tfsdk:"status"`
UserId types.Int64 `tfsdk:"user_id"`
Username types.String `tfsdk:"username"`
}
type userDataSource struct { type userDataSource struct {
client *sqlserverflexbetaPkg.APIClient client *sqlserverflexbetaPkg.APIClient
providerData core.ProviderData providerData core.ProviderData
} }
func (d *userDataSource) Metadata(_ context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) { func (d *userDataSource) Metadata(
_ context.Context,
req datasource.MetadataRequest,
resp *datasource.MetadataResponse,
) {
resp.TypeName = req.ProviderTypeName + "_sqlserverflexbeta_user" resp.TypeName = req.ProviderTypeName + "_sqlserverflexbeta_user"
} }
@ -59,7 +78,7 @@ func (d *userDataSource) Configure(
} }
func (d *userDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { func (d *userDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) {
var data sqlserverflexbetaGen.UserModel var data dataSourceModel
// Read Terraform configuration data into the model // Read Terraform configuration data into the model
resp.Diagnostics.Append(req.Config.Get(ctx, &data)...) resp.Diagnostics.Append(req.Config.Get(ctx, &data)...)
@ -72,13 +91,15 @@ func (d *userDataSource) Read(ctx context.Context, req datasource.ReadRequest, r
projectId := data.ProjectId.ValueString() projectId := data.ProjectId.ValueString()
region := d.providerData.GetRegionWithOverride(data.Region) region := d.providerData.GetRegionWithOverride(data.Region)
userId := data.UserId.ValueString() instanceId := data.InstanceId.ValueString()
userId := data.UserId.ValueInt64()
ctx = tflog.SetField(ctx, "project_id", projectId) ctx = tflog.SetField(ctx, "project_id", projectId)
ctx = tflog.SetField(ctx, "region", region) ctx = tflog.SetField(ctx, "region", region)
ctx = tflog.SetField(ctx, "instance_id", instanceId)
ctx = tflog.SetField(ctx, "user_id", userId) ctx = tflog.SetField(ctx, "user_id", userId)
userResp, err := d.client.GetUserRequest(ctx, projectId, region, userId).Execute() userResp, err := d.client.GetUserRequest(ctx, projectId, region, instanceId, userId).Execute()
if err != nil { if err != nil {
utils.LogError( utils.LogError(
ctx, ctx,

View file

@ -3,13 +3,9 @@ package sqlserverflexbeta
import ( import (
"context" "context"
"fmt" "fmt"
"math"
"github.com/hashicorp/terraform-plugin-framework/attr"
"github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/diag"
"github.com/hashicorp/terraform-plugin-framework/resource"
"github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-plugin-framework/types"
"tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit/internal/conversion"
sqlserverflexbeta "tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/pkg_gen/sqlserverflexbeta" sqlserverflexbeta "tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/pkg_gen/sqlserverflexbeta"
sqlserverflexbetaResGen "tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit/internal/services/sqlserverflexbeta/instance/resources_gen" sqlserverflexbetaResGen "tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit/internal/services/sqlserverflexbeta/instance/resources_gen"
@ -18,11 +14,39 @@ import (
func mapResponseToModel( func mapResponseToModel(
ctx context.Context, ctx context.Context,
resp *sqlserverflexbeta.GetUserResponse, resp *sqlserverflexbeta.GetUserResponse,
m *sqlserverflexbetaResGen.UserModel, m *dataSourceModel,
tfDiags diag.Diagnostics, tfDiags diag.Diagnostics,
) error { ) error {
if resp == nil {
return fmt.Errorf("response is nil")
}
m.Id = types.Int64Value(resp.GetId())
m.UserId = types.Int64Value(resp.GetId())
m.Username = types.StringValue(resp.GetUsername())
m.Port = types.Int64Value(resp.GetPort())
m.Host = types.StringValue(resp.GetHost())
m.DefaultDatabase = types.StringValue(resp.GetDefaultDatabase())
m.Status = types.StringValue(resp.GetStatus())
if resp.Roles != nil {
roles, diags := types.ListValueFrom(ctx, types.StringType, *resp.Roles)
tfDiags.Append(diags...)
if tfDiags.HasError() {
return fmt.Errorf("failed to map roles")
}
m.Roles = roles
} else {
m.Roles = types.ListNull(types.StringType)
}
if resp.Status != nil {
m.Status = types.StringValue(*resp.Status)
} else {
m.Status = types.StringNull()
}
// TODO: complete and refactor // TODO: complete and refactor
m.Id = types.StringValue(resp.GetId())
/* /*
sampleList, diags := types.ListValueFrom(ctx, types.StringType, resp.GetList()) sampleList, diags := types.ListValueFrom(ctx, types.StringType, resp.GetList())
@ -51,48 +75,63 @@ func mapResponseToModel(
return nil return nil
} }
// TODO: handle encryption field mapping when API supports it
func handleEncryption( func handleEncryption(
m *sqlserverflexbetaResGen.UserModel, m *dataSourceModel,
resp *sqlserverflexbeta.GetUserResponse, resp *sqlserverflexbeta.GetUserResponse,
) sqlserverflexbetaResGen.EncryptionValue { ) sqlserverflexbetaResGen.EncryptionValue {
if !resp.HasEncryption() || /*
resp.Encryption == nil || if !resp.HasEncryption() ||
resp.Encryption.KekKeyId == nil ||
resp.Encryption.KekKeyRingId == nil ||
resp.Encryption.KekKeyVersion == nil ||
resp.Encryption.ServiceAccount == nil {
if m.Encryption.IsNull() || m.Encryption.IsUnknown() { resp.Encryption == nil ||
return sqlserverflexbetaResGen.NewEncryptionValueNull() resp.Encryption.KekKeyId == nil ||
resp.Encryption.KekKeyRingId == nil ||
resp.Encryption.KekKeyVersion == nil ||
resp.Encryption.ServiceAccount == nil {
if m.Encryption.IsNull() || m.Encryption.IsUnknown() {
return sqlserverflexbetaResGen.NewEncryptionValueNull()
}
return m.Encryption
} }
return m.Encryption
}
enc := sqlserverflexbetaResGen.NewEncryptionValueNull() enc := sqlserverflexbetaResGen.NewEncryptionValueNull()
if kVal, ok := resp.Encryption.GetKekKeyIdOk(); ok { if kVal, ok := resp.Encryption.GetKekKeyIdOk(); ok {
enc.KekKeyId = types.StringValue(kVal) enc.KekKeyId = types.StringValue(kVal)
} }
if kkVal, ok := resp.Encryption.GetKekKeyRingIdOk(); ok { if kkVal, ok := resp.Encryption.GetKekKeyRingIdOk(); ok {
enc.KekKeyRingId = types.StringValue(kkVal) enc.KekKeyRingId = types.StringValue(kkVal)
} }
if kkvVal, ok := resp.Encryption.GetKekKeyVersionOk(); ok { if kkvVal, ok := resp.Encryption.GetKekKeyVersionOk(); ok {
enc.KekKeyVersion = types.StringValue(kkvVal) enc.KekKeyVersion = types.StringValue(kkvVal)
} }
if sa, ok := resp.Encryption.GetServiceAccountOk(); ok { if sa, ok := resp.Encryption.GetServiceAccountOk(); ok {
enc.ServiceAccount = types.StringValue(sa) enc.ServiceAccount = types.StringValue(sa)
} }
return enc return enc
*/
return sqlserverflexbetaResGen.NewEncryptionValueNull()
} }
func toCreatePayload( func toCreatePayload(
ctx context.Context, ctx context.Context,
model *sqlserverflexbetaResGen.UserModel, model *dataSourceModel,
) (*sqlserverflexbeta.CreateUserRequestPayload, error) { ) (*sqlserverflexbeta.CreateUserRequestPayload, error) {
if model == nil { if model == nil {
return nil, fmt.Errorf("nil model") return nil, fmt.Errorf("nil model")
} }
var roles []sqlserverflexbeta.UserRole
if !model.Roles.IsNull() && !model.Roles.IsUnknown() {
diags := model.Roles.ElementsAs(ctx, &roles, false)
if diags.HasError() {
return nil, fmt.Errorf("failed to convert roles: %v", diags)
}
}
return &sqlserverflexbeta.CreateUserRequestPayload{ return &sqlserverflexbeta.CreateUserRequestPayload{
// TODO: fill fields DefaultDatabase: model.DefaultDatabase.ValueStringPointer(),
Username: model.Username.ValueStringPointer(),
Roles: &roles,
}, nil }, nil
} }

View file

@ -33,6 +33,9 @@ func NewUserResource() resource.Resource {
return &userResource{} return &userResource{}
} }
// resourceModel describes the resource data model.
type resourceModel = sqlserverflexbetaResGen.UserModel
type userResource struct { type userResource struct {
client *sqlserverflexbeta.APIClient client *sqlserverflexbeta.APIClient
providerData core.ProviderData providerData core.ProviderData
@ -53,7 +56,11 @@ func (r *userResource) Schema(ctx context.Context, req resource.SchemaRequest, r
resp.Schema = sqlserverflexbetaResGen.UserResourceSchema(ctx) resp.Schema = sqlserverflexbetaResGen.UserResourceSchema(ctx)
} }
func (r *instanceResource) IdentitySchema(_ context.Context, _ resource.IdentitySchemaRequest, resp *resource.IdentitySchemaResponse) { func (r *userResource) IdentitySchema(
_ context.Context,
_ resource.IdentitySchemaRequest,
resp *resource.IdentitySchemaResponse,
) {
resp.IdentitySchema = identityschema.Schema{ resp.IdentitySchema = identityschema.Schema{
Attributes: map[string]identityschema.Attribute{ Attributes: map[string]identityschema.Attribute{
"project_id": identityschema.StringAttribute{ "project_id": identityschema.StringAttribute{
@ -85,8 +92,11 @@ func (r *userResource) Configure(
config.WithCustomAuth(r.providerData.RoundTripper), config.WithCustomAuth(r.providerData.RoundTripper),
utils.UserAgentConfigOption(r.providerData.Version), utils.UserAgentConfigOption(r.providerData.Version),
} }
if r.providerData.SqlserverflexbetaCustomEndpoint != "" { if r.providerData.SQLServerFlexCustomEndpoint != "" {
apiClientConfigOptions = append(apiClientConfigOptions, config.WithEndpoint(r.providerData.sqlserverflexbetaCustomEndpoint)) apiClientConfigOptions = append(
apiClientConfigOptions,
config.WithEndpoint(r.providerData.SQLServerFlexCustomEndpoint),
)
} else { } else {
apiClientConfigOptions = append(apiClientConfigOptions, config.WithRegion(r.providerData.GetRegion())) apiClientConfigOptions = append(apiClientConfigOptions, config.WithRegion(r.providerData.GetRegion()))
} }
@ -106,7 +116,7 @@ func (r *userResource) Configure(
} }
func (r *userResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { func (r *userResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
var data sqlserverflexbetaResGen.UserModel var data resourceModel
// Read Terraform plan data into the model // Read Terraform plan data into the model
resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...) resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...)
@ -159,14 +169,14 @@ func (r *userResource) Create(ctx context.Context, req resource.CreateRequest, r
*/ */
// Example data value setting // Example data value setting
data.UserId = types.StringValue("id-from-response") //data.UserId = types.StringValue("id-from-response")
// TODO: Set data returned by API in identity // TODO: Set data returned by API in identity
identity := UserResourceIdentityModel{ identity := UserResourceIdentityModel{
ProjectID: types.StringValue(projectId), ProjectID: types.StringValue(projectId),
Region: types.StringValue(region), Region: types.StringValue(region),
// TODO: add missing values // TODO: add missing values
UserID: types.StringValue(UserId), // UserID: types.StringValue(UserId),
} }
resp.Diagnostics.Append(resp.Identity.Set(ctx, identity)...) resp.Diagnostics.Append(resp.Identity.Set(ctx, identity)...)
if resp.Diagnostics.HasError() { if resp.Diagnostics.HasError() {
@ -228,7 +238,7 @@ func (r *userResource) Create(ctx context.Context, req resource.CreateRequest, r
} }
func (r *userResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { func (r *userResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
var data sqlserverflexbetaResGen.UserModel var data resourceModel
// Read Terraform prior state data into the model // Read Terraform prior state data into the model
resp.Diagnostics.Append(req.State.Get(ctx, &data)...) resp.Diagnostics.Append(req.State.Get(ctx, &data)...)
@ -270,7 +280,7 @@ func (r *userResource) Read(ctx context.Context, req resource.ReadRequest, resp
} }
func (r *userResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { func (r *userResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
var data sqlserverflexbetaResGen.UserModel var data resourceModel
// Read Terraform prior state data into the model // Read Terraform prior state data into the model
resp.Diagnostics.Append(req.State.Get(ctx, &data)...) resp.Diagnostics.Append(req.State.Get(ctx, &data)...)
@ -301,7 +311,7 @@ func (r *userResource) Update(ctx context.Context, req resource.UpdateRequest, r
} }
func (r *userResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { func (r *userResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
var data sqlserverflexbetaResGen.UserModel var data resourceModel
// Read Terraform prior state data into the model // Read Terraform prior state data into the model
resp.Diagnostics.Append(req.State.Get(ctx, &data)...) resp.Diagnostics.Append(req.State.Get(ctx, &data)...)
@ -335,7 +345,7 @@ func (r *userResource) ModifyPlan(
req resource.ModifyPlanRequest, req resource.ModifyPlanRequest,
resp *resource.ModifyPlanResponse, resp *resource.ModifyPlanResponse,
) { // nolint:gocritic // function signature required by Terraform ) { // nolint:gocritic // function signature required by Terraform
var configModel sqlserverflexbetaResGen.UserModel var configModel resourceModel
// skip initial empty configuration to avoid follow-up errors // skip initial empty configuration to avoid follow-up errors
if req.Config.Raw.IsNull() { if req.Config.Raw.IsNull() {
return return
@ -345,7 +355,7 @@ func (r *userResource) ModifyPlan(
return return
} }
var planModel sqlserverflexbetaResGen.UserModel var planModel resourceModel
resp.Diagnostics.Append(req.Plan.Get(ctx, &planModel)...) resp.Diagnostics.Append(req.Plan.Get(ctx, &planModel)...)
if resp.Diagnostics.HasError() { if resp.Diagnostics.HasError() {
return return

View file

@ -20,7 +20,30 @@ type apiClientInstanceMocked struct {
instanceGetFails bool instanceGetFails bool
} }
func (a *apiClientInstanceMocked) GetInstanceRequestExecute(_ context.Context, _, _, _ string) (*sqlserverflex.GetInstanceResponse, error) { func (a *apiClientInstanceMocked) GetDatabaseRequestExecute(
_ context.Context,
projectId string,
region string,
instanceId string,
databaseName string,
) (*sqlserverflex.GetDatabaseResponse, error) {
return nil, nil
}
func (a *apiClientInstanceMocked) GetUserRequestExecute(
ctx context.Context,
projectId string,
region string,
instanceId string,
userId int64,
) (*sqlserverflex.GetUserResponse, error) {
return nil, nil
}
func (a *apiClientInstanceMocked) GetInstanceRequestExecute(
_ context.Context,
_, _, _ string,
) (*sqlserverflex.GetInstanceResponse, error) {
if a.instanceGetFails { if a.instanceGetFails {
return nil, &oapierror.GenericOpenAPIError{ return nil, &oapierror.GenericOpenAPIError{
StatusCode: 500, StatusCode: 500,
@ -111,26 +134,28 @@ func TestCreateInstanceWaitHandler(t *testing.T) {
}, },
} }
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.desc, func(t *testing.T) { t.Run(
instanceId := "foo-bar" tt.desc, func(t *testing.T) {
instanceId := "foo-bar"
apiClient := &apiClientInstanceMocked{ apiClient := &apiClientInstanceMocked{
instanceId: instanceId, instanceId: instanceId,
instanceState: tt.instanceState, instanceState: tt.instanceState,
instanceGetFails: tt.instanceGetFails, instanceGetFails: tt.instanceGetFails,
} }
handler := CreateInstanceWaitHandler(context.Background(), apiClient, "", instanceId, "") handler := CreateInstanceWaitHandler(context.Background(), apiClient, "", instanceId, "")
gotRes, err := handler.SetTimeout(10 * time.Millisecond).SetSleepBeforeWait(1 * time.Millisecond).WaitWithContext(context.Background()) gotRes, err := handler.SetTimeout(10 * time.Millisecond).SetSleepBeforeWait(1 * time.Millisecond).WaitWithContext(context.Background())
if (err != nil) != tt.wantErr { if (err != nil) != tt.wantErr {
t.Fatalf("handler error = %v, wantErr %v", err, tt.wantErr) t.Fatalf("handler error = %v, wantErr %v", err, tt.wantErr)
} }
if !cmp.Equal(gotRes, tt.wantRes) { if !cmp.Equal(gotRes, tt.wantRes) {
t.Fatalf("handler gotRes = %v, want %v", gotRes, tt.wantRes) t.Fatalf("handler gotRes = %v, want %v", gotRes, tt.wantRes)
} }
}) },
)
} }
} }
@ -179,34 +204,36 @@ func TestUpdateInstanceWaitHandler(t *testing.T) {
}, },
} }
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.desc, func(t *testing.T) { t.Run(
instanceId := "foo-bar" tt.desc, func(t *testing.T) {
instanceId := "foo-bar"
apiClient := &apiClientInstanceMocked{ apiClient := &apiClientInstanceMocked{
instanceId: instanceId, instanceId: instanceId,
instanceState: tt.instanceState, instanceState: tt.instanceState,
instanceGetFails: tt.instanceGetFails, instanceGetFails: tt.instanceGetFails,
}
var wantRes *sqlserverflex.GetInstanceResponse
if tt.wantResp {
wantRes = &sqlserverflex.GetInstanceResponse{
Id: &instanceId,
Status: sqlserverflex.GetInstanceResponseGetStatusAttributeType(utils.Ptr(tt.instanceState)),
} }
}
handler := UpdateInstanceWaitHandler(context.Background(), apiClient, "", instanceId, "") var wantRes *sqlserverflex.GetInstanceResponse
if tt.wantResp {
wantRes = &sqlserverflex.GetInstanceResponse{
Id: &instanceId,
Status: sqlserverflex.GetInstanceResponseGetStatusAttributeType(utils.Ptr(tt.instanceState)),
}
}
gotRes, err := handler.SetTimeout(10 * time.Millisecond).SetSleepBeforeWait(1 * time.Millisecond).WaitWithContext(context.Background()) handler := UpdateInstanceWaitHandler(context.Background(), apiClient, "", instanceId, "")
if (err != nil) != tt.wantErr { gotRes, err := handler.SetTimeout(10 * time.Millisecond).SetSleepBeforeWait(1 * time.Millisecond).WaitWithContext(context.Background())
t.Fatalf("handler error = %v, wantErr %v", err, tt.wantErr)
} if (err != nil) != tt.wantErr {
if !cmp.Equal(gotRes, wantRes) { t.Fatalf("handler error = %v, wantErr %v", err, tt.wantErr)
t.Fatalf("handler gotRes = %v, want %v", gotRes, wantRes) }
} if !cmp.Equal(gotRes, wantRes) {
}) t.Fatalf("handler gotRes = %v, want %v", gotRes, wantRes)
}
},
)
} }
} }
@ -236,23 +263,25 @@ func TestDeleteInstanceWaitHandler(t *testing.T) {
}, },
} }
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.desc, func(t *testing.T) { t.Run(
instanceId := "foo-bar" tt.desc, func(t *testing.T) {
instanceId := "foo-bar"
apiClient := &apiClientInstanceMocked{ apiClient := &apiClientInstanceMocked{
instanceGetFails: tt.instanceGetFails, instanceGetFails: tt.instanceGetFails,
instanceIsDeleted: tt.instanceState == InstanceStateSuccess, instanceIsDeleted: tt.instanceState == InstanceStateSuccess,
instanceId: instanceId, instanceId: instanceId,
instanceState: tt.instanceState, instanceState: tt.instanceState,
} }
handler := DeleteInstanceWaitHandler(context.Background(), apiClient, "", instanceId, "") handler := DeleteInstanceWaitHandler(context.Background(), apiClient, "", instanceId, "")
_, err := handler.SetTimeout(10 * time.Millisecond).WaitWithContext(context.Background()) _, err := handler.SetTimeout(10 * time.Millisecond).WaitWithContext(context.Background())
if (err != nil) != tt.wantErr { if (err != nil) != tt.wantErr {
t.Fatalf("handler error = %v, wantErr %v", err, tt.wantErr) t.Fatalf("handler error = %v, wantErr %v", err, tt.wantErr)
} }
}) },
)
} }
} }