chore: changed and refactored providers #36

Merged
marcel.henselin merged 31 commits from feat/alpha_user_database into alpha 2026-02-10 08:10:03 +00:00
Showing only changes of commit a46e26b69b - Show all commits

View file

@ -14,9 +14,6 @@ import (
"github.com/hashicorp/terraform-plugin-framework/resource"
"github.com/hashicorp/terraform-plugin-framework/resource/identityschema"
"github.com/hashicorp/terraform-plugin-framework/resource/schema"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/int64planmodifier"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
"github.com/hashicorp/terraform-plugin-framework/schema/validator"
"github.com/hashicorp/terraform-plugin-framework/types"
"github.com/hashicorp/terraform-plugin-log/tflog"
"github.com/stackitcloud/stackit-sdk-go/core/oapierror"
@ -25,24 +22,33 @@ import (
"tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit/internal/core"
postgresflexalpha2 "tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit/internal/services/postgresflexalpha/database/resources_gen"
postgresflexUtils "tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit/internal/services/postgresflexalpha/utils"
"tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit/internal/utils"
)
// Ensure the implementation satisfies the expected interfaces.
var (
// Ensure the implementation satisfies the expected interfaces.
_ resource.Resource = &databaseResource{}
_ resource.ResourceWithConfigure = &databaseResource{}
_ resource.ResourceWithImportState = &databaseResource{}
_ resource.ResourceWithModifyPlan = &databaseResource{}
_ resource.ResourceWithIdentity = &databaseResource{}
// Define errors
errDatabaseNotFound = errors.New("database not found")
// Error message constants
extractErrorSummary = "extracting failed"
extractErrorMessage = "Extracting identity data: %v"
)
// ResourceModel describes the resource data model.
type ResourceModel struct {
postgresflexalpha2.DatabaseModel
TerraformID types.String `tfsdk:"id"`
ProjectID types.String `tfsdk:"project_id"`
Region types.String `tfsdk:"region"`
InstanceID types.String `tfsdk:"instance_id"`
DatabaseID types.Int64 `tfsdk:"database_id"`
TerraformID types.String `tfsdk:"id"`
}
// DatabaseResourceIdentityModel describes the resource's identity attributes.
@ -86,7 +92,7 @@ func (r *databaseResource) ModifyPlan(
return
}
//TODO utils.AdaptRegion(ctx, configModel.Region, &planModel.Region, r.providerData.GetRegion(), resp)
utils.AdaptRegion(ctx, configModel.Region, &planModel.Region, r.providerData.GetRegion(), resp)
if resp.Diagnostics.HasError() {
return
}
@ -128,18 +134,32 @@ var modifiersFileByte []byte
// Schema defines the schema for the resource.
func (r *databaseResource) Schema(ctx context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) {
s := postgresflexalpha2.DatabaseResourceSchema(ctx)
s.Attributes["id"] = schema.StringAttribute{
Description: "Terraform's internal resource ID. It is structured as \\\"`project_id`,`region`,`instance_id`,`database_id`\\\".\",",
s.Attributes["project_id"] = schema.StringAttribute{
Description: "STACKIT project ID to which the instance is associated.",
MarkdownDescription: "STACKIT project ID to which the instance is associated.",
Required: true,
}
s.Attributes["instance_id"] = schema.StringAttribute{
Description: "ID of the PostgresFlex instance.",
MarkdownDescription: "ID of the PostgresFlex instance.",
Required: true,
}
s.Attributes["region"] = schema.StringAttribute{
Description: "Region of the PostgresFlex instance.",
MarkdownDescription: "Region of the PostgresFlex instance.",
Optional: true,
Computed: true,
}
s.Attributes["database_id"] = schema.Int64Attribute{
Description: "ID of the database.",
Description: "The ID of the database.",
Computed: true,
}
s.Attributes["id"] = schema.StringAttribute{
Description: "Terraform's internal resource ID. It is structured as \\\"`project_id`,`region`,`instance_id`,`database_id`\\\".\",",
Optional: true,
Computed: true,
PlanModifiers: []planmodifier.Int64{
int64planmodifier.UseStateForUnknown(),
},
Validators: []validator.Int64{},
}
fields, err := postgresflexUtils.ReadModifiersConfig(modifiersFileByte)
@ -300,10 +320,16 @@ func (r *databaseResource) Read(
ctx = core.InitProviderContext(ctx)
projectId := identityData.ProjectID.ValueString()
instanceId := identityData.InstanceID.ValueString()
databaseId := model.DatabaseID.ValueInt64()
region := r.providerData.GetRegionWithOverride(identityData.Region)
projectId, instanceId, region, databaseId, errExt := r.extractIdentityData(model, identityData)
if errExt != nil {
core.LogAndAddError(
ctx,
&resp.Diagnostics,
extractErrorSummary,
fmt.Sprintf(extractErrorMessage, errExt),
)
}
ctx = tflog.SetField(ctx, "project_id", projectId)
ctx = tflog.SetField(ctx, "instance_id", instanceId)
ctx = tflog.SetField(ctx, "region", region)
@ -365,11 +391,16 @@ func (r *databaseResource) Update(
ctx = core.InitProviderContext(ctx)
projectId := identityData.ProjectID.ValueString()
instanceId := identityData.InstanceID.ValueString()
region := r.providerData.GetRegionWithOverride(identityData.Region)
projectId, instanceId, region, databaseId64, errExt := r.extractIdentityData(model, identityData)
if errExt != nil {
core.LogAndAddError(
ctx,
&resp.Diagnostics,
extractErrorSummary,
fmt.Sprintf(extractErrorMessage, errExt),
)
}
databaseId64 := model.DatabaseID.ValueInt64() // database id
if databaseId64 > math.MaxInt32 {
core.LogAndAddError(ctx, &resp.Diagnostics, "Error in type conversion", "int value too large (databaseId)")
return
@ -463,10 +494,15 @@ func (r *databaseResource) Delete(
ctx = core.InitProviderContext(ctx)
projectId := identityData.ProjectID.ValueString()
instanceId := identityData.InstanceID.ValueString()
region := r.providerData.GetRegionWithOverride(identityData.Region)
databaseId64 := model.DatabaseID.ValueInt64() //database id
projectId, instanceId, region, databaseId64, errExt := r.extractIdentityData(model, identityData)
if errExt != nil {
core.LogAndAddError(
ctx,
&resp.Diagnostics,
extractErrorSummary,
fmt.Sprintf(extractErrorMessage, errExt),
)
}
if databaseId64 > math.MaxInt32 {
core.LogAndAddError(ctx, &resp.Diagnostics, "Error in type conversion", "int value too large (databaseId)")
@ -525,13 +561,12 @@ func (r *databaseResource) ImportState(
resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("instance_id"), idParts[2])...)
resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("database_id"), databaseId)...)
//TODO: Investigate if this logic is still required.
//core.LogAndAddWarning(
// ctx,
// &resp.Diagnostics,
// "Postgresflex database imported with empty password",
// "The database password is not imported as it is only available upon creation of a new database. The password field will be empty.",
//)
core.LogAndAddWarning(
ctx,
&resp.Diagnostics,
"Postgresflex database imported with empty password",
"The database password is not imported as it is only available upon creation of a new database. The password field will be empty.",
)
var identityData DatabaseResourceIdentityModel
identityData.ProjectID = types.StringValue(idParts[0])
@ -539,7 +574,7 @@ func (r *databaseResource) ImportState(
identityData.InstanceID = types.StringValue(idParts[2])
identityData.DatabaseID = types.Int64Value(databaseId)
resp.Diagnostics.Append(req.Identity.Set(ctx, &identityData)...)
resp.Diagnostics.Append(resp.Identity.Set(ctx, &identityData)...)
if resp.Diagnostics.HasError() {
return
@ -548,3 +583,46 @@ func (r *databaseResource) ImportState(
tflog.Info(ctx, "Postgres Flex instance state imported")
}
// extractIdentityData extracts essential identifiers from the resource model, falling back to the identity model.
func (r *databaseResource) extractIdentityData(
model ResourceModel,
identity DatabaseResourceIdentityModel,
) (projectId, region, instanceId string, databaseId int64, err error) {
if !model.DatabaseID.IsNull() && !model.DatabaseID.IsUnknown() {
databaseId = model.DatabaseID.ValueInt64()
} else {
if identity.DatabaseID.IsNull() || identity.DatabaseID.IsUnknown() {
return "", "", "", 0, fmt.Errorf("database_id not found in config")
}
databaseId = identity.DatabaseID.ValueInt64()
}
if !model.ProjectID.IsNull() && !model.ProjectID.IsUnknown() {
projectId = model.ProjectID.ValueString()
} else {
if identity.ProjectID.IsNull() || identity.ProjectID.IsUnknown() {
return "", "", "", 0, fmt.Errorf("project_id not found in config")
}
projectId = identity.ProjectID.ValueString()
}
if !model.Region.IsNull() && !model.Region.IsUnknown() {
region = r.providerData.GetRegionWithOverride(model.Region)
} else {
if identity.Region.IsNull() || identity.Region.IsUnknown() {
return "", "", "", 0, fmt.Errorf("region not found in config")
}
region = r.providerData.GetRegionWithOverride(identity.Region)
}
if !model.InstanceID.IsNull() && !model.InstanceID.IsUnknown() {
instanceId = model.InstanceID.ValueString()
} else {
if identity.InstanceID.IsNull() || identity.InstanceID.IsUnknown() {
return "", "", "", 0, fmt.Errorf("instance_id not found in config")
}
instanceId = identity.InstanceID.ValueString()
}
return projectId, region, instanceId, databaseId, nil
}