chore: changed and refactored providers (#36)

## Description

<!-- **Please link some issue here describing what you are trying to achieve.**

In case there is no issue present for your PR, please consider creating one.
At least please give us some description what you are trying to achieve and why your change is needed. -->

relates to #1234

## Checklist

- [ ] Issue was linked above
- [ ] Code format was applied: `make fmt`
- [ ] Examples were added / adjusted (see `examples/` directory)
- [x] Docs are up-to-date: `make generate-docs` (will be checked by CI)
- [ ] Unit tests got implemented or updated
- [ ] Acceptance tests got implemented or updated (see e.g. [here](f5f99d1709/stackit/internal/services/dns/dns_acc_test.go))
- [x] Unit tests are passing: `make test` (will be checked by CI)
- [x] No linter issues: `make lint` (will be checked by CI)

Co-authored-by: Marcel S. Henselin <marcel.henselin@stackit.cloud>
Reviewed-on: #36
Reviewed-by: Marcel_Henselin <marcel.henselin@stackit.cloud>
Co-authored-by: Andre Harms <andre.harms@stackit.cloud>
Co-committed-by: Andre Harms <andre.harms@stackit.cloud>
This commit is contained in:
Andre_Harms 2026-02-10 08:10:02 +00:00 committed by Marcel_Henselin
parent b1b359f436
commit de019908d2
Signed by: tf-provider.git.onstackit.cloud
GPG key ID: 6D7E8A1ED8955A9C
70 changed files with 6250 additions and 2608 deletions

View file

@ -11,7 +11,6 @@ import (
"time"
"github.com/hashicorp/terraform-plugin-framework/resource/identityschema"
postgresflexUtils "tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit/internal/services/postgresflexalpha/utils"
sqlserverflexalpha2 "tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit/internal/services/sqlserverflexalpha/instance/resources_gen"
sqlserverflexUtils "tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit/internal/services/sqlserverflexalpha/utils"
@ -37,23 +36,26 @@ var (
_ 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
var validNodeTypes []string = []string{
"Single",
"Replica",
}
// resourceModel describes the resource data model.
type resourceModel = sqlserverflexalpha2.InstanceModel
type InstanceResourceIdentityModel struct {
ProjectID types.String `tfsdk:"project_id"`
Region types.String `tfsdk:"region"`
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.
type instanceResource struct {
client *sqlserverflexalpha.APIClient
@ -140,270 +142,28 @@ var modifiersFileByte []byte
// Schema defines the schema for the resource.
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)
fields, err := postgresflexUtils.ReadModifiersConfig(modifiersFileByte)
fields, err := utils.ReadModifiersConfig(modifiersFileByte)
if err != nil {
resp.Diagnostics.AddError("error during read modifiers config file", err.Error())
return
}
err = postgresflexUtils.AddPlanModifiersToResourceSchema(fields, &schema)
err = utils.AddPlanModifiersToResourceSchema(fields, &schema)
if err != nil {
resp.Diagnostics.AddError("error adding plan modifiers", err.Error())
return
}
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{
Attributes: map[string]identityschema.Attribute{
"project_id": identityschema.StringAttribute{
@ -425,7 +185,7 @@ func (r *instanceResource) Create(
req resource.CreateRequest,
resp *resource.CreateResponse,
) { // nolint:gocritic // function signature required by Terraform
var model sqlserverflexalpha2.InstanceModel
var model resourceModel
diags := req.Plan.Get(ctx, &model)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
@ -528,7 +288,7 @@ func (r *instanceResource) Create(
// Map response body to schema
// 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 {
core.LogAndAddError(
ctx,
@ -554,7 +314,7 @@ func (r *instanceResource) Read(
req resource.ReadRequest,
resp *resource.ReadResponse,
) { // nolint:gocritic // function signature required by Terraform
var model sqlserverflexalpha2.InstanceModel
var model resourceModel
diags := req.State.Get(ctx, &model)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
@ -592,7 +352,7 @@ func (r *instanceResource) Read(
ctx = core.LogResponse(ctx)
// Map response body to schema
err = mapResponseToModel(ctx, instanceResp, &model, resp.Diagnostics)
err = mapFields(ctx, instanceResp, &model, resp.Diagnostics)
if err != nil {
core.LogAndAddError(
ctx,
@ -629,7 +389,7 @@ func (r *instanceResource) Update(
resp *resource.UpdateResponse,
) { // nolint:gocritic // function signature required by Terraform
// Retrieve values from plan
var model sqlserverflexalpha2.InstanceModel
var model resourceModel
diags := req.Plan.Get(ctx, &model)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
@ -683,7 +443,7 @@ func (r *instanceResource) Update(
}
// 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)
if err != nil {
core.LogAndAddError(
@ -709,7 +469,7 @@ func (r *instanceResource) Delete(
resp *resource.DeleteResponse,
) { // nolint:gocritic // function signature required by Terraform
// Retrieve values from state
var model sqlserverflexalpha2.InstanceModel
var model resourceModel
diags := req.State.Get(ctx, &model)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
@ -754,20 +514,41 @@ func (r *instanceResource) ImportState(
req resource.ImportStateRequest,
resp *resource.ImportStateResponse,
) {
// TODO
idParts := strings.Split(req.ID, core.Separator)
if req.ID != "" {
idParts := strings.Split(req.ID, core.Separator)
if len(idParts) != 3 || idParts[0] == "" || idParts[1] == "" || idParts[2] == "" {
core.LogAndAddError(
ctx, &resp.Diagnostics,
"Error importing instance",
fmt.Sprintf("Expected import identifier with format: [project_id],[region],[instance_id] Got: %q", req.ID),
)
if len(idParts) != 3 || idParts[0] == "" || idParts[1] == "" || idParts[2] == "" {
core.LogAndAddError(
ctx, &resp.Diagnostics,
"Error importing instance",
fmt.Sprintf(
"Expected import identifier with format: [project_id],[region],[instance_id] Got: %q",
req.ID,
),
)
return
}
resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("project_id"), idParts[0])...)
resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("region"), idParts[1])...)
resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("instance_id"), idParts[2])...)
return
}
resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("project_id"), idParts[0])...)
resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("region"), idParts[1])...)
resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("instance_id"), idParts[2])...)
// If no ID is provided, attempt to read identity attributes from the import configuration
var identityData InstanceResourceIdentityModel
resp.Diagnostics.Append(req.Identity.Get(ctx, &identityData)...)
if resp.Diagnostics.HasError() {
return
}
projectId := identityData.ProjectID.ValueString()
region := identityData.Region.ValueString()
instanceId := identityData.InstanceID.ValueString()
resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("project_id"), projectId)...)
resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("region"), region)...)
resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("instance_id"), instanceId)...)
tflog.Info(ctx, "SQLServer Flex instance state imported")
}