From e141f89c9fd808f7c848a6a918da3b5cd5da666a Mon Sep 17 00:00:00 2001 From: Henrique Santos Date: Wed, 20 Sep 2023 09:39:27 +0100 Subject: [PATCH 01/17] Remove unnecessary pointer --- stackit/core/core.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stackit/core/core.go b/stackit/core/core.go index 1c1dfcb35..74619d120 100644 --- a/stackit/core/core.go +++ b/stackit/core/core.go @@ -52,5 +52,5 @@ func DiagsToError(diags diag.Diagnostics) error { // LogAndAddError Logs the error and adds it to the diags func LogAndAddError(ctx context.Context, diags *diag.Diagnostics, summary, detail string) { tflog.Error(ctx, summary) - (*diags).AddError(summary, detail) + diags.AddError(summary, detail) } From 7ad4ad7144ad28cd84edfecdee6722042bbd3067 Mon Sep 17 00:00:00 2001 From: Henrique Santos Date: Wed, 20 Sep 2023 10:00:02 +0100 Subject: [PATCH 02/17] Add early return on error --- stackit/services/dns/recordset/resource.go | 9 +++++++++ stackit/services/dns/zone/resource.go | 12 ++++++++++++ 2 files changed, 21 insertions(+) diff --git a/stackit/services/dns/recordset/resource.go b/stackit/services/dns/recordset/resource.go index 81e114b08..97333743a 100644 --- a/stackit/services/dns/recordset/resource.go +++ b/stackit/services/dns/recordset/resource.go @@ -256,6 +256,9 @@ func (r *recordSetResource) Create(ctx context.Context, req resource.CreateReque // Set state to fully populated data diags = resp.State.Set(ctx, model) resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } tflog.Info(ctx, "DNS record set created") } @@ -290,6 +293,9 @@ func (r *recordSetResource) Read(ctx context.Context, req resource.ReadRequest, // Set refreshed state diags = resp.State.Set(ctx, model) resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } tflog.Info(ctx, "DNS record set read") } @@ -346,6 +352,9 @@ func (r *recordSetResource) Update(ctx context.Context, req resource.UpdateReque } diags = resp.State.Set(ctx, model) resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } tflog.Info(ctx, "DNS record set updated") } diff --git a/stackit/services/dns/zone/resource.go b/stackit/services/dns/zone/resource.go index 7b63af93c..7526fb843 100644 --- a/stackit/services/dns/zone/resource.go +++ b/stackit/services/dns/zone/resource.go @@ -109,6 +109,9 @@ func (r *zoneResource) Configure(ctx context.Context, req resource.ConfigureRequ } tflog.Info(ctx, "DNS zone client configured") + if resp.Diagnostics.HasError() { + return + } r.client = apiClient } @@ -345,6 +348,9 @@ func (r *zoneResource) Create(ctx context.Context, req resource.CreateRequest, r // Set state to fully populated data diags = resp.State.Set(ctx, model) resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } tflog.Info(ctx, "DNS zone created") } @@ -376,6 +382,9 @@ func (r *zoneResource) Read(ctx context.Context, req resource.ReadRequest, resp // Set refreshed state diags = resp.State.Set(ctx, state) resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } tflog.Info(ctx, "DNS zone read") } @@ -429,6 +438,9 @@ func (r *zoneResource) Update(ctx context.Context, req resource.UpdateRequest, r } diags = resp.State.Set(ctx, model) resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } tflog.Info(ctx, "DNS zone updated") } From 9da469d8aa3445cd6bf79b72bca1641e926d3474 Mon Sep 17 00:00:00 2001 From: Henrique Santos Date: Wed, 20 Sep 2023 14:24:36 +0100 Subject: [PATCH 03/17] Revamp logging, uniform, multiple bug fixes --- stackit/provider.go | 8 +- stackit/services/argus/credential/resource.go | 32 ++- stackit/services/argus/instance/datasource.go | 28 +-- stackit/services/argus/instance/resource.go | 90 ++++--- .../services/argus/scrapeconfig/datasource.go | 13 +- .../services/argus/scrapeconfig/resource.go | 59 +++-- stackit/services/dns/recordset/datasource.go | 26 +- stackit/services/dns/recordset/resource.go | 42 ++-- stackit/services/dns/zone/datasource.go | 25 +- stackit/services/dns/zone/resource.go | 55 ++--- .../services/logme/credentials/datasource.go | 15 +- .../services/logme/credentials/resource.go | 34 +-- stackit/services/logme/instance/datasource.go | 32 +-- stackit/services/logme/instance/resource.go | 124 ++++++---- .../mariadb/credentials/datasource.go | 23 +- .../services/mariadb/credentials/resource.go | 62 ++--- .../services/mariadb/instance/datasource.go | 34 +-- stackit/services/mariadb/instance/resource.go | 143 +++++++---- .../opensearch/credentials/datasource.go | 17 +- .../opensearch/credentials/resource.go | 54 +++-- .../opensearch/instance/datasource.go | 34 +-- .../services/opensearch/instance/resource.go | 144 +++++++---- .../postgresflex/instance/datasource.go | 35 +-- .../postgresflex/instance/resource.go | 63 ++--- .../services/postgresflex/user/datasource.go | 17 +- .../services/postgresflex/user/resource.go | 38 +-- .../postgresql/credentials/datasource.go | 17 +- .../postgresql/credentials/resource.go | 62 ++--- .../postgresql/instance/datasource.go | 38 +-- .../services/postgresql/instance/resource.go | 138 ++++++----- .../rabbitmq/credentials/datasource.go | 15 +- .../services/rabbitmq/credentials/resource.go | 54 +++-- .../services/rabbitmq/instance/datasource.go | 34 +-- .../services/rabbitmq/instance/resource.go | 222 +++++++++-------- .../services/redis/credentials/datasource.go | 15 +- .../services/redis/credentials/resource.go | 56 +++-- stackit/services/redis/instance/datasource.go | 34 +-- stackit/services/redis/instance/resource.go | 225 ++++++++++-------- .../resourcemanager/project/datasource.go | 19 +- .../resourcemanager/project/resource.go | 66 +++-- stackit/services/ske/cluster/datasource.go | 13 +- stackit/services/ske/cluster/resource.go | 83 +++---- stackit/services/ske/project/datasource.go | 23 +- stackit/services/ske/project/resource.go | 32 +-- 44 files changed, 1364 insertions(+), 1029 deletions(-) diff --git a/stackit/provider.go b/stackit/provider.go index 78c4fc8ee..d34e016f8 100644 --- a/stackit/provider.go +++ b/stackit/provider.go @@ -2,6 +2,7 @@ package stackit import ( "context" + "fmt" "github.com/hashicorp/terraform-plugin-framework/datasource" "github.com/hashicorp/terraform-plugin-framework/provider" @@ -225,10 +226,7 @@ func (p *Provider) Configure(ctx context.Context, req provider.ConfigureRequest, } roundTripper, err := sdkauth.SetupAuth(sdkConfig) if err != nil { - resp.Diagnostics.AddError( - "Unable to Setup SDK", - err.Error(), - ) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error configuring provider", fmt.Sprintf("Setting up authentication: %v", err)) return } @@ -274,7 +272,7 @@ func (p *Provider) Resources(_ context.Context) []func() resource.Resource { postgresInstance.NewInstanceResource, postgresCredentials.NewCredentialsResource, logMeInstance.NewInstanceResource, - logMeCredentials.NewlogmeCredentialsResource, + logMeCredentials.NewCredentialsResource, mariaDBInstance.NewInstanceResource, mariaDBCredentials.NewCredentialsResource, openSearchInstance.NewInstanceResource, diff --git a/stackit/services/argus/credential/resource.go b/stackit/services/argus/credential/resource.go index d8efb4a3b..44befbb00 100644 --- a/stackit/services/argus/credential/resource.go +++ b/stackit/services/argus/credential/resource.go @@ -49,7 +49,7 @@ func (r *credentialResource) Metadata(_ context.Context, req resource.MetadataRe } // Configure adds the provider configured client to the resource. -func (r *credentialResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { +func (r *credentialResource) Configure(ctx context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { // Prevent panic if the provider has not been configured. if req.ProviderData == nil { return @@ -57,7 +57,7 @@ func (r *credentialResource) Configure(_ context.Context, req resource.Configure providerData, ok := req.ProviderData.(core.ProviderData) if !ok { - resp.Diagnostics.AddError("Unexpected Data Source Configure Type", fmt.Sprintf("Expected stackit.ProviderData, got %T", req.ProviderData)) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error configuring API client", fmt.Sprintf("Expected configure type stackit.ProviderData, got %T", req.ProviderData)) return } @@ -76,10 +76,12 @@ func (r *credentialResource) Configure(_ context.Context, req resource.Configure } if err != nil { - resp.Diagnostics.AddError("Could not Configure API Client", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error configuring API client", err.Error()) return } + r.client = apiClient + tflog.Info(ctx, "Argus credential client configured") } func (r *credentialResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) { @@ -148,17 +150,20 @@ func (r *credentialResource) Create(ctx context.Context, req resource.CreateRequ got, err := r.client.CreateCredential(ctx, instanceId, projectId).Execute() if err != nil { - resp.Diagnostics.AddError("Error creating credential", fmt.Sprintf("Calling API: %v", err)) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating credential", fmt.Sprintf("Calling API: %v", err)) return } err = mapFields(got.Credentials, &model) if err != nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error mapping fields", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating credential", fmt.Sprintf("Processing API payload: %v", err)) return } diags = resp.State.Set(ctx, &model) resp.Diagnostics.Append(diags...) - tflog.Info(ctx, "ARGUS credential created") + if resp.Diagnostics.HasError() { + return + } + tflog.Info(ctx, "Argus credential created") } func mapFields(r *argus.Credential, model *Model) error { @@ -202,17 +207,20 @@ func (r *credentialResource) Read(ctx context.Context, req resource.ReadRequest, userName := model.Username.ValueString() _, err := r.client.GetCredential(ctx, instanceId, projectId, userName).Execute() if err != nil { - resp.Diagnostics.AddError("Error reading credential", fmt.Sprintf("Project id = %s, instance id = %s, username = %s: %v", projectId, instanceId, userName, err)) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading credential", fmt.Sprintf("Calling API: %v", err)) return } diags = resp.State.Set(ctx, model) resp.Diagnostics.Append(diags...) - tflog.Info(ctx, "ARGUS credential read") + if resp.Diagnostics.HasError() { + return + } + tflog.Info(ctx, "Argus credential read") } -func (r *credentialResource) Update(_ context.Context, _ resource.UpdateRequest, resp *resource.UpdateResponse) { // nolint:gocritic // function signature required by Terraform +func (r *credentialResource) Update(ctx context.Context, _ resource.UpdateRequest, resp *resource.UpdateResponse) { // nolint:gocritic // function signature required by Terraform // Update shouldn't be called - resp.Diagnostics.AddError("Error updating credentials", "credentials can't be updated") + core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating credential", "Credential can't be updated") } // Delete deletes the resource and removes the Terraform state on success. @@ -229,8 +237,8 @@ func (r *credentialResource) Delete(ctx context.Context, req resource.DeleteRequ userName := model.Username.ValueString() _, err := r.client.DeleteCredential(ctx, instanceId, projectId, userName).Execute() if err != nil { - resp.Diagnostics.AddError("Error deleting credential", "project id = "+projectId+", instance id = "+instanceId+", username = "+userName+", "+err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error deleting credential", fmt.Sprintf("Calling API: %v", err)) return } - tflog.Info(ctx, "ARGUS credential deleted") + tflog.Info(ctx, "Argus credential deleted") } diff --git a/stackit/services/argus/instance/datasource.go b/stackit/services/argus/instance/datasource.go index 5bf173bf6..fdd890853 100644 --- a/stackit/services/argus/instance/datasource.go +++ b/stackit/services/argus/instance/datasource.go @@ -9,6 +9,7 @@ import ( "github.com/hashicorp/terraform-plugin-framework/datasource/schema" "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/config" "github.com/stackitcloud/stackit-sdk-go/services/argus" "github.com/stackitcloud/terraform-provider-stackit/stackit/core" @@ -35,7 +36,7 @@ func (d *instanceDataSource) Metadata(_ context.Context, req datasource.Metadata resp.TypeName = req.ProviderTypeName + "_argus_instance" } -func (d *instanceDataSource) Configure(_ context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) { +func (d *instanceDataSource) Configure(ctx context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) { // Prevent panic if the provider has not been configured. if req.ProviderData == nil { return @@ -46,7 +47,7 @@ func (d *instanceDataSource) Configure(_ context.Context, req datasource.Configu providerData, ok := req.ProviderData.(core.ProviderData) if !ok { - resp.Diagnostics.AddError("Unexpected Data Source Configure Type", fmt.Sprintf("Expected stackit.ProviderData, got %T. Please report this issue to the provider developers.", req.ProviderData)) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error configuring API client", fmt.Sprintf("Expected configure type stackit.ProviderData, got %T", req.ProviderData)) return } @@ -62,13 +63,11 @@ func (d *instanceDataSource) Configure(_ context.Context, req datasource.Configu ) } if err != nil { - resp.Diagnostics.AddError( - "Could not Configure API Client", - err.Error(), - ) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error configuring API client", fmt.Sprintf("Configuring client: %v", err)) return } d.client = apiClient + tflog.Info(ctx, "Argus instance client configured") } // Schema defines the schema for the data source. @@ -202,28 +201,29 @@ func (d *instanceDataSource) Schema(_ context.Context, _ datasource.SchemaReques // Read refreshes the Terraform state with the latest data. func (d *instanceDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { // nolint:gocritic // function signature required by Terraform - var state Model - diags := req.Config.Get(ctx, &state) + var model Model + diags := req.Config.Get(ctx, &model) resp.Diagnostics.Append(diags...) if resp.Diagnostics.HasError() { return } - projectId := state.ProjectId.ValueString() - instanceId := state.InstanceId.ValueString() + projectId := model.ProjectId.ValueString() + instanceId := model.InstanceId.ValueString() instanceResponse, err := d.client.GetInstance(ctx, instanceId, projectId).Execute() if err != nil { - core.LogAndAddError(ctx, &diags, "Unable to read instance", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading instance", fmt.Sprintf("Calling API: %v", err)) return } - err = mapFields(ctx, instanceResponse, &state) + err = mapFields(ctx, instanceResponse, &model) if err != nil { - core.LogAndAddError(ctx, &diags, "Mapping fields", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading instance", fmt.Sprintf("Processing API payload: %v", err)) return } - diags = resp.State.Set(ctx, state) + diags = resp.State.Set(ctx, model) resp.Diagnostics.Append(diags...) if resp.Diagnostics.HasError() { return } + tflog.Info(ctx, "Argus instance read") } diff --git a/stackit/services/argus/instance/resource.go b/stackit/services/argus/instance/resource.go index fd1a37341..4a73a01ad 100644 --- a/stackit/services/argus/instance/resource.go +++ b/stackit/services/argus/instance/resource.go @@ -8,7 +8,6 @@ import ( "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator" "github.com/hashicorp/terraform-plugin-framework/attr" - "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/path" "github.com/hashicorp/terraform-plugin-framework/resource" "github.com/hashicorp/terraform-plugin-framework/resource/schema" @@ -17,6 +16,7 @@ import ( "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier" "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/config" "github.com/stackitcloud/stackit-sdk-go/services/argus" "github.com/stackitcloud/terraform-provider-stackit/stackit/core" @@ -75,7 +75,7 @@ func (r *instanceResource) Metadata(_ context.Context, req resource.MetadataRequ } // Configure adds the provider configured client to the resource. -func (r *instanceResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { +func (r *instanceResource) Configure(ctx context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { // Prevent panic if the provider has not been configured. if req.ProviderData == nil { return @@ -83,7 +83,7 @@ func (r *instanceResource) Configure(_ context.Context, req resource.ConfigureRe providerData, ok := req.ProviderData.(core.ProviderData) if !ok { - resp.Diagnostics.AddError("Unexpected Resource Configure Type", fmt.Sprintf("Expected stackit.ProviderData, got %T. Please report this issue to the provider developers.", req.ProviderData)) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error configuring API client", fmt.Sprintf("Expected configure type stackit.ProviderData, got %T", req.ProviderData)) return } @@ -102,10 +102,12 @@ func (r *instanceResource) Configure(_ context.Context, req resource.ConfigureRe } if err != nil { - resp.Diagnostics.AddError("Could not Configure API Client", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error configuring API client", fmt.Sprintf("Configuring client: %v", err)) return } + r.client = apiClient + tflog.Info(ctx, "Argus instance client configured") } // Schema defines the schema for the resource. @@ -264,48 +266,50 @@ func (r *instanceResource) Create(ctx context.Context, req resource.CreateReques } projectId := model.ProjectId.ValueString() + ctx = tflog.SetField(ctx, "project_id", projectId) - r.loadPlanId(ctx, &resp.Diagnostics, &model) - if diags.HasError() { - core.LogAndAddError(ctx, &diags, "Failed to load argus service plan", "plan "+model.PlanName.ValueString()) + err := r.loadPlanId(ctx, &model) + if err != nil { + core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating instance", fmt.Sprintf("Loading service plan: %v", err)) return } // Generate API request body from model payload, err := toCreatePayload(&model) if err != nil { - resp.Diagnostics.AddError("Error creating instance", fmt.Sprintf("Creating API payload: %v", err)) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating instance", fmt.Sprintf("Creating API payload: %v", err)) return } createResp, err := r.client.CreateInstance(ctx, projectId).CreateInstancePayload(*payload).Execute() if err != nil { - resp.Diagnostics.AddError("Error creating instance", fmt.Sprintf("Calling API: %v", err)) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating instance", fmt.Sprintf("Calling API: %v", err)) return } instanceId := createResp.InstanceId - if instanceId == nil || *instanceId == "" { - resp.Diagnostics.AddError("Error creating instance", "API didn't return an instance id") - return - } + ctx = tflog.SetField(ctx, "instance_id", instanceId) wr, err := argus.CreateInstanceWaitHandler(ctx, r.client, *instanceId, projectId).SetTimeout(20 * time.Minute).WaitWithContext(ctx) if err != nil { - resp.Diagnostics.AddError("Error creating instance", fmt.Sprintf("Instance creation waiting: %v", err)) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating instance", fmt.Sprintf("Instance creation waiting: %v", err)) return } got, ok := wr.(*argus.InstanceResponse) if !ok { - resp.Diagnostics.AddError("Error creating instance", fmt.Sprintf("Wait result conversion, got %+v", got)) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating instance", fmt.Sprintf("Wait result conversion, got %+v", got)) return } - // Map response body to schema and populate Computed attribute values + // Map response body to schema err = mapFields(ctx, got, &model) if err != nil { - resp.Diagnostics.AddError("Error mapping fields", fmt.Sprintf("Project id %s, instance id %s: %v", projectId, *instanceId, err)) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating instance", fmt.Sprintf("Processing API payload: %v", err)) return } // Set state to fully populated data diags = resp.State.Set(ctx, model) resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + tflog.Info(ctx, "Argus instance created") } // Read refreshes the Terraform state with the latest data. @@ -318,22 +322,28 @@ func (r *instanceResource) Read(ctx context.Context, req resource.ReadRequest, r } projectId := model.ProjectId.ValueString() instanceId := model.InstanceId.ValueString() + ctx = tflog.SetField(ctx, "project_id", projectId) + ctx = tflog.SetField(ctx, "instance_id", instanceId) instanceResp, err := r.client.GetInstance(ctx, instanceId, projectId).Execute() if err != nil { - resp.Diagnostics.AddError("Error reading instance", fmt.Sprintf("Project id = %s, instance id = %s: %v", projectId, instanceId, err)) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading instance", fmt.Sprintf("Calling API: %v", err)) return } - // Map response body to schema and populate Computed attribute values + // Map response body to schema err = mapFields(ctx, instanceResp, &model) if err != nil { - resp.Diagnostics.AddError("Error mapping fields", fmt.Sprintf("Project id %s, instance id %s: %v", projectId, instanceId, err)) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading instance", fmt.Sprintf("Processing API payload: %v", err)) return } // Set refreshed model diags = resp.State.Set(ctx, model) resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + tflog.Info(ctx, "Argus instance created") } // Update updates the resource and sets the updated Terraform state on success. @@ -348,42 +358,46 @@ func (r *instanceResource) Update(ctx context.Context, req resource.UpdateReques projectId := model.ProjectId.ValueString() instanceId := model.InstanceId.ValueString() - r.loadPlanId(ctx, &resp.Diagnostics, &model) - if diags.HasError() { - core.LogAndAddError(ctx, &diags, "Failed to load argus service plan", "plan "+model.PlanName.ValueString()) + err := r.loadPlanId(ctx, &model) + if err != nil { + core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating instance", fmt.Sprintf("Loading service plan: %v", err)) return } // Generate API request body from model payload, err := toUpdatePayload(&model) if err != nil { - resp.Diagnostics.AddError("Error updating instance", fmt.Sprintf("Could not create API payload: %v", err)) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating instance", fmt.Sprintf("Creating API payload: %v", err)) return } // Update existing instance _, err = r.client.UpdateInstance(ctx, instanceId, projectId).UpdateInstancePayload(*payload).Execute() if err != nil { - resp.Diagnostics.AddError("Error updating instance", "project id = "+projectId+", instance Id = "+instanceId+", "+err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating instance", fmt.Sprintf("Calling API: %v", err)) return } wr, err := argus.UpdateInstanceWaitHandler(ctx, r.client, instanceId, projectId).SetTimeout(20 * time.Minute).WaitWithContext(ctx) if err != nil { - resp.Diagnostics.AddError("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 } got, ok := wr.(*argus.InstanceResponse) if !ok { - resp.Diagnostics.AddError("Error updating instance", fmt.Sprintf("Wait result conversion, got %+v", got)) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating instance", fmt.Sprintf("Wait result conversion, got %+v", got)) return } err = mapFields(ctx, got, &model) if err != nil { - resp.Diagnostics.AddError("Error mapping fields in update", "project id = "+projectId+", instance Id = "+instanceId+", "+err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating instance", fmt.Sprintf("Processing API payload: %v", err)) return } diags = resp.State.Set(ctx, model) resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + tflog.Info(ctx, "Argus instance updated") } // Delete deletes the resource and removes the Terraform state on success. @@ -402,14 +416,16 @@ func (r *instanceResource) Delete(ctx context.Context, req resource.DeleteReques // Delete existing instance _, err := r.client.DeleteInstance(ctx, instanceId, projectId).Execute() if err != nil { - resp.Diagnostics.AddError("Error deleting instance", "project id = "+projectId+", instance Id = "+instanceId+", "+err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error deleting instance", fmt.Sprintf("Calling API: %v", err)) return } _, err = argus.DeleteInstanceWaitHandler(ctx, r.client, instanceId, projectId).SetTimeout(10 * time.Minute).WaitWithContext(ctx) if err != nil { - resp.Diagnostics.AddError("Error deleting instance", fmt.Sprintf("Instance deletion waiting: %v", err)) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error deleting instance", fmt.Sprintf("Instance deletion waiting: %v", err)) return } + + tflog.Info(ctx, "Argus instance deleted") } // ImportState imports a resource into the Terraform state on success. @@ -418,8 +434,8 @@ func (r *instanceResource) ImportState(ctx context.Context, req resource.ImportS idParts := strings.Split(req.ID, core.Separator) if len(idParts) != 2 || idParts[0] == "" || idParts[1] == "" { - resp.Diagnostics.AddError( - "Unexpected Import Identifier", + core.LogAndAddError(ctx, &resp.Diagnostics, + "Unexpected import identifier", fmt.Sprintf("Expected import identifier with format: [project_id],[instance_id] Got: %q", req.ID), ) return @@ -427,6 +443,7 @@ func (r *instanceResource) ImportState(ctx context.Context, req resource.ImportS resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("project_id"), idParts[0])...) resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("instance_id"), idParts[1])...) + tflog.Info(ctx, "Argus instance state imported") } func mapFields(ctx context.Context, r *argus.InstanceResponse, model *Model) error { @@ -529,12 +546,11 @@ func toUpdatePayload(model *Model) (*argus.UpdateInstancePayload, error) { }, nil } -func (r *instanceResource) loadPlanId(ctx context.Context, diags *diag.Diagnostics, model *Model) { +func (r *instanceResource) loadPlanId(ctx context.Context, model *Model) error { projectId := model.ProjectId.ValueString() res, err := r.client.GetPlans(ctx, projectId).Execute() if err != nil { - diags.AddError("Failed to list argus plans", err.Error()) - return + return err } planName := model.PlanName.ValueString() @@ -552,7 +568,7 @@ func (r *instanceResource) loadPlanId(ctx context.Context, diags *diag.Diagnosti avl = fmt.Sprintf("%s\n- %s", avl, *p.Name) } if model.PlanId.ValueString() == "" { - diags.AddError("Invalid plan_name", fmt.Sprintf("Couldn't find plan_name '%s', available names are:%s", planName, avl)) - return + return fmt.Errorf("couldn't find plan_name '%s', available names are: %s", planName, avl) } + return nil } diff --git a/stackit/services/argus/scrapeconfig/datasource.go b/stackit/services/argus/scrapeconfig/datasource.go index e6843d21f..617e28691 100644 --- a/stackit/services/argus/scrapeconfig/datasource.go +++ b/stackit/services/argus/scrapeconfig/datasource.go @@ -37,7 +37,7 @@ func (d *scrapeConfigDataSource) Metadata(_ context.Context, req datasource.Meta resp.TypeName = req.ProviderTypeName + "_argus_scrapeconfig" } -func (d *scrapeConfigDataSource) Configure(_ context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) { +func (d *scrapeConfigDataSource) Configure(ctx context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) { // Prevent panic if the provider has not been configured. if req.ProviderData == nil { return @@ -48,7 +48,7 @@ func (d *scrapeConfigDataSource) Configure(_ context.Context, req datasource.Con providerData, ok := req.ProviderData.(core.ProviderData) if !ok { - resp.Diagnostics.AddError("Unexpected Data Source Configure Type", fmt.Sprintf("Expected stackit.ProviderData, got %T. Please report this issue to the provider developers.", req.ProviderData)) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error configuring API client", fmt.Sprintf("Expected configure type stackit.ProviderData, got %T", req.ProviderData)) return } @@ -64,10 +64,7 @@ func (d *scrapeConfigDataSource) Configure(_ context.Context, req datasource.Con ) } if err != nil { - resp.Diagnostics.AddError( - "Could not Configure API Client", - err.Error(), - ) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error configuring API client", fmt.Sprintf("Configuring client: %v", err)) return } d.client = apiClient @@ -204,13 +201,13 @@ func (d *scrapeConfigDataSource) Read(ctx context.Context, req datasource.ReadRe scResp, err := d.client.GetScrapeConfig(ctx, instanceId, scName, projectId).Execute() if err != nil { - core.LogAndAddError(ctx, &diags, "Unable to read scrape config", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Unable to read scrape config", err.Error()) return } err = mapFields(scResp.Data, &model) if err != nil { - core.LogAndAddError(ctx, &diags, "Mapping fields", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Mapping fields", err.Error()) return } diags = resp.State.Set(ctx, model) diff --git a/stackit/services/argus/scrapeconfig/resource.go b/stackit/services/argus/scrapeconfig/resource.go index 1be326369..3caa06c74 100644 --- a/stackit/services/argus/scrapeconfig/resource.go +++ b/stackit/services/argus/scrapeconfig/resource.go @@ -86,7 +86,7 @@ func (r *scrapeConfigResource) Metadata(_ context.Context, req resource.Metadata } // Configure adds the provider configured client to the resource. -func (r *scrapeConfigResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { +func (r *scrapeConfigResource) Configure(ctx context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { // Prevent panic if the provider has not been configured. if req.ProviderData == nil { return @@ -94,7 +94,7 @@ func (r *scrapeConfigResource) Configure(_ context.Context, req resource.Configu providerData, ok := req.ProviderData.(core.ProviderData) if !ok { - resp.Diagnostics.AddError("Unexpected Resource Configure Type", fmt.Sprintf("Expected stackit.ProviderData, got %T. Please report this issue to the provider developers.", req.ProviderData)) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error configuring API client", fmt.Sprintf("Expected configure type stackit.ProviderData, got %T", req.ProviderData)) return } @@ -113,10 +113,11 @@ func (r *scrapeConfigResource) Configure(_ context.Context, req resource.Configu } if err != nil { - resp.Diagnostics.AddError("Could not Configure API Client", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error configuring API client", err.Error()) return } r.client = apiClient + tflog.Info(ctx, "Argus scrape config client configured") } // Schema defines the schema for the resource. @@ -277,33 +278,36 @@ func (r *scrapeConfigResource) Create(ctx context.Context, req resource.CreateRe // Generate API request body from model payload, err := toCreatePayload(ctx, &model) if err != nil { - resp.Diagnostics.AddError("Error creating scrape config", fmt.Sprintf("Creating API payload: %v", err)) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating scrape config", fmt.Sprintf("Creating API payload: %v", err)) return } _, err = r.client.CreateScrapeConfig(ctx, instanceId, projectId).CreateScrapeConfigPayload(*payload).Execute() if err != nil { - resp.Diagnostics.AddError("Error creating scrape config", fmt.Sprintf("Calling API: %v", err)) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating scrape config", fmt.Sprintf("Calling API: %v", err)) return } _, err = argus.CreateScrapeConfigWaitHandler(ctx, r.client, instanceId, scName, projectId).SetTimeout(3 * time.Minute).WaitWithContext(ctx) if err != nil { - resp.Diagnostics.AddError("Error creating scrape config", fmt.Sprintf("ScrapeConfig creation waiting: %v", err)) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating scrape config", fmt.Sprintf("Scrape config creation waiting: %v", err)) return } got, err := r.client.GetScrapeConfig(ctx, instanceId, scName, projectId).Execute() if err != nil { - resp.Diagnostics.AddError("Error creating scrape config", fmt.Sprintf("ScrapeConfig creation waiting: %v", err)) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating scrape config", fmt.Sprintf("Calling API for updated data: %v", err)) return } err = mapFields(got.Data, &model) if err != nil { - resp.Diagnostics.AddError("Error mapping fields", fmt.Sprintf("Project id %s, ScrapeConfig id %s: %v", projectId, scName, err)) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating scrape config", fmt.Sprintf("Processing API payload: %v", err)) return } // Set state to fully populated data diags = resp.State.Set(ctx, model) resp.Diagnostics.Append(diags...) - tflog.Info(ctx, "ARGUS scrape config created") + if resp.Diagnostics.HasError() { + return + } + tflog.Info(ctx, "Argus scrape config created") } // Read refreshes the Terraform state with the latest data. @@ -320,20 +324,23 @@ func (r *scrapeConfigResource) Read(ctx context.Context, req resource.ReadReques scResp, err := r.client.GetScrapeConfig(ctx, instanceId, scName, projectId).Execute() if err != nil { - resp.Diagnostics.AddError("Error reading scrape config", fmt.Sprintf("Project id = %s, instance id = %s, scrape config name = %s: %v", projectId, instanceId, scName, err)) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading scrape config", fmt.Sprintf("Calling API: %v", err)) return } - // Map response body to schema and populate Computed attribute values + // Map response body to schema err = mapFields(scResp.Data, &model) if err != nil { - resp.Diagnostics.AddError("Error mapping fields", fmt.Sprintf("Project id = %s, instance id = %s, sc name = %s: %v", projectId, instanceId, scName, err)) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading scrape config", fmt.Sprintf("Processing API payload: %v", err)) return } // Set refreshed model diags = resp.State.Set(ctx, model) resp.Diagnostics.Append(diags...) - tflog.Info(ctx, "ARGUS scrape config read") + if resp.Diagnostics.HasError() { + return + } + tflog.Info(ctx, "Argus scrape config read") } // Update updates the resource and sets the updated Terraform state on success. @@ -352,12 +359,12 @@ func (r *scrapeConfigResource) Update(ctx context.Context, req resource.UpdateRe // Generate API request body from model payload, err := toUpdatePayload(ctx, &model) if err != nil { - resp.Diagnostics.AddError("Error updating scrape config", fmt.Sprintf("Could not create API payload: %v", err)) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating scrape config", fmt.Sprintf("Creating API payload: %v", err)) return } _, err = r.client.UpdateScrapeConfig(ctx, instanceId, scName, projectId).UpdateScrapeConfigPayload(*payload).Execute() if err != nil { - resp.Diagnostics.AddError("Error updating scrape config", fmt.Sprintf("Project id = %s, instance id = %s, scrape config name = %s: %v", projectId, instanceId, scName, err)) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating scrape config", fmt.Sprintf("Calling API: %v", err)) return } // We do not have an update status provided by the argus scrape config api, so we cannot use a waiter here, hence a simple sleep is used. @@ -366,17 +373,20 @@ func (r *scrapeConfigResource) Update(ctx context.Context, req resource.UpdateRe // Fetch updated ScrapeConfig scResp, err := r.client.GetScrapeConfig(ctx, instanceId, scName, projectId).Execute() if err != nil { - resp.Diagnostics.AddError("Error reading updated data", fmt.Sprintf("Project id %s, instance id %s, jo name %s: %v", projectId, instanceId, scName, err)) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating scrape config", fmt.Sprintf("Calling API for updated data: %v", err)) return } err = mapFields(scResp.Data, &model) if err != nil { - resp.Diagnostics.AddError("Error mapping fields in update", "project id = "+projectId+", instance id = "+instanceId+", scrape config name = "+scName+", "+err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating scrape config", fmt.Sprintf("Processing API payload: %v", err)) return } diags = resp.State.Set(ctx, model) resp.Diagnostics.Append(diags...) - tflog.Info(ctx, "ARGUS scrape config updated") + if resp.Diagnostics.HasError() { + return + } + tflog.Info(ctx, "Argus scrape config updated") } // Delete deletes the resource and removes the Terraform state on success. @@ -396,15 +406,16 @@ func (r *scrapeConfigResource) Delete(ctx context.Context, req resource.DeleteRe // Delete existing ScrapeConfig _, err := r.client.DeleteScrapeConfig(ctx, instanceId, scName, projectId).Execute() if err != nil { - resp.Diagnostics.AddError("Error deleting scrape config", "project id = "+projectId+", instance id = "+instanceId+", scrape config name = "+scName+", "+err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error deleting scrape config", fmt.Sprintf("Calling API: %v", err)) return } _, err = argus.DeleteScrapeConfigWaitHandler(ctx, r.client, instanceId, scName, projectId).SetTimeout(1 * time.Minute).WaitWithContext(ctx) if err != nil { - resp.Diagnostics.AddError("Error deleting scrape config", fmt.Sprintf("ScrapeConfig deletion waiting: %v", err)) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error deleting scrape config", fmt.Sprintf("Scrape config deletion waiting: %v", err)) return } - tflog.Info(ctx, "ARGUS scrape config deleted") + + tflog.Info(ctx, "Argus scrape config deleted") } // ImportState imports a resource into the Terraform state on success. @@ -413,8 +424,8 @@ func (r *scrapeConfigResource) ImportState(ctx context.Context, req resource.Imp idParts := strings.Split(req.ID, core.Separator) if len(idParts) != 3 || idParts[0] == "" || idParts[1] == "" || idParts[2] == "" { - resp.Diagnostics.AddError( - "Unexpected Import Identifier", + core.LogAndAddError(ctx, &resp.Diagnostics, + "Unexpected import identifier", fmt.Sprintf("Expected import identifier with format: [project_id],[instance_id],[name] Got: %q", req.ID), ) return @@ -423,7 +434,7 @@ func (r *scrapeConfigResource) ImportState(ctx context.Context, req resource.Imp resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("project_id"), idParts[0])...) resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("instance_id"), idParts[1])...) resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("name"), idParts[2])...) - tflog.Info(ctx, "ARGUS scrape config state imported") + tflog.Info(ctx, "Argus scrape config state imported") } func mapFields(sc *argus.Job, model *Model) error { diff --git a/stackit/services/dns/recordset/datasource.go b/stackit/services/dns/recordset/datasource.go index 681cb26eb..517f3cd82 100644 --- a/stackit/services/dns/recordset/datasource.go +++ b/stackit/services/dns/recordset/datasource.go @@ -44,7 +44,7 @@ func (d *recordSetDataSource) Configure(ctx context.Context, req datasource.Conf providerData, ok := req.ProviderData.(core.ProviderData) if !ok { - resp.Diagnostics.AddError("Unexpected Data Source Configure Type", fmt.Sprintf("Expected stackit.ProviderData, got %T. Please report this issue to the provider developers.", req.ProviderData)) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error configuring API client", fmt.Sprintf("Expected configure type stackit.ProviderData, got %T", req.ProviderData)) return } @@ -62,12 +62,12 @@ func (d *recordSetDataSource) Configure(ctx context.Context, req datasource.Conf } if err != nil { - resp.Diagnostics.AddError("Could not Configure API Client", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error configuring API client", fmt.Sprintf("Configuring client: %v", err)) return } - tflog.Info(ctx, "DNS record set client configured") d.client = apiClient + tflog.Info(ctx, "DNS record set client configured") } // Schema defines the schema for the data source. @@ -142,33 +142,33 @@ func (d *recordSetDataSource) Schema(_ context.Context, _ datasource.SchemaReque // Read refreshes the Terraform state with the latest data. func (d *recordSetDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { // nolint:gocritic // function signature required by Terraform - var state Model - diags := req.Config.Get(ctx, &state) + var model Model + diags := req.Config.Get(ctx, &model) resp.Diagnostics.Append(diags...) if resp.Diagnostics.HasError() { return } - projectId := state.ProjectId.ValueString() - zoneId := state.ZoneId.ValueString() - recordSetId := state.RecordSetId.ValueString() + projectId := model.ProjectId.ValueString() + zoneId := model.ZoneId.ValueString() + recordSetId := model.RecordSetId.ValueString() ctx = tflog.SetField(ctx, "project_id", projectId) ctx = tflog.SetField(ctx, "zone_id", zoneId) ctx = tflog.SetField(ctx, "record_set_id", recordSetId) zoneResp, err := d.client.GetRecordSet(ctx, projectId, zoneId, recordSetId).Execute() if err != nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Unable to Read record set", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading record set", fmt.Sprintf("Calling API: %v", err)) return } - err = mapFields(zoneResp, &state) + err = mapFields(zoneResp, &model) if err != nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Mapping fields", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading record set", fmt.Sprintf("Processing API payload: %v", err)) return } - diags = resp.State.Set(ctx, state) + diags = resp.State.Set(ctx, model) resp.Diagnostics.Append(diags...) if resp.Diagnostics.HasError() { return } - tflog.Info(ctx, "DNS record set created") + tflog.Info(ctx, "DNS record set read") } diff --git a/stackit/services/dns/recordset/resource.go b/stackit/services/dns/recordset/resource.go index 97333743a..7c183a357 100644 --- a/stackit/services/dns/recordset/resource.go +++ b/stackit/services/dns/recordset/resource.go @@ -72,7 +72,7 @@ func (r *recordSetResource) Configure(ctx context.Context, req resource.Configur providerData, ok := req.ProviderData.(core.ProviderData) if !ok { - resp.Diagnostics.AddError("Unexpected Resource Configure Type", fmt.Sprintf("Expected stackit.ProviderData, got %T. Please report this issue to the provider developers.", req.ProviderData)) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error configuring API client", fmt.Sprintf("Expected configure type stackit.ProviderData, got %T", req.ProviderData)) return } @@ -90,12 +90,12 @@ func (r *recordSetResource) Configure(ctx context.Context, req resource.Configur } if err != nil { - resp.Diagnostics.AddError("Could not Configure API Client", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error configuring API client", fmt.Sprintf("Configuring client: %v", err)) return } - tflog.Debug(ctx, "DNS record set client configured") r.client = apiClient + tflog.Info(ctx, "DNS record set client configured") } // Schema defines the schema for the resource. @@ -225,32 +225,32 @@ func (r *recordSetResource) Create(ctx context.Context, req resource.CreateReque // Generate API request body from model payload, err := toCreatePayload(&model) if err != nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating recordset", fmt.Sprintf("Creating API payload: %v", err)) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating record set", fmt.Sprintf("Creating API payload: %v", err)) return } // Create new recordset recordSetResp, err := r.client.CreateRecordSet(ctx, projectId, zoneId).CreateRecordSetPayload(*payload).Execute() if err != nil || recordSetResp.Rrset == nil || recordSetResp.Rrset.Id == nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating recordset", fmt.Sprintf("Calling API: %v", err)) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating record set", fmt.Sprintf("Calling API: %v", err)) return } ctx = tflog.SetField(ctx, "record_set_id", *recordSetResp.Rrset.Id) wr, err := dns.CreateRecordSetWaitHandler(ctx, r.client, projectId, zoneId, *recordSetResp.Rrset.Id).SetTimeout(1 * time.Minute).WaitWithContext(ctx) if err != nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating recordset", fmt.Sprintf("Instance creation waiting: %v", err)) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating record set", fmt.Sprintf("Instance creation waiting: %v", err)) return } got, ok := wr.(*dns.RecordSetResponse) if !ok { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating recordset", fmt.Sprintf("Wait result conversion, got %+v", got)) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating record set", fmt.Sprintf("Wait result conversion, got %+v", got)) return } - // Map response body to schema and populate Computed attribute values + // Map response body to schema err = mapFields(got, &model) if err != nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error mapping fields", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating record set", fmt.Sprintf("Processing API payload: %v", err)) return } // Set state to fully populated data @@ -279,14 +279,14 @@ func (r *recordSetResource) Read(ctx context.Context, req resource.ReadRequest, recordSetResp, err := r.client.GetRecordSet(ctx, projectId, zoneId, recordSetId).Execute() if err != nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading zones", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading record set", fmt.Sprintf("Calling API: %v", err)) return } - // Map response body to schema and populate Computed attribute values + // Map response body to schema err = mapFields(recordSetResp, &model) if err != nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error mapping fields", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading record set", fmt.Sprintf("Processing API payload: %v", err)) return } @@ -319,35 +319,35 @@ func (r *recordSetResource) Update(ctx context.Context, req resource.UpdateReque // Generate API request body from model payload, err := toUpdatePayload(&model) if err != nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating recordset", fmt.Sprintf("Could not create API payload: %v", err)) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating record set", fmt.Sprintf("Creating API payload: %v", err)) return } // Update recordset _, err = r.client.UpdateRecordSet(ctx, projectId, zoneId, recordSetId).UpdateRecordSetPayload(*payload).Execute() if err != nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating recordset", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating record set", err.Error()) return } wr, err := dns.UpdateRecordSetWaitHandler(ctx, r.client, projectId, zoneId, recordSetId).SetTimeout(1 * time.Minute).WaitWithContext(ctx) if err != nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating recordset", fmt.Sprintf("Instance update waiting: %v", err)) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating record set", fmt.Sprintf("Instance update waiting: %v", err)) return } got, ok := wr.(*dns.RecordSetResponse) if !ok { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating recordset", fmt.Sprintf("Wait result conversion, got %+v", got)) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating record set", fmt.Sprintf("Wait result conversion, got %+v", got)) return } // Fetch updated record set recordSetResp, err := r.client.GetRecordSet(ctx, projectId, zoneId, recordSetId).Execute() if err != nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading updated data", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating record set", fmt.Sprintf("Calling API for updated data: %v", err)) return } err = mapFields(recordSetResp, &model) if err != nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error mapping fields in update", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating record set", fmt.Sprintf("Processing API payload: %v", err)) return } diags = resp.State.Set(ctx, model) @@ -378,7 +378,7 @@ func (r *recordSetResource) Delete(ctx context.Context, req resource.DeleteReque // Delete existing record set _, err := r.client.DeleteRecordSet(ctx, projectId, zoneId, recordSetId).Execute() if err != nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error deleting recordset", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error deleting record set", fmt.Sprintf("Calling API: %v", err)) } _, err = dns.DeleteRecordSetWaitHandler(ctx, r.client, projectId, zoneId, recordSetId).SetTimeout(1 * time.Minute).WaitWithContext(ctx) if err != nil { @@ -393,8 +393,8 @@ func (r *recordSetResource) Delete(ctx context.Context, req resource.DeleteReque func (r *recordSetResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { idParts := strings.Split(req.ID, core.Separator) if len(idParts) != 3 || idParts[0] == "" || idParts[1] == "" || idParts[2] == "" { - resp.Diagnostics.AddError( - "Unexpected Import Identifier", + core.LogAndAddError(ctx, &resp.Diagnostics, + "Unexpected import identifier", fmt.Sprintf("Expected import identifier with format [project_id],[zone_id],[record_set_id], got %q", req.ID), ) return diff --git a/stackit/services/dns/zone/datasource.go b/stackit/services/dns/zone/datasource.go index 9b41f01f1..6ad7d1486 100644 --- a/stackit/services/dns/zone/datasource.go +++ b/stackit/services/dns/zone/datasource.go @@ -46,7 +46,7 @@ func (d *zoneDataSource) Configure(ctx context.Context, req datasource.Configure providerData, ok := req.ProviderData.(core.ProviderData) if !ok { - resp.Diagnostics.AddError("Unexpected Data Source Configure Type", fmt.Sprintf("Expected stackit.ProviderData, got %T. Please report this issue to the provider developers.", req.ProviderData)) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error configuring API client", fmt.Sprintf("Expected configure type stackit.ProviderData, got %T", req.ProviderData)) return } @@ -61,15 +61,12 @@ func (d *zoneDataSource) Configure(ctx context.Context, req datasource.Configure ) } if err != nil { - resp.Diagnostics.AddError( - "Could not Configure API Client", - err.Error(), - ) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error configuring API client", fmt.Sprintf("Configuring client: %v", err)) return } - tflog.Info(ctx, "DNS zone client configured") d.client = apiClient + tflog.Info(ctx, "DNS zone client configured") } // Schema defines the schema for the data source. @@ -180,29 +177,29 @@ func (d *zoneDataSource) Schema(_ context.Context, _ datasource.SchemaRequest, r // Read refreshes the Terraform state with the latest data. func (d *zoneDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { // nolint:gocritic // function signature required by Terraform - var state Model - diags := req.Config.Get(ctx, &state) + var model Model + diags := req.Config.Get(ctx, &model) resp.Diagnostics.Append(diags...) if resp.Diagnostics.HasError() { return } - projectId := state.ProjectId.ValueString() - zoneId := state.ZoneId.ValueString() + projectId := model.ProjectId.ValueString() + zoneId := model.ZoneId.ValueString() ctx = tflog.SetField(ctx, "project_id", projectId) ctx = tflog.SetField(ctx, "zone_id", zoneId) zoneResp, err := d.client.GetZone(ctx, projectId, zoneId).Execute() if err != nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Unable to Read Zone", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading zone", fmt.Sprintf("Calling API: %v", err)) return } - err = mapFields(zoneResp, &state) + err = mapFields(zoneResp, &model) if err != nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Mapping fields", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading zone", fmt.Sprintf("Processing API payload: %v", err)) return } - diags = resp.State.Set(ctx, state) + diags = resp.State.Set(ctx, model) resp.Diagnostics.Append(diags...) if resp.Diagnostics.HasError() { return diff --git a/stackit/services/dns/zone/resource.go b/stackit/services/dns/zone/resource.go index 7526fb843..0150ff371 100644 --- a/stackit/services/dns/zone/resource.go +++ b/stackit/services/dns/zone/resource.go @@ -85,7 +85,7 @@ func (r *zoneResource) Configure(ctx context.Context, req resource.ConfigureRequ providerData, ok := req.ProviderData.(core.ProviderData) if !ok { - resp.Diagnostics.AddError("Unexpected Resource Configure Type", fmt.Sprintf("Expected stackit.ProviderData, got %T. Please report this issue to the provider developers.", req.ProviderData)) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error configuring API client", fmt.Sprintf("Expected configure type stackit.ProviderData, got %T", req.ProviderData)) return } @@ -104,15 +104,12 @@ func (r *zoneResource) Configure(ctx context.Context, req resource.ConfigureRequ } if err != nil { - resp.Diagnostics.AddError("Could not Configure API Client", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error configuring API client", fmt.Sprintf("Configuring client: %v", err)) return } - tflog.Info(ctx, "DNS zone client configured") - if resp.Diagnostics.HasError() { - return - } r.client = apiClient + tflog.Info(ctx, "DNS zone client configured") } // Schema defines the schema for the resource. @@ -321,16 +318,12 @@ func (r *zoneResource) Create(ctx context.Context, req resource.CreateRequest, r core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating zone", fmt.Sprintf("Calling API: %v", err)) return } - if createResp.Zone.Id == nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating zone", "API didn't return zone id") - return - } zoneId := *createResp.Zone.Id ctx = tflog.SetField(ctx, "zone_id", zoneId) wr, err := dns.CreateZoneWaitHandler(ctx, r.client, projectId, zoneId).SetTimeout(10 * time.Minute).WaitWithContext(ctx) if err != nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating zone", fmt.Sprintf("Instance creation waiting: %v", err)) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating zone", fmt.Sprintf("Zone creation waiting: %v", err)) return } got, ok := wr.(*dns.ZoneResponse) @@ -339,10 +332,10 @@ func (r *zoneResource) Create(ctx context.Context, req resource.CreateRequest, r return } - // Map response body to schema and populate Computed attribute values + // Map response body to schema err = mapFields(got, &model) if err != nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error mapping fields", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating zone", fmt.Sprintf("Processing API payload: %v", err)) return } // Set state to fully populated data @@ -356,31 +349,31 @@ func (r *zoneResource) Create(ctx context.Context, req resource.CreateRequest, r // Read refreshes the Terraform state with the latest data. func (r *zoneResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { // nolint:gocritic // function signature required by Terraform - var state Model - diags := req.State.Get(ctx, &state) + var model Model + diags := req.State.Get(ctx, &model) resp.Diagnostics.Append(diags...) if resp.Diagnostics.HasError() { return } - projectId := state.ProjectId.ValueString() - zoneId := state.ZoneId.ValueString() + projectId := model.ProjectId.ValueString() + zoneId := model.ZoneId.ValueString() ctx = tflog.SetField(ctx, "project_id", projectId) ctx = tflog.SetField(ctx, "zone_id", zoneId) zoneResp, err := r.client.GetZone(ctx, projectId, zoneId).Execute() if err != nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading zones", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading zone", fmt.Sprintf("Calling API: %v", err)) return } - // Map response body to schema and populate Computed attribute values - err = mapFields(zoneResp, &state) + // Map response body to schema + err = mapFields(zoneResp, &model) if err != nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error mapping fields", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading zone", fmt.Sprintf("Processing API payload: %v", err)) return } // Set refreshed state - diags = resp.State.Set(ctx, state) + diags = resp.State.Set(ctx, model) resp.Diagnostics.Append(diags...) if resp.Diagnostics.HasError() { return @@ -405,18 +398,18 @@ func (r *zoneResource) Update(ctx context.Context, req resource.UpdateRequest, r // Generate API request body from model payload, err := toUpdatePayload(&model) if err != nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating zone", fmt.Sprintf("Could not create API payload: %v", err)) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating zone", fmt.Sprintf("Creating API payload: %v", err)) return } // Update existing zone _, err = r.client.UpdateZone(ctx, projectId, zoneId).UpdateZonePayload(*payload).Execute() if err != nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating zone", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating zone", fmt.Sprintf("Calling API: %v", err)) return } wr, err := dns.UpdateZoneWaitHandler(ctx, r.client, projectId, zoneId).SetTimeout(10 * time.Minute).WaitWithContext(ctx) if err != nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating zone", fmt.Sprintf("Instance update waiting: %v", err)) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating zone", fmt.Sprintf("Zone update waiting: %v", err)) return } got, ok := wr.(*dns.ZoneResponse) @@ -428,12 +421,12 @@ func (r *zoneResource) Update(ctx context.Context, req resource.UpdateRequest, r // Fetch updated zone zoneResp, err := r.client.GetZone(ctx, projectId, zoneId).Execute() if err != nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading updated data", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating zone", fmt.Sprintf("Calling API for updated data: %v", err)) return } err = mapFields(zoneResp, &model) if err != nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error mapping fields in update", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating zone", fmt.Sprintf("Processing API payload: %v", err)) return } diags = resp.State.Set(ctx, model) @@ -462,12 +455,12 @@ func (r *zoneResource) Delete(ctx context.Context, req resource.DeleteRequest, r // Delete existing zone _, err := r.client.DeleteZone(ctx, projectId, zoneId).Execute() if err != nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error deleting zone", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error deleting zone", fmt.Sprintf("Calling API: %v", err)) return } _, err = dns.DeleteZoneWaitHandler(ctx, r.client, projectId, zoneId).SetTimeout(10 * time.Minute).WaitWithContext(ctx) if err != nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error deleting zone", fmt.Sprintf("Instance deletion waiting: %v", err)) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error deleting zone", fmt.Sprintf("Zone deletion waiting: %v", err)) return } @@ -480,8 +473,8 @@ func (r *zoneResource) ImportState(ctx context.Context, req resource.ImportState idParts := strings.Split(req.ID, core.Separator) if len(idParts) != 2 || idParts[0] == "" || idParts[1] == "" { - resp.Diagnostics.AddError( - "Unexpected Import Identifier", + core.LogAndAddError(ctx, &resp.Diagnostics, + "Unexpected import identifier", fmt.Sprintf("Expected import identifier with format: [project_id],[zone_id] Got: %q", req.ID), ) return diff --git a/stackit/services/logme/credentials/datasource.go b/stackit/services/logme/credentials/datasource.go index 0bd1bb18f..d2d951e44 100644 --- a/stackit/services/logme/credentials/datasource.go +++ b/stackit/services/logme/credentials/datasource.go @@ -45,7 +45,7 @@ func (r *credentialsDataSource) Configure(ctx context.Context, req datasource.Co providerData, ok := req.ProviderData.(core.ProviderData) if !ok { - resp.Diagnostics.AddError("Unexpected Data Source Configure Type", fmt.Sprintf("Expected stackit.ProviderData, got %T. Please report this issue to the provider developers.", req.ProviderData)) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error configuring API client", fmt.Sprintf("Expected configure type stackit.ProviderData, got %T", req.ProviderData)) return } @@ -64,12 +64,12 @@ func (r *credentialsDataSource) Configure(ctx context.Context, req datasource.Co } if err != nil { - resp.Diagnostics.AddError("Could not Configure API Client", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error configuring API client", fmt.Sprintf("Configuring client: %v", err)) return } - tflog.Info(ctx, "LogMe zone client configured") r.client = apiClient + tflog.Info(ctx, "LogMe credentials client configured") } // Schema defines the schema for the resource. @@ -160,19 +160,22 @@ func (r *credentialsDataSource) Read(ctx context.Context, req datasource.ReadReq recordSetResp, err := r.client.GetCredentials(ctx, projectId, instanceId, credentialsId).Execute() if err != nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading credentials", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading credentials", fmt.Sprintf("Calling API: %v", err)) return } - // Map response body to schema and populate Computed attribute values + // Map response body to schema err = mapFields(recordSetResp, &model) if err != nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error mapping fields", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading credentials", fmt.Sprintf("Processing API payload: %v", err)) return } // Set refreshed state diags = resp.State.Set(ctx, model) resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } tflog.Info(ctx, "LogMe credentials read") } diff --git a/stackit/services/logme/credentials/resource.go b/stackit/services/logme/credentials/resource.go index db62619e2..8b33384f4 100644 --- a/stackit/services/logme/credentials/resource.go +++ b/stackit/services/logme/credentials/resource.go @@ -45,8 +45,8 @@ type Model struct { Username types.String `tfsdk:"username"` } -// NewlogmeCredentialsResource is a helper function to simplify the provider implementation. -func NewlogmeCredentialsResource() resource.Resource { +// NewCredentialsResource is a helper function to simplify the provider implementation. +func NewCredentialsResource() resource.Resource { return &logmeCredentialsResource{} } @@ -69,7 +69,7 @@ func (r *logmeCredentialsResource) Configure(ctx context.Context, req resource.C providerData, ok := req.ProviderData.(core.ProviderData) if !ok { - resp.Diagnostics.AddError("Unexpected Resource Configure Type", fmt.Sprintf("Expected stackit.ProviderData, got %T. Please report this issue to the provider developers.", req.ProviderData)) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error configuring API client", fmt.Sprintf("Expected configure type stackit.ProviderData, got %T", req.ProviderData)) return } @@ -88,12 +88,12 @@ func (r *logmeCredentialsResource) Configure(ctx context.Context, req resource.C } if err != nil { - resp.Diagnostics.AddError("Could not Configure API Client", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error configuring API client", fmt.Sprintf("Configuring client: %v", err)) return } - tflog.Info(ctx, "logme zone client configured") r.client = apiClient + tflog.Info(ctx, "LogMe credentials client configured") } // Schema defines the schema for the resource. @@ -218,14 +218,17 @@ func (r *logmeCredentialsResource) Create(ctx context.Context, req resource.Crea return } - // Map response body to schema and populate Computed attribute values + // Map response body to schema err = mapFields(got, &model) if err != nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error mapping fields", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating credentials", fmt.Sprintf("Processing API payload: %v", err)) return } diags = resp.State.Set(ctx, model) resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } tflog.Info(ctx, "LogMe credentials created") } @@ -246,27 +249,30 @@ func (r *logmeCredentialsResource) Read(ctx context.Context, req resource.ReadRe recordSetResp, err := r.client.GetCredentials(ctx, projectId, instanceId, credentialsId).Execute() if err != nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading credentials", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading credentials", fmt.Sprintf("Calling API: %v", err)) return } - // Map response body to schema and populate Computed attribute values + // Map response body to schema err = mapFields(recordSetResp, &model) if err != nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error mapping fields", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading credentials", fmt.Sprintf("Processing API payload: %v", err)) return } // Set refreshed state diags = resp.State.Set(ctx, model) resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } tflog.Info(ctx, "LogMe credentials read") } // Update updates the resource and sets the updated Terraform state on success. -func (r *logmeCredentialsResource) Update(_ context.Context, _ resource.UpdateRequest, resp *resource.UpdateResponse) { // nolint:gocritic // function signature required by Terraform +func (r *logmeCredentialsResource) Update(ctx context.Context, _ resource.UpdateRequest, resp *resource.UpdateResponse) { // nolint:gocritic // function signature required by Terraform // Update shouldn't be called - resp.Diagnostics.AddError("Error updating credentials", "credentials can't be updated") + core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating credentials", "Credentials can't be updated") } // Delete deletes the resource and removes the Terraform state on success. @@ -288,7 +294,7 @@ func (r *logmeCredentialsResource) Delete(ctx context.Context, req resource.Dele // Delete existing record set err := r.client.DeleteCredentials(ctx, projectId, instanceId, credentialsId).Execute() if err != nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error deleting credentials", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error deleting credentials", fmt.Sprintf("Calling API: %v", err)) } _, err = logme.DeleteCredentialsWaitHandler(ctx, r.client, projectId, instanceId, credentialsId).SetTimeout(1 * time.Minute).WaitWithContext(ctx) if err != nil { @@ -304,7 +310,7 @@ func (r *logmeCredentialsResource) ImportState(ctx context.Context, req resource idParts := strings.Split(req.ID, core.Separator) if len(idParts) != 3 || idParts[0] == "" || idParts[1] == "" || idParts[2] == "" { core.LogAndAddError(ctx, &resp.Diagnostics, - "Unexpected Import Identifier", + "Unexpected import identifier", fmt.Sprintf("Expected import identifier with format [project_id],[instance_id],[credentials_id], got %q", req.ID), ) return diff --git a/stackit/services/logme/instance/datasource.go b/stackit/services/logme/instance/datasource.go index 8f73c0a65..6ddc5dbd0 100644 --- a/stackit/services/logme/instance/datasource.go +++ b/stackit/services/logme/instance/datasource.go @@ -44,7 +44,7 @@ func (r *instanceDataSource) Configure(ctx context.Context, req datasource.Confi providerData, ok := req.ProviderData.(core.ProviderData) if !ok { - resp.Diagnostics.AddError("Unexpected Data Source Configure Type", fmt.Sprintf("Expected stackit.ProviderData, got %T. Please report this issue to the provider developers.", req.ProviderData)) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error configuring API client", fmt.Sprintf("Expected configure type stackit.ProviderData, got %T", req.ProviderData)) return } @@ -63,12 +63,12 @@ func (r *instanceDataSource) Configure(ctx context.Context, req datasource.Confi } if err != nil { - resp.Diagnostics.AddError("Could not Configure API Client", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error configuring API client", fmt.Sprintf("Configuring client: %v", err)) return } - tflog.Info(ctx, "LogMe zone client configured") r.client = apiClient + tflog.Info(ctx, "LogMe zone client configured") } // Schema defines the schema for the resource. @@ -152,37 +152,41 @@ func (r *instanceDataSource) Schema(_ context.Context, _ datasource.SchemaReques // 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 - var state Model - diags := req.Config.Get(ctx, &state) + var model Model + diags := req.Config.Get(ctx, &model) resp.Diagnostics.Append(diags...) if resp.Diagnostics.HasError() { return } - - projectId := state.ProjectId.ValueString() - instanceId := state.InstanceId.ValueString() + projectId := model.ProjectId.ValueString() + instanceId := model.InstanceId.ValueString() ctx = tflog.SetField(ctx, "project_id", projectId) ctx = tflog.SetField(ctx, "instance_id", instanceId) + instanceResp, err := r.client.GetInstance(ctx, projectId, instanceId).Execute() if err != nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Unable to read instance", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading instance", fmt.Sprintf("Calling API: %v", err)) return } - err = mapFields(instanceResp, &state) + err = mapFields(instanceResp, &model) if err != nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Mapping fields", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading instance", fmt.Sprintf("Processing API payload: %v", err)) return } // Compute and store values not present in the API response - loadPlanNameAndVersion(ctx, r.client, &resp.Diagnostics, &state) - if resp.Diagnostics.HasError() { + err = loadPlanNameAndVersion(ctx, r.client, &model) + if err != nil { + core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading instance", fmt.Sprintf("Loading service plan details: %v", err)) return } // Set refreshed state - diags = resp.State.Set(ctx, &state) + diags = resp.State.Set(ctx, &model) resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } tflog.Info(ctx, "LogMe instance read") } diff --git a/stackit/services/logme/instance/resource.go b/stackit/services/logme/instance/resource.go index 3a51dc402..0bf583b8c 100644 --- a/stackit/services/logme/instance/resource.go +++ b/stackit/services/logme/instance/resource.go @@ -8,7 +8,6 @@ import ( "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator" "github.com/hashicorp/terraform-plugin-framework/attr" - "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/schema/validator" "github.com/hashicorp/terraform-plugin-framework/types/basetypes" "github.com/hashicorp/terraform-plugin-log/tflog" @@ -82,7 +81,7 @@ func (r *instanceResource) Configure(ctx context.Context, req resource.Configure providerData, ok := req.ProviderData.(core.ProviderData) if !ok { - resp.Diagnostics.AddError("Unexpected Resource Configure Type", fmt.Sprintf("Expected stackit.ProviderData, got %T. Please report this issue to the provider developers.", req.ProviderData)) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error configuring API client", fmt.Sprintf("Expected configure type stackit.ProviderData, got %T", req.ProviderData)) return } @@ -101,12 +100,12 @@ func (r *instanceResource) Configure(ctx context.Context, req resource.Configure } if err != nil { - resp.Diagnostics.AddError("Could not Configure API Client", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error configuring API client", fmt.Sprintf("Configuring client: %v", err)) return } - tflog.Info(ctx, "logme zone client configured") r.client = apiClient + tflog.Info(ctx, "LogMe instance client configured") } // Schema defines the schema for the resource. @@ -233,11 +232,6 @@ func (r *instanceResource) Create(ctx context.Context, req resource.CreateReques projectId := model.ProjectId.ValueString() ctx = tflog.SetField(ctx, "project_id", projectId) - r.loadPlanId(ctx, &resp.Diagnostics, &model) - if resp.Diagnostics.HasError() { - return - } - var parameters = ¶metersModel{} if !(model.Parameters.IsNull() || model.Parameters.IsUnknown()) { diags = model.Parameters.As(ctx, parameters, basetypes.ObjectAsOptions{}) @@ -247,6 +241,12 @@ func (r *instanceResource) Create(ctx context.Context, req resource.CreateReques } } + err := r.loadPlanId(ctx, &model) + if err != nil { + core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating instance", fmt.Sprintf("Loading service plan: %v", err)) + return + } + // Generate API request body from model payload, err := toCreatePayload(&model, parameters) if err != nil { @@ -272,54 +272,69 @@ func (r *instanceResource) Create(ctx context.Context, req resource.CreateReques return } - // Map response body to schema and populate Computed attribute values + // Map response body to schema err = mapFields(got, &model) if err != nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error mapping fields", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating instance", fmt.Sprintf("Processing API payload: %v", err)) + return + } + + // Compute and store values not present in the API response + err = loadPlanNameAndVersion(ctx, r.client, &model) + if err != nil { + core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading instance", fmt.Sprintf("Loading service plan details: %v", err)) return } + // Set state to fully populated data diags = resp.State.Set(ctx, model) resp.Diagnostics.Append(diags...) - tflog.Info(ctx, "logme instance created") + if resp.Diagnostics.HasError() { + return + } + tflog.Info(ctx, "LogMe instance created") } // 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 - var state Model - diags := req.State.Get(ctx, &state) + var model Model + diags := req.State.Get(ctx, &model) resp.Diagnostics.Append(diags...) if resp.Diagnostics.HasError() { return } - projectId := state.ProjectId.ValueString() - instanceId := state.InstanceId.ValueString() + projectId := model.ProjectId.ValueString() + instanceId := model.InstanceId.ValueString() ctx = tflog.SetField(ctx, "project_id", projectId) ctx = tflog.SetField(ctx, "instance_id", instanceId) instanceResp, err := r.client.GetInstance(ctx, projectId, instanceId).Execute() if err != nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading instances", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading instance", fmt.Sprintf("Calling API: %v", err)) return } - // Map response body to schema and populate Computed attribute values - err = mapFields(instanceResp, &state) + // Map response body to schema + err = mapFields(instanceResp, &model) if err != nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error mapping fields", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading instance", fmt.Sprintf("Processing API payload: %v", err)) return } // Compute and store values not present in the API response - loadPlanNameAndVersion(ctx, r.client, &resp.Diagnostics, &state) - if resp.Diagnostics.HasError() { + err = loadPlanNameAndVersion(ctx, r.client, &model) + if err != nil { + core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading instance", fmt.Sprintf("Loading service plan details: %v", err)) return } // Set refreshed state - diags = resp.State.Set(ctx, state) + diags = resp.State.Set(ctx, model) resp.Diagnostics.Append(diags...) - tflog.Info(ctx, "logme instance read") + if resp.Diagnostics.HasError() { + return + } + tflog.Info(ctx, "LogMe instance read") } // Update updates the resource and sets the updated Terraform state on success. @@ -335,11 +350,6 @@ func (r *instanceResource) Update(ctx context.Context, req resource.UpdateReques ctx = tflog.SetField(ctx, "project_id", projectId) ctx = tflog.SetField(ctx, "instance_id", instanceId) - r.loadPlanId(ctx, &resp.Diagnostics, &model) - if resp.Diagnostics.HasError() { - return - } - var parameters = ¶metersModel{} if !(model.Parameters.IsNull() || model.Parameters.IsUnknown()) { diags = model.Parameters.As(ctx, parameters, basetypes.ObjectAsOptions{}) @@ -349,16 +359,22 @@ func (r *instanceResource) Update(ctx context.Context, req resource.UpdateReques } } + err := r.loadPlanId(ctx, &model) + if err != nil { + core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating instance", fmt.Sprintf("Loading service plan: %v", err)) + return + } + // Generate API request body from model payload, err := toUpdatePayload(&model, parameters) if err != nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating instance", fmt.Sprintf("Could not create API payload: %v", err)) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating instance", fmt.Sprintf("Creating API payload: %v", err)) return } // Update existing instance err = r.client.UpdateInstance(ctx, projectId, instanceId).UpdateInstancePayload(*payload).Execute() if err != nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating instance", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating instance", fmt.Sprintf("Calling API: %v", err)) return } wr, err := logme.UpdateInstanceWaitHandler(ctx, r.client, projectId, instanceId).SetTimeout(15 * time.Minute).WaitWithContext(ctx) @@ -372,15 +388,26 @@ func (r *instanceResource) Update(ctx context.Context, req resource.UpdateReques return } - // Map response body to schema and populate Computed attribute values + // Map response body to schema err = mapFields(got, &model) if err != nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error mapping fields in update", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating instance", fmt.Sprintf("Processing API payload: %v", err)) return } + + // Compute and store values not present in the API response + err = loadPlanNameAndVersion(ctx, r.client, &model) + if err != nil { + core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading instance", fmt.Sprintf("Loading service plan details: %v", err)) + return + } + diags = resp.State.Set(ctx, model) resp.Diagnostics.Append(diags...) - tflog.Info(ctx, "logme instance updated") + if resp.Diagnostics.HasError() { + return + } + tflog.Info(ctx, "LogMe instance updated") } // Delete deletes the resource and removes the Terraform state on success. @@ -400,7 +427,7 @@ func (r *instanceResource) Delete(ctx context.Context, req resource.DeleteReques // Delete existing instance err := r.client.DeleteInstance(ctx, projectId, instanceId).Execute() if err != nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error deleting instance", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error deleting instance", fmt.Sprintf("Calling API: %v", err)) return } _, err = logme.DeleteInstanceWaitHandler(ctx, r.client, projectId, instanceId).SetTimeout(15 * time.Minute).WaitWithContext(ctx) @@ -408,7 +435,7 @@ func (r *instanceResource) Delete(ctx context.Context, req resource.DeleteReques core.LogAndAddError(ctx, &resp.Diagnostics, "Error deleting instance", fmt.Sprintf("Instance deletion waiting: %v", err)) return } - tflog.Info(ctx, "logme instance deleted") + tflog.Info(ctx, "LogMe instance deleted") } // ImportState imports a resource into the Terraform state on success. @@ -417,8 +444,8 @@ func (r *instanceResource) ImportState(ctx context.Context, req resource.ImportS idParts := strings.Split(req.ID, core.Separator) if len(idParts) != 2 || idParts[0] == "" || idParts[1] == "" { - resp.Diagnostics.AddError( - "Unexpected Import Identifier", + core.LogAndAddError(ctx, &resp.Diagnostics, + "Unexpected import identifier", fmt.Sprintf("Expected import identifier with format: [project_id],[instance_id] Got: %q", req.ID), ) return @@ -608,12 +635,11 @@ func toUpdatePayload(model *Model, parameters *parametersModel) (*logme.UpdateIn }, nil } -func (r *instanceResource) loadPlanId(ctx context.Context, diags *diag.Diagnostics, model *Model) { +func (r *instanceResource) loadPlanId(ctx context.Context, model *Model) error { projectId := model.ProjectId.ValueString() res, err := r.client.GetOfferings(ctx, projectId).Execute() if err != nil { - diags.AddError("Failed to list LogMe offerings", err.Error()) - return + return fmt.Errorf("getting LogMe offerings: %v", err) } version := model.Version.ValueString() @@ -634,26 +660,24 @@ func (r *instanceResource) loadPlanId(ctx context.Context, diags *diag.Diagnosti } if strings.EqualFold(*plan.Name, planName) && plan.Id != nil { model.PlanId = types.StringPointerValue(plan.Id) - return + return nil } availablePlanNames = fmt.Sprintf("%s\n- %s", availablePlanNames, *plan.Name) } } if !isValidVersion { - diags.AddError("Invalid version", fmt.Sprintf("Couldn't find version '%s', available versions are:%s", version, availableVersions)) - return + return fmt.Errorf("couldn't find version '%s', available versions are: %s", version, availableVersions) } - diags.AddError("Invalid plan_name", fmt.Sprintf("Couldn't find plan_name '%s' for version %s, available names are:%s", planName, version, availablePlanNames)) + return fmt.Errorf("couldn't find plan_name '%s' for version %s, available names are: %s", planName, version, availablePlanNames) } -func loadPlanNameAndVersion(ctx context.Context, client *logme.APIClient, diags *diag.Diagnostics, model *Model) { +func loadPlanNameAndVersion(ctx context.Context, client *logme.APIClient, model *Model) error { projectId := model.ProjectId.ValueString() planId := model.PlanId.ValueString() res, err := client.GetOfferings(ctx, projectId).Execute() if err != nil { - diags.AddError("Failed to list LogMe offerings", err.Error()) - return + return fmt.Errorf("getting LogMe offerings: %v", err) } for _, offer := range *res.Offerings { @@ -661,10 +685,10 @@ func loadPlanNameAndVersion(ctx context.Context, client *logme.APIClient, diags if strings.EqualFold(*plan.Id, planId) && plan.Id != nil { model.PlanName = types.StringPointerValue(plan.Name) model.Version = types.StringPointerValue(offer.Version) - return + return nil } } } - diags.AddWarning("Failed to get plan_name and version", fmt.Sprintf("Couldn't find plan_name and version for plan_id = %s", planId)) + return fmt.Errorf("couldn't find plan_name and version for plan_id '%s'", planId) } diff --git a/stackit/services/mariadb/credentials/datasource.go b/stackit/services/mariadb/credentials/datasource.go index de7974c0b..f8014670e 100644 --- a/stackit/services/mariadb/credentials/datasource.go +++ b/stackit/services/mariadb/credentials/datasource.go @@ -45,7 +45,7 @@ func (r *credentialsDataSource) Configure(ctx context.Context, req datasource.Co providerData, ok := req.ProviderData.(core.ProviderData) if !ok { - resp.Diagnostics.AddError("Unexpected Data Source Configure Type", fmt.Sprintf("Expected stackit.ProviderData, got %T. Please report this issue to the provider developers.", req.ProviderData)) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error configuring API client", fmt.Sprintf("Expected configure type stackit.ProviderData, got %T", req.ProviderData)) return } @@ -64,21 +64,21 @@ func (r *credentialsDataSource) Configure(ctx context.Context, req datasource.Co } if err != nil { - resp.Diagnostics.AddError("Could not Configure API Client", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error configuring API client", fmt.Sprintf("Configuring client: %v", err)) return } - tflog.Info(ctx, "Postgresql zone client configured") r.client = apiClient + tflog.Info(ctx, "mariadb credentials client configured") } // Schema defines the schema for the resource. func (r *credentialsDataSource) Schema(_ context.Context, _ datasource.SchemaRequest, resp *datasource.SchemaResponse) { descriptions := map[string]string{ - "main": "MariaDB credentials data source schema.", - "id": "Terraform's internal resource ID. It is structured as \"`project_id`,`instance_id`,`credentials_id`\".", + "main": "mariadb credentials data source schema.", + "id": "Terraform's internal resource identifier. It is structured as \"`project_id`,`instance_id`,`credentials_id`\".", "credentials_id": "The credentials ID.", - "instance_id": "ID of the MariaDB instance.", + "instance_id": "ID of the mariadb instance.", "project_id": "STACKIT project ID to which the instance is associated.", } @@ -160,19 +160,22 @@ func (r *credentialsDataSource) Read(ctx context.Context, req datasource.ReadReq recordSetResp, err := r.client.GetCredentials(ctx, projectId, instanceId, credentialsId).Execute() if err != nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading credentials", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading credentials", fmt.Sprintf("Calling API: %v", err)) return } - // Map response body to schema and populate Computed attribute values + // Map response body to schema err = mapFields(recordSetResp, &model) if err != nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error mapping fields", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading credentials", fmt.Sprintf("Processing API payload: %v", err)) return } // Set refreshed state diags = resp.State.Set(ctx, model) resp.Diagnostics.Append(diags...) - tflog.Info(ctx, "MariaDB credentials read") + if resp.Diagnostics.HasError() { + return + } + tflog.Info(ctx, "mariadb credentials read") } diff --git a/stackit/services/mariadb/credentials/resource.go b/stackit/services/mariadb/credentials/resource.go index 9ee5092c0..745abd375 100644 --- a/stackit/services/mariadb/credentials/resource.go +++ b/stackit/services/mariadb/credentials/resource.go @@ -25,9 +25,9 @@ import ( // Ensure the implementation satisfies the expected interfaces. var ( - _ resource.Resource = &mariaDBCredentialsResource{} - _ resource.ResourceWithConfigure = &mariaDBCredentialsResource{} - _ resource.ResourceWithImportState = &mariaDBCredentialsResource{} + _ resource.Resource = &mariadbCredentialsResource{} + _ resource.ResourceWithConfigure = &mariadbCredentialsResource{} + _ resource.ResourceWithImportState = &mariadbCredentialsResource{} ) type Model struct { @@ -45,23 +45,23 @@ type Model struct { Username types.String `tfsdk:"username"` } -// NewPostgreSQLCredentialsResource is a helper function to simplify the provider implementation. +// NewCredentialsResource is a helper function to simplify the provider implementation. func NewCredentialsResource() resource.Resource { - return &mariaDBCredentialsResource{} + return &mariadbCredentialsResource{} } // credentialsResource is the resource implementation. -type mariaDBCredentialsResource struct { +type mariadbCredentialsResource struct { client *mariadb.APIClient } // Metadata returns the resource type name. -func (r *mariaDBCredentialsResource) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { +func (r *mariadbCredentialsResource) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { resp.TypeName = req.ProviderTypeName + "_mariadb_credentials" } // Configure adds the provider configured client to the resource. -func (r *mariaDBCredentialsResource) Configure(ctx context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { +func (r *mariadbCredentialsResource) Configure(ctx context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { // Prevent panic if the provider has not been configured. if req.ProviderData == nil { return @@ -69,7 +69,7 @@ func (r *mariaDBCredentialsResource) Configure(ctx context.Context, req resource providerData, ok := req.ProviderData.(core.ProviderData) if !ok { - resp.Diagnostics.AddError("Unexpected Resource Configure Type", fmt.Sprintf("Expected stackit.ProviderData, got %T. Please report this issue to the provider developers.", req.ProviderData)) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error configuring API client", fmt.Sprintf("Expected configure type stackit.ProviderData, got %T", req.ProviderData)) return } @@ -88,19 +88,19 @@ func (r *mariaDBCredentialsResource) Configure(ctx context.Context, req resource } if err != nil { - resp.Diagnostics.AddError("Could not Configure API Client", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error configuring API client", fmt.Sprintf("Configuring client: %v", err)) return } - tflog.Info(ctx, "MariaDB client configured") r.client = apiClient + tflog.Info(ctx, "MariaDB credentials client configured") } // Schema defines the schema for the resource. -func (r *mariaDBCredentialsResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) { +func (r *mariadbCredentialsResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) { descriptions := map[string]string{ "main": "MariaDB credentials resource schema.", - "id": "Terraform's internal resource ID. It is structured as \"`project_id`,`instance_id`,`credentials_id`\".", + "id": "Terraform's internal resource identifier. It is structured as \"`project_id`,`instance_id`,`credentials_id`\".", "credentials_id": "The credentials ID.", "instance_id": "ID of the MariaDB instance.", "project_id": "STACKIT Project ID to which the instance is associated.", @@ -182,7 +182,7 @@ func (r *mariaDBCredentialsResource) Schema(_ context.Context, _ resource.Schema } // Create creates the resource and sets the initial Terraform state. -func (r *mariaDBCredentialsResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { // nolint:gocritic // function signature required by Terraform +func (r *mariadbCredentialsResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { // nolint:gocritic // function signature required by Terraform var model Model diags := req.Plan.Get(ctx, &model) resp.Diagnostics.Append(diags...) @@ -218,19 +218,22 @@ func (r *mariaDBCredentialsResource) Create(ctx context.Context, req resource.Cr return } - // Map response body to schema and populate Computed attribute values + // Map response body to schema err = mapFields(got, &model) if err != nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error mapping fields", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating credentials", fmt.Sprintf("Processing API payload: %v", err)) return } diags = resp.State.Set(ctx, model) resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } tflog.Info(ctx, "MariaDB credentials created") } // Read refreshes the Terraform state with the latest data. -func (r *mariaDBCredentialsResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { // nolint:gocritic // function signature required by Terraform +func (r *mariadbCredentialsResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { // nolint:gocritic // function signature required by Terraform var model Model diags := req.State.Get(ctx, &model) resp.Diagnostics.Append(diags...) @@ -246,31 +249,34 @@ func (r *mariaDBCredentialsResource) Read(ctx context.Context, req resource.Read recordSetResp, err := r.client.GetCredentials(ctx, projectId, instanceId, credentialsId).Execute() if err != nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading credentials", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading credentials", fmt.Sprintf("Calling API: %v", err)) return } - // Map response body to schema and populate Computed attribute values + // Map response body to schema err = mapFields(recordSetResp, &model) if err != nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error mapping fields", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading credentials", fmt.Sprintf("Processing API payload: %v", err)) return } // Set refreshed state diags = resp.State.Set(ctx, model) resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } tflog.Info(ctx, "MariaDB credentials read") } // Update updates the resource and sets the updated Terraform state on success. -func (r *mariaDBCredentialsResource) Update(_ context.Context, _ resource.UpdateRequest, resp *resource.UpdateResponse) { // nolint:gocritic // function signature required by Terraform +func (r *mariadbCredentialsResource) Update(ctx context.Context, _ resource.UpdateRequest, resp *resource.UpdateResponse) { // nolint:gocritic // function signature required by Terraform // Update shouldn't be called - resp.Diagnostics.AddError("Error updating credentials", "credentials can't be updated") + core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating credentials", "Credentials can't be updated") } // Delete deletes the resource and removes the Terraform state on success. -func (r *mariaDBCredentialsResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { // nolint:gocritic // function signature required by Terraform +func (r *mariadbCredentialsResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { // nolint:gocritic // function signature required by Terraform var model Model diags := req.State.Get(ctx, &model) resp.Diagnostics.Append(diags...) @@ -288,7 +294,7 @@ func (r *mariaDBCredentialsResource) Delete(ctx context.Context, req resource.De // Delete existing record set err := r.client.DeleteCredentials(ctx, projectId, instanceId, credentialsId).Execute() if err != nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error deleting credentials", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error deleting credentials", fmt.Sprintf("Calling API: %v", err)) } _, err = mariadb.DeleteCredentialsWaitHandler(ctx, r.client, projectId, instanceId, credentialsId).SetTimeout(1 * time.Minute).WaitWithContext(ctx) if err != nil { @@ -299,12 +305,12 @@ func (r *mariaDBCredentialsResource) Delete(ctx context.Context, req resource.De } // ImportState imports a resource into the Terraform state on success. -// The expected format of the resource import identifier is: project_id,instance_id,credentials_id -func (r *mariaDBCredentialsResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { +// The expected format of the resource import identifier is: project_id,instance_id,credentials_id +func (r *mariadbCredentialsResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { idParts := strings.Split(req.ID, core.Separator) if len(idParts) != 3 || idParts[0] == "" || idParts[1] == "" || idParts[2] == "" { core.LogAndAddError(ctx, &resp.Diagnostics, - "Unexpected Import Identifier", + "Unexpected import identifier", fmt.Sprintf("Expected import identifier with format [project_id],[instance_id],[credentials_id], got %q", req.ID), ) return @@ -313,7 +319,7 @@ func (r *mariaDBCredentialsResource) ImportState(ctx context.Context, req resour resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("project_id"), idParts[0])...) resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("instance_id"), idParts[1])...) resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("credentials_id"), idParts[2])...) - tflog.Info(ctx, "Postgresql credentials state imported") + tflog.Info(ctx, "MariaDB credentials state imported") } func mapFields(credentialsResp *mariadb.CredentialsResponse, model *Model) error { diff --git a/stackit/services/mariadb/instance/datasource.go b/stackit/services/mariadb/instance/datasource.go index 9d24b20b1..b8d77867b 100644 --- a/stackit/services/mariadb/instance/datasource.go +++ b/stackit/services/mariadb/instance/datasource.go @@ -44,7 +44,7 @@ func (r *instanceDataSource) Configure(ctx context.Context, req datasource.Confi providerData, ok := req.ProviderData.(core.ProviderData) if !ok { - resp.Diagnostics.AddError("Unexpected Data Source Configure Type", fmt.Sprintf("Expected stackit.ProviderData, got %T. Please report this issue to the provider developers.", req.ProviderData)) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error configuring API client", fmt.Sprintf("Expected configure type stackit.ProviderData, got %T", req.ProviderData)) return } @@ -63,19 +63,19 @@ func (r *instanceDataSource) Configure(ctx context.Context, req datasource.Confi } if err != nil { - resp.Diagnostics.AddError("Could not Configure API Client", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error configuring API client", fmt.Sprintf("Configuring client: %v", err)) return } - tflog.Info(ctx, "MariaDB zone client configured") r.client = apiClient + tflog.Info(ctx, "MariaDB zone client configured") } // Schema defines the schema for the resource. func (r *instanceDataSource) Schema(_ context.Context, _ datasource.SchemaRequest, resp *datasource.SchemaResponse) { descriptions := map[string]string{ "main": "MariaDB instance data source schema.", - "id": "Terraform's internal resource ID. It is structured as \"`project_id`,`instance_id`\".", + "id": "Terraform's internal resource identifier. It is structured as \"`project_id`,`zone_id`\".", "instance_id": "ID of the MariaDB instance.", "project_id": "STACKIT Project ID to which the instance is associated.", "name": "Instance name.", @@ -152,37 +152,41 @@ func (r *instanceDataSource) Schema(_ context.Context, _ datasource.SchemaReques // 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 - var state Model - diags := req.Config.Get(ctx, &state) + var model Model + diags := req.Config.Get(ctx, &model) resp.Diagnostics.Append(diags...) if resp.Diagnostics.HasError() { return } - - projectId := state.ProjectId.ValueString() - instanceId := state.InstanceId.ValueString() + projectId := model.ProjectId.ValueString() + instanceId := model.InstanceId.ValueString() ctx = tflog.SetField(ctx, "project_id", projectId) ctx = tflog.SetField(ctx, "instance_id", instanceId) + instanceResp, err := r.client.GetInstance(ctx, projectId, instanceId).Execute() if err != nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Unable to read instance", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading instance", fmt.Sprintf("Calling API: %v", err)) return } - err = mapFields(instanceResp, &state) + err = mapFields(instanceResp, &model) if err != nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Mapping fields", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading instance", fmt.Sprintf("Processing API payload: %v", err)) return } // Compute and store values not present in the API response - loadPlanNameAndVersion(ctx, r.client, &resp.Diagnostics, &state) - if resp.Diagnostics.HasError() { + err = loadPlanNameAndVersion(ctx, r.client, &model) + if err != nil { + core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading instance", fmt.Sprintf("Loading service plan details: %v", err)) return } // Set refreshed state - diags = resp.State.Set(ctx, &state) + diags = resp.State.Set(ctx, &model) resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } tflog.Info(ctx, "MariaDB instance read") } diff --git a/stackit/services/mariadb/instance/resource.go b/stackit/services/mariadb/instance/resource.go index d2d9d63b3..cfbf870bf 100644 --- a/stackit/services/mariadb/instance/resource.go +++ b/stackit/services/mariadb/instance/resource.go @@ -8,7 +8,6 @@ import ( "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator" "github.com/hashicorp/terraform-plugin-framework/attr" - "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/schema/validator" "github.com/hashicorp/terraform-plugin-framework/types/basetypes" "github.com/hashicorp/terraform-plugin-log/tflog" @@ -82,7 +81,7 @@ func (r *instanceResource) Configure(ctx context.Context, req resource.Configure providerData, ok := req.ProviderData.(core.ProviderData) if !ok { - resp.Diagnostics.AddError("Unexpected Resource Configure Type", fmt.Sprintf("Expected stackit.ProviderData, got %T. Please report this issue to the provider developers.", req.ProviderData)) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error configuring API client", fmt.Sprintf("Expected configure type stackit.ProviderData, got %T", req.ProviderData)) return } @@ -101,12 +100,12 @@ func (r *instanceResource) Configure(ctx context.Context, req resource.Configure } if err != nil { - resp.Diagnostics.AddError("Could not Configure API Client", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error configuring API client", fmt.Sprintf("Configuring client: %v", err)) return } - tflog.Info(ctx, "mariadb zone client configured") r.client = apiClient + tflog.Info(ctx, "MariaDB instance client configured") } // Schema defines the schema for the resource. @@ -128,6 +127,9 @@ func (r *instanceResource) Schema(_ context.Context, _ resource.SchemaRequest, r "id": schema.StringAttribute{ Description: descriptions["id"], Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, }, "instance_id": schema.StringAttribute{ Description: descriptions["instance_id"], @@ -187,18 +189,33 @@ func (r *instanceResource) Schema(_ context.Context, _ resource.SchemaRequest, r }, "cf_guid": schema.StringAttribute{ Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, }, "cf_space_guid": schema.StringAttribute{ Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, }, "dashboard_url": schema.StringAttribute{ Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, }, "image_url": schema.StringAttribute{ Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, }, "cf_organization_guid": schema.StringAttribute{ Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, }, }, } @@ -215,11 +232,6 @@ func (r *instanceResource) Create(ctx context.Context, req resource.CreateReques projectId := model.ProjectId.ValueString() ctx = tflog.SetField(ctx, "project_id", projectId) - r.loadPlanId(ctx, &resp.Diagnostics, &model) - if resp.Diagnostics.HasError() { - return - } - var parameters = ¶metersModel{} if !(model.Parameters.IsNull() || model.Parameters.IsUnknown()) { diags = model.Parameters.As(ctx, parameters, basetypes.ObjectAsOptions{}) @@ -229,6 +241,12 @@ func (r *instanceResource) Create(ctx context.Context, req resource.CreateReques } } + err := r.loadPlanId(ctx, &model) + if err != nil { + core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating instance", fmt.Sprintf("Loading service plan: %v", err)) + return + } + // Generate API request body from model payload, err := toCreatePayload(&model, parameters) if err != nil { @@ -254,54 +272,69 @@ func (r *instanceResource) Create(ctx context.Context, req resource.CreateReques return } - // Map response body to schema and populate Computed attribute values + // Map response body to schema err = mapFields(got, &model) if err != nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error mapping fields", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating instance", fmt.Sprintf("Processing API payload: %v", err)) + return + } + + // Compute and store values not present in the API response + err = loadPlanNameAndVersion(ctx, r.client, &model) + if err != nil { + core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading instance", fmt.Sprintf("Loading service plan details: %v", err)) return } + // Set state to fully populated data diags = resp.State.Set(ctx, model) resp.Diagnostics.Append(diags...) - tflog.Info(ctx, "mariadb instance created") + if resp.Diagnostics.HasError() { + return + } + tflog.Info(ctx, "MariaDB instance created") } // 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 - var state Model - diags := req.State.Get(ctx, &state) + var model Model + diags := req.State.Get(ctx, &model) resp.Diagnostics.Append(diags...) if resp.Diagnostics.HasError() { return } - projectId := state.ProjectId.ValueString() - instanceId := state.InstanceId.ValueString() + projectId := model.ProjectId.ValueString() + instanceId := model.InstanceId.ValueString() ctx = tflog.SetField(ctx, "project_id", projectId) ctx = tflog.SetField(ctx, "instance_id", instanceId) instanceResp, err := r.client.GetInstance(ctx, projectId, instanceId).Execute() if err != nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading instances", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading instance", fmt.Sprintf("Calling API: %v", err)) return } - // Map response body to schema and populate Computed attribute values - err = mapFields(instanceResp, &state) + // Map response body to schema + err = mapFields(instanceResp, &model) if err != nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error mapping fields", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading instance", fmt.Sprintf("Processing API payload: %v", err)) return } // Compute and store values not present in the API response - loadPlanNameAndVersion(ctx, r.client, &resp.Diagnostics, &state) - if resp.Diagnostics.HasError() { + err = loadPlanNameAndVersion(ctx, r.client, &model) + if err != nil { + core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading instance", fmt.Sprintf("Loading service plan details: %v", err)) return } // Set refreshed state - diags = resp.State.Set(ctx, state) + diags = resp.State.Set(ctx, model) resp.Diagnostics.Append(diags...) - tflog.Info(ctx, "mariadb instance read") + if resp.Diagnostics.HasError() { + return + } + tflog.Info(ctx, "MariaDB instance read") } // Update updates the resource and sets the updated Terraform state on success. @@ -317,11 +350,6 @@ func (r *instanceResource) Update(ctx context.Context, req resource.UpdateReques ctx = tflog.SetField(ctx, "project_id", projectId) ctx = tflog.SetField(ctx, "instance_id", instanceId) - r.loadPlanId(ctx, &resp.Diagnostics, &model) - if resp.Diagnostics.HasError() { - return - } - var parameters = ¶metersModel{} if !(model.Parameters.IsNull() || model.Parameters.IsUnknown()) { diags = model.Parameters.As(ctx, parameters, basetypes.ObjectAsOptions{}) @@ -331,16 +359,22 @@ func (r *instanceResource) Update(ctx context.Context, req resource.UpdateReques } } + err := r.loadPlanId(ctx, &model) + if err != nil { + core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating instance", fmt.Sprintf("Loading service plan: %v", err)) + return + } + // Generate API request body from model payload, err := toUpdatePayload(&model, parameters) if err != nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating instance", fmt.Sprintf("Could not create API payload: %v", err)) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating instance", fmt.Sprintf("Creating API payload: %v", err)) return } // Update existing instance err = r.client.UpdateInstance(ctx, projectId, instanceId).UpdateInstancePayload(*payload).Execute() if err != nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating instance", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating instance", fmt.Sprintf("Calling API: %v", err)) return } wr, err := mariadb.UpdateInstanceWaitHandler(ctx, r.client, projectId, instanceId).SetTimeout(15 * time.Minute).WaitWithContext(ctx) @@ -354,19 +388,31 @@ func (r *instanceResource) Update(ctx context.Context, req resource.UpdateReques return } - // Map response body to schema and populate Computed attribute values + // Map response body to schema err = mapFields(got, &model) if err != nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error mapping fields in update", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating instance", fmt.Sprintf("Processing API payload: %v", err)) + return + } + + // Compute and store values not present in the API response + err = loadPlanNameAndVersion(ctx, r.client, &model) + if err != nil { + core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading instance", fmt.Sprintf("Loading service plan details: %v", err)) return } + diags = resp.State.Set(ctx, model) resp.Diagnostics.Append(diags...) - tflog.Info(ctx, "mariadb instance updated") + if resp.Diagnostics.HasError() { + return + } + tflog.Info(ctx, "MariaDB instance updated") } // 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 + // Retrieve values from state var model Model diags := req.State.Get(ctx, &model) resp.Diagnostics.Append(diags...) @@ -381,7 +427,7 @@ func (r *instanceResource) Delete(ctx context.Context, req resource.DeleteReques // Delete existing instance err := r.client.DeleteInstance(ctx, projectId, instanceId).Execute() if err != nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error deleting instance", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error deleting instance", fmt.Sprintf("Calling API: %v", err)) return } _, err = mariadb.DeleteInstanceWaitHandler(ctx, r.client, projectId, instanceId).SetTimeout(15 * time.Minute).WaitWithContext(ctx) @@ -389,7 +435,7 @@ func (r *instanceResource) Delete(ctx context.Context, req resource.DeleteReques core.LogAndAddError(ctx, &resp.Diagnostics, "Error deleting instance", fmt.Sprintf("Instance deletion waiting: %v", err)) return } - tflog.Info(ctx, "mariadb instance deleted") + tflog.Info(ctx, "MariaDB instance deleted") } // ImportState imports a resource into the Terraform state on success. @@ -398,8 +444,8 @@ func (r *instanceResource) ImportState(ctx context.Context, req resource.ImportS idParts := strings.Split(req.ID, core.Separator) if len(idParts) != 2 || idParts[0] == "" || idParts[1] == "" { - resp.Diagnostics.AddError( - "Unexpected Import Identifier", + core.LogAndAddError(ctx, &resp.Diagnostics, + "Unexpected import identifier", fmt.Sprintf("Expected import identifier with format: [project_id],[instance_id] Got: %q", req.ID), ) return @@ -589,12 +635,11 @@ func toUpdatePayload(model *Model, parameters *parametersModel) (*mariadb.Update }, nil } -func (r *instanceResource) loadPlanId(ctx context.Context, diags *diag.Diagnostics, model *Model) { +func (r *instanceResource) loadPlanId(ctx context.Context, model *Model) error { projectId := model.ProjectId.ValueString() res, err := r.client.GetOfferings(ctx, projectId).Execute() if err != nil { - diags.AddError("Failed to list MariaDB offerings", err.Error()) - return + return fmt.Errorf("getting MariaDB offerings: %v", err) } version := model.Version.ValueString() @@ -615,26 +660,24 @@ func (r *instanceResource) loadPlanId(ctx context.Context, diags *diag.Diagnosti } if strings.EqualFold(*plan.Name, planName) && plan.Id != nil { model.PlanId = types.StringPointerValue(plan.Id) - return + return nil } availablePlanNames = fmt.Sprintf("%s\n- %s", availablePlanNames, *plan.Name) } } if !isValidVersion { - diags.AddError("Invalid version", fmt.Sprintf("Couldn't find version '%s', available versions are:%s", version, availableVersions)) - return + return fmt.Errorf("couldn't find version '%s', available versions are: %s", version, availableVersions) } - diags.AddError("Invalid plan_name", fmt.Sprintf("Couldn't find plan_name '%s' for version %s, available names are:%s", planName, version, availablePlanNames)) + return fmt.Errorf("couldn't find plan_name '%s' for version %s, available names are: %s", planName, version, availablePlanNames) } -func loadPlanNameAndVersion(ctx context.Context, client *mariadb.APIClient, diags *diag.Diagnostics, model *Model) { +func loadPlanNameAndVersion(ctx context.Context, client *mariadb.APIClient, model *Model) error { projectId := model.ProjectId.ValueString() planId := model.PlanId.ValueString() res, err := client.GetOfferings(ctx, projectId).Execute() if err != nil { - diags.AddError("Failed to list MariaDB offerings", err.Error()) - return + return fmt.Errorf("getting MariaDB offerings: %v", err) } for _, offer := range *res.Offerings { @@ -642,10 +685,10 @@ func loadPlanNameAndVersion(ctx context.Context, client *mariadb.APIClient, diag if strings.EqualFold(*plan.Id, planId) && plan.Id != nil { model.PlanName = types.StringPointerValue(plan.Name) model.Version = types.StringPointerValue(offer.Version) - return + return nil } } } - diags.AddWarning("Failed to get plan_name and version", fmt.Sprintf("Couldn't find plan_name and version for plan_id = %s", planId)) + return fmt.Errorf("couldn't find plan_name and version for plan_id '%s'", planId) } diff --git a/stackit/services/opensearch/credentials/datasource.go b/stackit/services/opensearch/credentials/datasource.go index a9010a3b9..007473934 100644 --- a/stackit/services/opensearch/credentials/datasource.go +++ b/stackit/services/opensearch/credentials/datasource.go @@ -45,7 +45,7 @@ func (r *credentialsDataSource) Configure(ctx context.Context, req datasource.Co providerData, ok := req.ProviderData.(core.ProviderData) if !ok { - resp.Diagnostics.AddError("Unexpected Data Source Configure Type", fmt.Sprintf("Expected stackit.ProviderData, got %T. Please report this issue to the provider developers.", req.ProviderData)) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error configuring API client", fmt.Sprintf("Expected configure type stackit.ProviderData, got %T", req.ProviderData)) return } @@ -64,12 +64,12 @@ func (r *credentialsDataSource) Configure(ctx context.Context, req datasource.Co } if err != nil { - resp.Diagnostics.AddError("Could not Configure API Client", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error configuring API client", fmt.Sprintf("Configuring client: %v", err)) return } - tflog.Info(ctx, "Postgresql zone client configured") r.client = apiClient + tflog.Info(ctx, "OpenSearch credentials client configured") } // Schema defines the schema for the resource. @@ -160,19 +160,22 @@ func (r *credentialsDataSource) Read(ctx context.Context, req datasource.ReadReq recordSetResp, err := r.client.GetCredentials(ctx, projectId, instanceId, credentialsId).Execute() if err != nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading credentials", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading credentials", fmt.Sprintf("Calling API: %v", err)) return } - // Map response body to schema and populate Computed attribute values + // Map response body to schema err = mapFields(recordSetResp, &model) if err != nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error mapping fields", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading credentials", fmt.Sprintf("Processing API payload: %v", err)) return } // Set refreshed state diags = resp.State.Set(ctx, model) resp.Diagnostics.Append(diags...) - tflog.Info(ctx, "Postgresql credentials read") + if resp.Diagnostics.HasError() { + return + } + tflog.Info(ctx, "OpenSearch credentials read") } diff --git a/stackit/services/opensearch/credentials/resource.go b/stackit/services/opensearch/credentials/resource.go index e15608171..5cdb7b1dd 100644 --- a/stackit/services/opensearch/credentials/resource.go +++ b/stackit/services/opensearch/credentials/resource.go @@ -25,9 +25,9 @@ import ( // Ensure the implementation satisfies the expected interfaces. var ( - _ resource.Resource = &openSearchCredentialsResource{} - _ resource.ResourceWithConfigure = &openSearchCredentialsResource{} - _ resource.ResourceWithImportState = &openSearchCredentialsResource{} + _ resource.Resource = &opensearchCredentialsResource{} + _ resource.ResourceWithConfigure = &opensearchCredentialsResource{} + _ resource.ResourceWithImportState = &opensearchCredentialsResource{} ) type Model struct { @@ -47,21 +47,21 @@ type Model struct { // NewCredentialsResource is a helper function to simplify the provider implementation. func NewCredentialsResource() resource.Resource { - return &openSearchCredentialsResource{} + return &opensearchCredentialsResource{} } // credentialsResource is the resource implementation. -type openSearchCredentialsResource struct { +type opensearchCredentialsResource struct { client *opensearch.APIClient } // Metadata returns the resource type name. -func (r *openSearchCredentialsResource) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { +func (r *opensearchCredentialsResource) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { resp.TypeName = req.ProviderTypeName + "_opensearch_credentials" } // Configure adds the provider configured client to the resource. -func (r *openSearchCredentialsResource) Configure(ctx context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { +func (r *opensearchCredentialsResource) Configure(ctx context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { // Prevent panic if the provider has not been configured. if req.ProviderData == nil { return @@ -69,7 +69,7 @@ func (r *openSearchCredentialsResource) Configure(ctx context.Context, req resou providerData, ok := req.ProviderData.(core.ProviderData) if !ok { - resp.Diagnostics.AddError("Unexpected Resource Configure Type", fmt.Sprintf("Expected stackit.ProviderData, got %T. Please report this issue to the provider developers.", req.ProviderData)) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error configuring API client", fmt.Sprintf("Expected configure type stackit.ProviderData, got %T", req.ProviderData)) return } @@ -88,16 +88,16 @@ func (r *openSearchCredentialsResource) Configure(ctx context.Context, req resou } if err != nil { - resp.Diagnostics.AddError("Could not Configure API Client", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error configuring API client", fmt.Sprintf("Configuring client: %v", err)) return } - tflog.Info(ctx, "OpenSearch zone client configured") r.client = apiClient + tflog.Info(ctx, "OpenSearch credentials client configured") } // Schema defines the schema for the resource. -func (r *openSearchCredentialsResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) { +func (r *opensearchCredentialsResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) { descriptions := map[string]string{ "main": "OpenSearch credentials resource schema.", "id": "Terraform's internal resource identifier. It is structured as \"`project_id`,`instance_id`,`credentials_id`\".", @@ -182,7 +182,7 @@ func (r *openSearchCredentialsResource) Schema(_ context.Context, _ resource.Sch } // Create creates the resource and sets the initial Terraform state. -func (r *openSearchCredentialsResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { // nolint:gocritic // function signature required by Terraform +func (r *opensearchCredentialsResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { // nolint:gocritic // function signature required by Terraform var model Model diags := req.Plan.Get(ctx, &model) resp.Diagnostics.Append(diags...) @@ -218,19 +218,22 @@ func (r *openSearchCredentialsResource) Create(ctx context.Context, req resource return } - // Map response body to schema and populate Computed attribute values + // Map response body to schema err = mapFields(got, &model) if err != nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error mapping fields", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating credentials", fmt.Sprintf("Processing API payload: %v", err)) return } diags = resp.State.Set(ctx, model) resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } tflog.Info(ctx, "OpenSearch credentials created") } // Read refreshes the Terraform state with the latest data. -func (r *openSearchCredentialsResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { // nolint:gocritic // function signature required by Terraform +func (r *opensearchCredentialsResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { // nolint:gocritic // function signature required by Terraform var model Model diags := req.State.Get(ctx, &model) resp.Diagnostics.Append(diags...) @@ -246,31 +249,34 @@ func (r *openSearchCredentialsResource) Read(ctx context.Context, req resource.R recordSetResp, err := r.client.GetCredentials(ctx, projectId, instanceId, credentialsId).Execute() if err != nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading credentials", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading credentials", fmt.Sprintf("Calling API: %v", err)) return } - // Map response body to schema and populate Computed attribute values + // Map response body to schema err = mapFields(recordSetResp, &model) if err != nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error mapping fields", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading credentials", fmt.Sprintf("Processing API payload: %v", err)) return } // Set refreshed state diags = resp.State.Set(ctx, model) resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } tflog.Info(ctx, "OpenSearch credentials read") } // Update updates the resource and sets the updated Terraform state on success. -func (r *openSearchCredentialsResource) Update(_ context.Context, _ resource.UpdateRequest, resp *resource.UpdateResponse) { // nolint:gocritic // function signature required by Terraform +func (r *opensearchCredentialsResource) Update(ctx context.Context, _ resource.UpdateRequest, resp *resource.UpdateResponse) { // nolint:gocritic // function signature required by Terraform // Update shouldn't be called - resp.Diagnostics.AddError("Error updating credentials", "credentials can't be updated") + core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating credentials", "Credentials can't be updated") } // Delete deletes the resource and removes the Terraform state on success. -func (r *openSearchCredentialsResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { // nolint:gocritic // function signature required by Terraform +func (r *opensearchCredentialsResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { // nolint:gocritic // function signature required by Terraform var model Model diags := req.State.Get(ctx, &model) resp.Diagnostics.Append(diags...) @@ -288,7 +294,7 @@ func (r *openSearchCredentialsResource) Delete(ctx context.Context, req resource // Delete existing record set err := r.client.DeleteCredentials(ctx, projectId, instanceId, credentialsId).Execute() if err != nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error deleting credentials", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error deleting credentials", fmt.Sprintf("Calling API: %v", err)) } _, err = opensearch.DeleteCredentialsWaitHandler(ctx, r.client, projectId, instanceId, credentialsId).SetTimeout(1 * time.Minute).WaitWithContext(ctx) if err != nil { @@ -300,11 +306,11 @@ func (r *openSearchCredentialsResource) Delete(ctx context.Context, req resource // ImportState imports a resource into the Terraform state on success. // The expected format of the resource import identifier is: project_id,instance_id,credentials_id -func (r *openSearchCredentialsResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { +func (r *opensearchCredentialsResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { idParts := strings.Split(req.ID, core.Separator) if len(idParts) != 3 || idParts[0] == "" || idParts[1] == "" || idParts[2] == "" { core.LogAndAddError(ctx, &resp.Diagnostics, - "Unexpected Import Identifier", + "Unexpected import identifier", fmt.Sprintf("Expected import identifier with format [project_id],[instance_id],[credentials_id], got %q", req.ID), ) return diff --git a/stackit/services/opensearch/instance/datasource.go b/stackit/services/opensearch/instance/datasource.go index 6888cd8e7..7427e8c27 100644 --- a/stackit/services/opensearch/instance/datasource.go +++ b/stackit/services/opensearch/instance/datasource.go @@ -44,7 +44,7 @@ func (r *instanceDataSource) Configure(ctx context.Context, req datasource.Confi providerData, ok := req.ProviderData.(core.ProviderData) if !ok { - resp.Diagnostics.AddError("Unexpected Data Source Configure Type", fmt.Sprintf("Expected stackit.ProviderData, got %T. Please report this issue to the provider developers.", req.ProviderData)) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error configuring API client", fmt.Sprintf("Expected configure type stackit.ProviderData, got %T", req.ProviderData)) return } @@ -63,19 +63,19 @@ func (r *instanceDataSource) Configure(ctx context.Context, req datasource.Confi } if err != nil { - resp.Diagnostics.AddError("Could not Configure API Client", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error configuring API client", fmt.Sprintf("Configuring client: %v", err)) return } - tflog.Info(ctx, "OpenSearch zone client configured") r.client = apiClient + tflog.Info(ctx, "OpenSearch zone client configured") } // Schema defines the schema for the resource. func (r *instanceDataSource) Schema(_ context.Context, _ datasource.SchemaRequest, resp *datasource.SchemaResponse) { descriptions := map[string]string{ "main": "OpenSearch instance data source schema.", - "id": "Terraform's internal resource identifier. It is structured as \"`project_id`,`instance_id`\".", + "id": "Terraform's internal resource identifier. It is structured as \"`project_id`,`zone_id`\".", "instance_id": "ID of the OpenSearch instance.", "project_id": "STACKIT Project ID to which the instance is associated.", "name": "Instance name.", @@ -152,37 +152,41 @@ func (r *instanceDataSource) Schema(_ context.Context, _ datasource.SchemaReques // 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 - var state Model - diags := req.Config.Get(ctx, &state) + var model Model + diags := req.Config.Get(ctx, &model) resp.Diagnostics.Append(diags...) if resp.Diagnostics.HasError() { return } - - projectId := state.ProjectId.ValueString() - instanceId := state.InstanceId.ValueString() + projectId := model.ProjectId.ValueString() + instanceId := model.InstanceId.ValueString() ctx = tflog.SetField(ctx, "project_id", projectId) ctx = tflog.SetField(ctx, "instance_id", instanceId) + instanceResp, err := r.client.GetInstance(ctx, projectId, instanceId).Execute() if err != nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Unable to read instance", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading instance", fmt.Sprintf("Calling API: %v", err)) return } - err = mapFields(instanceResp, &state) + err = mapFields(instanceResp, &model) if err != nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Mapping fields", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading instance", fmt.Sprintf("Processing API payload: %v", err)) return } // Compute and store values not present in the API response - loadPlanNameAndVersion(ctx, r.client, &resp.Diagnostics, &state) - if resp.Diagnostics.HasError() { + err = loadPlanNameAndVersion(ctx, r.client, &model) + if err != nil { + core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading instance", fmt.Sprintf("Loading service plan details: %v", err)) return } // Set refreshed state - diags = resp.State.Set(ctx, &state) + diags = resp.State.Set(ctx, &model) resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } tflog.Info(ctx, "OpenSearch instance read") } diff --git a/stackit/services/opensearch/instance/resource.go b/stackit/services/opensearch/instance/resource.go index ee0a8470f..4df4c5007 100644 --- a/stackit/services/opensearch/instance/resource.go +++ b/stackit/services/opensearch/instance/resource.go @@ -8,7 +8,6 @@ import ( "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator" "github.com/hashicorp/terraform-plugin-framework/attr" - "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/schema/validator" "github.com/hashicorp/terraform-plugin-framework/types/basetypes" "github.com/hashicorp/terraform-plugin-log/tflog" @@ -82,7 +81,7 @@ func (r *instanceResource) Configure(ctx context.Context, req resource.Configure providerData, ok := req.ProviderData.(core.ProviderData) if !ok { - resp.Diagnostics.AddError("Unexpected Resource Configure Type", fmt.Sprintf("Expected stackit.ProviderData, got %T. Please report this issue to the provider developers.", req.ProviderData)) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error configuring API client", fmt.Sprintf("Expected configure type stackit.ProviderData, got %T", req.ProviderData)) return } @@ -101,12 +100,12 @@ func (r *instanceResource) Configure(ctx context.Context, req resource.Configure } if err != nil { - resp.Diagnostics.AddError("Could not Configure API Client", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error configuring API client", fmt.Sprintf("Configuring client: %v", err)) return } - tflog.Info(ctx, "opensearch zone client configured") r.client = apiClient + tflog.Info(ctx, "OpenSearch instance client configured") } // Schema defines the schema for the resource. @@ -128,6 +127,9 @@ func (r *instanceResource) Schema(_ context.Context, _ resource.SchemaRequest, r "id": schema.StringAttribute{ Description: descriptions["id"], Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, }, "instance_id": schema.StringAttribute{ Description: descriptions["instance_id"], @@ -187,18 +189,33 @@ func (r *instanceResource) Schema(_ context.Context, _ resource.SchemaRequest, r }, "cf_guid": schema.StringAttribute{ Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, }, "cf_space_guid": schema.StringAttribute{ Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, }, "dashboard_url": schema.StringAttribute{ Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, }, "image_url": schema.StringAttribute{ Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, }, "cf_organization_guid": schema.StringAttribute{ Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, }, }, } @@ -215,11 +232,6 @@ func (r *instanceResource) Create(ctx context.Context, req resource.CreateReques projectId := model.ProjectId.ValueString() ctx = tflog.SetField(ctx, "project_id", projectId) - r.loadPlanId(ctx, &resp.Diagnostics, &model) - if resp.Diagnostics.HasError() { - return - } - var parameters = ¶metersModel{} if !(model.Parameters.IsNull() || model.Parameters.IsUnknown()) { diags = model.Parameters.As(ctx, parameters, basetypes.ObjectAsOptions{}) @@ -229,6 +241,12 @@ func (r *instanceResource) Create(ctx context.Context, req resource.CreateReques } } + err := r.loadPlanId(ctx, &model) + if err != nil { + core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating instance", fmt.Sprintf("Loading service plan: %v", err)) + return + } + // Generate API request body from model payload, err := toCreatePayload(&model, parameters) if err != nil { @@ -254,54 +272,69 @@ func (r *instanceResource) Create(ctx context.Context, req resource.CreateReques return } - // Map response body to schema and populate Computed attribute values + // Map response body to schema err = mapFields(got, &model) if err != nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error mapping fields", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating instance", fmt.Sprintf("Processing API payload: %v", err)) return } + + // Compute and store values not present in the API response + err = loadPlanNameAndVersion(ctx, r.client, &model) + if err != nil { + core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading instance", fmt.Sprintf("Loading service plan details: %v", err)) + return + } + // Set state to fully populated data diags = resp.State.Set(ctx, model) resp.Diagnostics.Append(diags...) - tflog.Info(ctx, "opensearch instance created") + if resp.Diagnostics.HasError() { + return + } + tflog.Info(ctx, "OpenSearch instance created") } // 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 - var state Model - diags := req.State.Get(ctx, &state) + var model Model + diags := req.State.Get(ctx, &model) resp.Diagnostics.Append(diags...) if resp.Diagnostics.HasError() { return } - projectId := state.ProjectId.ValueString() - instanceId := state.InstanceId.ValueString() + projectId := model.ProjectId.ValueString() + instanceId := model.InstanceId.ValueString() ctx = tflog.SetField(ctx, "project_id", projectId) ctx = tflog.SetField(ctx, "instance_id", instanceId) instanceResp, err := r.client.GetInstance(ctx, projectId, instanceId).Execute() if err != nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading instances", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading instance", fmt.Sprintf("Calling API: %v", err)) return } - // Map response body to schema and populate Computed attribute values - err = mapFields(instanceResp, &state) + // Map response body to schema + err = mapFields(instanceResp, &model) if err != nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error mapping fields", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading instance", fmt.Sprintf("Processing API payload: %v", err)) return } // Compute and store values not present in the API response - loadPlanNameAndVersion(ctx, r.client, &resp.Diagnostics, &state) - if resp.Diagnostics.HasError() { + err = loadPlanNameAndVersion(ctx, r.client, &model) + if err != nil { + core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading instance", fmt.Sprintf("Loading service plan details: %v", err)) return } // Set refreshed state - diags = resp.State.Set(ctx, state) + diags = resp.State.Set(ctx, model) resp.Diagnostics.Append(diags...) - tflog.Info(ctx, "opensearch instance read") + if resp.Diagnostics.HasError() { + return + } + tflog.Info(ctx, "OpenSearch instance read") } // Update updates the resource and sets the updated Terraform state on success. @@ -317,11 +350,6 @@ func (r *instanceResource) Update(ctx context.Context, req resource.UpdateReques ctx = tflog.SetField(ctx, "project_id", projectId) ctx = tflog.SetField(ctx, "instance_id", instanceId) - r.loadPlanId(ctx, &resp.Diagnostics, &model) - if resp.Diagnostics.HasError() { - return - } - var parameters = ¶metersModel{} if !(model.Parameters.IsNull() || model.Parameters.IsUnknown()) { diags = model.Parameters.As(ctx, parameters, basetypes.ObjectAsOptions{}) @@ -331,16 +359,22 @@ func (r *instanceResource) Update(ctx context.Context, req resource.UpdateReques } } + err := r.loadPlanId(ctx, &model) + if err != nil { + core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating instance", fmt.Sprintf("Loading service plan: %v", err)) + return + } + // Generate API request body from model payload, err := toUpdatePayload(&model, parameters) if err != nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating instance", fmt.Sprintf("Could not create API payload: %v", err)) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating instance", fmt.Sprintf("Creating API payload: %v", err)) return } // Update existing instance err = r.client.UpdateInstance(ctx, projectId, instanceId).UpdateInstancePayload(*payload).Execute() if err != nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating instance", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating instance", fmt.Sprintf("Calling API: %v", err)) return } wr, err := opensearch.UpdateInstanceWaitHandler(ctx, r.client, projectId, instanceId).SetTimeout(15 * time.Minute).WaitWithContext(ctx) @@ -354,15 +388,26 @@ func (r *instanceResource) Update(ctx context.Context, req resource.UpdateReques return } - // Map response body to schema and populate Computed attribute values + // Map response body to schema err = mapFields(got, &model) if err != nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error mapping fields in update", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating instance", fmt.Sprintf("Processing API payload: %v", err)) + return + } + + // Compute and store values not present in the API response + err = loadPlanNameAndVersion(ctx, r.client, &model) + if err != nil { + core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading instance", fmt.Sprintf("Loading service plan details: %v", err)) return } + diags = resp.State.Set(ctx, model) resp.Diagnostics.Append(diags...) - tflog.Info(ctx, "opensearch instance updated") + if resp.Diagnostics.HasError() { + return + } + tflog.Info(ctx, "OpenSearch instance updated") } // Delete deletes the resource and removes the Terraform state on success. @@ -382,7 +427,7 @@ func (r *instanceResource) Delete(ctx context.Context, req resource.DeleteReques // Delete existing instance err := r.client.DeleteInstance(ctx, projectId, instanceId).Execute() if err != nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error deleting instance", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error deleting instance", fmt.Sprintf("Calling API: %v", err)) return } _, err = opensearch.DeleteInstanceWaitHandler(ctx, r.client, projectId, instanceId).SetTimeout(15 * time.Minute).WaitWithContext(ctx) @@ -390,7 +435,7 @@ func (r *instanceResource) Delete(ctx context.Context, req resource.DeleteReques core.LogAndAddError(ctx, &resp.Diagnostics, "Error deleting instance", fmt.Sprintf("Instance deletion waiting: %v", err)) return } - tflog.Info(ctx, "opensearch instance deleted") + tflog.Info(ctx, "OpenSearch instance deleted") } // ImportState imports a resource into the Terraform state on success. @@ -399,8 +444,8 @@ func (r *instanceResource) ImportState(ctx context.Context, req resource.ImportS idParts := strings.Split(req.ID, core.Separator) if len(idParts) != 2 || idParts[0] == "" || idParts[1] == "" { - resp.Diagnostics.AddError( - "Unexpected Import Identifier", + core.LogAndAddError(ctx, &resp.Diagnostics, + "Unexpected import identifier", fmt.Sprintf("Expected import identifier with format: [project_id],[instance_id] Got: %q", req.ID), ) return @@ -410,6 +455,7 @@ func (r *instanceResource) ImportState(ctx context.Context, req resource.ImportS resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("instance_id"), idParts[1])...) tflog.Info(ctx, "OpenSearch instance state imported") } + func mapFields(instance *opensearch.Instance, model *Model) error { if instance == nil { return fmt.Errorf("response input is nil") @@ -442,6 +488,7 @@ func mapFields(instance *opensearch.Instance, model *Model) error { model.ImageUrl = types.StringPointerValue(instance.ImageUrl) model.Name = types.StringPointerValue(instance.Name) model.CfOrganizationGuid = types.StringPointerValue(instance.CfOrganizationGuid) + if instance.Parameters == nil { model.Parameters = types.ObjectNull(parametersTypes) } else { @@ -588,12 +635,11 @@ func toUpdatePayload(model *Model, parameters *parametersModel) (*opensearch.Upd }, nil } -func (r *instanceResource) loadPlanId(ctx context.Context, diags *diag.Diagnostics, model *Model) { +func (r *instanceResource) loadPlanId(ctx context.Context, model *Model) error { projectId := model.ProjectId.ValueString() res, err := r.client.GetOfferings(ctx, projectId).Execute() if err != nil { - diags.AddError("Failed to list OpenSearch offerings", err.Error()) - return + return fmt.Errorf("getting OpenSearch offerings: %v", err) } version := model.Version.ValueString() @@ -614,26 +660,24 @@ func (r *instanceResource) loadPlanId(ctx context.Context, diags *diag.Diagnosti } if strings.EqualFold(*plan.Name, planName) && plan.Id != nil { model.PlanId = types.StringPointerValue(plan.Id) - return + return nil } availablePlanNames = fmt.Sprintf("%s\n- %s", availablePlanNames, *plan.Name) } } if !isValidVersion { - diags.AddError("Invalid version", fmt.Sprintf("Couldn't find version '%s', available versions are:%s", version, availableVersions)) - return + return fmt.Errorf("couldn't find version '%s', available versions are: %s", version, availableVersions) } - diags.AddError("Invalid plan_name", fmt.Sprintf("Couldn't find plan_name '%s' for version %s, available names are:%s", planName, version, availablePlanNames)) + return fmt.Errorf("couldn't find plan_name '%s' for version %s, available names are: %s", planName, version, availablePlanNames) } -func loadPlanNameAndVersion(ctx context.Context, client *opensearch.APIClient, diags *diag.Diagnostics, model *Model) { +func loadPlanNameAndVersion(ctx context.Context, client *opensearch.APIClient, model *Model) error { projectId := model.ProjectId.ValueString() planId := model.PlanId.ValueString() res, err := client.GetOfferings(ctx, projectId).Execute() if err != nil { - diags.AddError("Failed to list OpenSearch offerings", err.Error()) - return + return fmt.Errorf("getting OpenSearch offerings: %v", err) } for _, offer := range *res.Offerings { @@ -641,10 +685,10 @@ func loadPlanNameAndVersion(ctx context.Context, client *opensearch.APIClient, d if strings.EqualFold(*plan.Id, planId) && plan.Id != nil { model.PlanName = types.StringPointerValue(plan.Name) model.Version = types.StringPointerValue(offer.Version) - return + return nil } } } - diags.AddWarning("Failed to get plan_name and version", fmt.Sprintf("Couldn't find plan_name and version for plan_id = %s", planId)) + return fmt.Errorf("couldn't find plan_name and version for plan_id '%s'", planId) } diff --git a/stackit/services/postgresflex/instance/datasource.go b/stackit/services/postgresflex/instance/datasource.go index 57c5b0880..a57b30323 100644 --- a/stackit/services/postgresflex/instance/datasource.go +++ b/stackit/services/postgresflex/instance/datasource.go @@ -46,7 +46,7 @@ func (r *instanceDataSource) Configure(ctx context.Context, req datasource.Confi providerData, ok := req.ProviderData.(core.ProviderData) if !ok { - resp.Diagnostics.AddError("Unexpected Data Source Configure Type", fmt.Sprintf("Expected stackit.ProviderData, got %T", req.ProviderData)) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error configuring API client", fmt.Sprintf("Expected configure type stackit.ProviderData, got %T", req.ProviderData)) return } @@ -65,12 +65,12 @@ func (r *instanceDataSource) Configure(ctx context.Context, req datasource.Confi } if err != nil { - resp.Diagnostics.AddError("Could not Configure API Client", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error configuring API client", fmt.Sprintf("Configuring client: %v", err)) return } - tflog.Info(ctx, "Postgresflex instance client configured") r.client = apiClient + tflog.Info(ctx, "PostgresFlex instance client configured") } // Schema defines the schema for the resource. @@ -159,47 +159,50 @@ func (r *instanceDataSource) Schema(_ context.Context, _ datasource.SchemaReques // 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 - var state Model - diags := req.Config.Get(ctx, &state) + var model Model + diags := req.Config.Get(ctx, &model) resp.Diagnostics.Append(diags...) if resp.Diagnostics.HasError() { return } - projectId := state.ProjectId.ValueString() - instanceId := state.InstanceId.ValueString() + projectId := model.ProjectId.ValueString() + instanceId := model.InstanceId.ValueString() ctx = tflog.SetField(ctx, "project_id", projectId) ctx = tflog.SetField(ctx, "instance_id", instanceId) instanceResp, err := r.client.GetInstance(ctx, projectId, instanceId).Execute() if err != nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Unable to read instance", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading instance", fmt.Sprintf("Calling API: %v", err)) return } var flavor = &flavorModel{} - if !(state.Flavor.IsNull() || state.Flavor.IsUnknown()) { - diags = state.Flavor.As(ctx, flavor, basetypes.ObjectAsOptions{}) + if !(model.Flavor.IsNull() || model.Flavor.IsUnknown()) { + diags = model.Flavor.As(ctx, flavor, basetypes.ObjectAsOptions{}) resp.Diagnostics.Append(diags...) if resp.Diagnostics.HasError() { return } } var storage = &storageModel{} - if !(state.Storage.IsNull() || state.Storage.IsUnknown()) { - diags = state.Storage.As(ctx, storage, basetypes.ObjectAsOptions{}) + if !(model.Storage.IsNull() || model.Storage.IsUnknown()) { + diags = model.Storage.As(ctx, storage, basetypes.ObjectAsOptions{}) resp.Diagnostics.Append(diags...) if resp.Diagnostics.HasError() { return } } - err = mapFields(instanceResp, &state, flavor, storage) + err = mapFields(instanceResp, &model, flavor, storage) if err != nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Mapping fields", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading instance", fmt.Sprintf("Processing API payload: %v", err)) return } // Set refreshed state - diags = resp.State.Set(ctx, state) + diags = resp.State.Set(ctx, model) resp.Diagnostics.Append(diags...) - tflog.Info(ctx, "Postgresql instance read") + if resp.Diagnostics.HasError() { + return + } + tflog.Info(ctx, "PostgresFlex instance read") } diff --git a/stackit/services/postgresflex/instance/resource.go b/stackit/services/postgresflex/instance/resource.go index fa8e288ad..05449ce3c 100644 --- a/stackit/services/postgresflex/instance/resource.go +++ b/stackit/services/postgresflex/instance/resource.go @@ -99,7 +99,7 @@ func (r *instanceResource) Configure(ctx context.Context, req resource.Configure providerData, ok := req.ProviderData.(core.ProviderData) if !ok { - resp.Diagnostics.AddError("Unexpected Data Source Configure Type", fmt.Sprintf("Expected stackit.ProviderData, got %T", req.ProviderData)) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error configuring API client", fmt.Sprintf("Expected configure type stackit.ProviderData, got %T", req.ProviderData)) return } @@ -118,12 +118,12 @@ func (r *instanceResource) Configure(ctx context.Context, req resource.Configure } if err != nil { - resp.Diagnostics.AddError("Could not Configure API Client", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error configuring API client", fmt.Sprintf("Configuring client: %v", err)) return } - tflog.Info(ctx, "Postgresflex instance client configured") r.client = apiClient + tflog.Info(ctx, "PostgresFlex instance client configured") } // Schema defines the schema for the resource. @@ -286,10 +286,6 @@ func (r *instanceResource) Create(ctx context.Context, req resource.CreateReques core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating instance", fmt.Sprintf("Calling API: %v", err)) return } - if createResp == nil || createResp.Id == nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating instance", "Didn't get ID of created instance. An instance might have been created") - return - } instanceId := *createResp.Id ctx = tflog.SetField(ctx, "instance_id", instanceId) wr, err := postgresflex.CreateInstanceWaitHandler(ctx, r.client, projectId, instanceId).SetTimeout(15 * time.Minute).WaitWithContext(ctx) @@ -303,42 +299,45 @@ func (r *instanceResource) Create(ctx context.Context, req resource.CreateReques return } - // Map response body to schema and populate Computed attribute values + // Map response body to schema err = mapFields(got, &model, flavor, storage) if err != nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error mapping fields", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating instance", fmt.Sprintf("Processing API payload: %v", err)) return } // Set state to fully populated data diags = resp.State.Set(ctx, model) resp.Diagnostics.Append(diags...) - tflog.Info(ctx, "Postgresflex instance created") + if resp.Diagnostics.HasError() { + return + } + tflog.Info(ctx, "PostgresFlex instance created") } // 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 - var state Model - diags := req.State.Get(ctx, &state) + var model Model + diags := req.State.Get(ctx, &model) resp.Diagnostics.Append(diags...) if resp.Diagnostics.HasError() { return } - projectId := state.ProjectId.ValueString() - instanceId := state.InstanceId.ValueString() + projectId := model.ProjectId.ValueString() + instanceId := model.InstanceId.ValueString() ctx = tflog.SetField(ctx, "project_id", projectId) ctx = tflog.SetField(ctx, "instance_id", instanceId) var flavor = &flavorModel{} - if !(state.Flavor.IsNull() || state.Flavor.IsUnknown()) { - diags = state.Flavor.As(ctx, flavor, basetypes.ObjectAsOptions{}) + if !(model.Flavor.IsNull() || model.Flavor.IsUnknown()) { + diags = model.Flavor.As(ctx, flavor, basetypes.ObjectAsOptions{}) resp.Diagnostics.Append(diags...) if resp.Diagnostics.HasError() { return } } var storage = &storageModel{} - if !(state.Storage.IsNull() || state.Storage.IsUnknown()) { - diags = state.Storage.As(ctx, storage, basetypes.ObjectAsOptions{}) + if !(model.Storage.IsNull() || model.Storage.IsUnknown()) { + diags = model.Storage.As(ctx, storage, basetypes.ObjectAsOptions{}) resp.Diagnostics.Append(diags...) if resp.Diagnostics.HasError() { return @@ -351,16 +350,19 @@ func (r *instanceResource) Read(ctx context.Context, req resource.ReadRequest, r return } - // Map response body to schema and populate Computed attribute values - err = mapFields(instanceResp, &state, flavor, storage) + // Map response body to schema + err = mapFields(instanceResp, &model, flavor, storage) if err != nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error mapping fields", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading instance", fmt.Sprintf("Processing API payload: %v", err)) return } // Set refreshed state - diags = resp.State.Set(ctx, state) + diags = resp.State.Set(ctx, model) resp.Diagnostics.Append(diags...) - tflog.Info(ctx, "Postgresflex instance read") + if resp.Diagnostics.HasError() { + return + } + tflog.Info(ctx, "PostgresFlex instance read") } // Update updates the resource and sets the updated Terraform state on success. @@ -409,7 +411,7 @@ func (r *instanceResource) Update(ctx context.Context, req resource.UpdateReques // Generate API request body from model payload, err := toUpdatePayload(&model, acl, flavor, storage) if err != nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating instance", fmt.Sprintf("Could not create API payload: %v", err)) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating instance", fmt.Sprintf("Creating API payload: %v", err)) return } // Update existing instance @@ -429,7 +431,7 @@ func (r *instanceResource) Update(ctx context.Context, req resource.UpdateReques return } - // Map response body to schema and populate Computed attribute values + // Map response body to schema err = mapFields(got, &model, flavor, storage) if err != nil { core.LogAndAddError(ctx, &resp.Diagnostics, "Error mapping fields in update", err.Error()) @@ -437,6 +439,9 @@ func (r *instanceResource) Update(ctx context.Context, req resource.UpdateReques } diags = resp.State.Set(ctx, model) resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } tflog.Info(ctx, "Postgresflex instance updated") } @@ -457,7 +462,7 @@ func (r *instanceResource) Delete(ctx context.Context, req resource.DeleteReques // Delete existing instance err := r.client.DeleteInstance(ctx, projectId, instanceId).Execute() if err != nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error deleting instance", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error deleting instance", fmt.Sprintf("Calling API: %v", err)) return } _, err = postgresflex.DeleteInstanceWaitHandler(ctx, r.client, projectId, instanceId).SetTimeout(15 * time.Minute).WaitWithContext(ctx) @@ -465,7 +470,7 @@ func (r *instanceResource) Delete(ctx context.Context, req resource.DeleteReques core.LogAndAddError(ctx, &resp.Diagnostics, "Error deleting instance", fmt.Sprintf("Instance deletion waiting: %v", err)) return } - tflog.Info(ctx, "Postgresflex instance deleted") + tflog.Info(ctx, "PostgresFlex instance deleted") } // ImportState imports a resource into the Terraform state on success. @@ -474,8 +479,8 @@ func (r *instanceResource) ImportState(ctx context.Context, req resource.ImportS idParts := strings.Split(req.ID, core.Separator) if len(idParts) != 2 || idParts[0] == "" || idParts[1] == "" { - resp.Diagnostics.AddError( - "Unexpected Import Identifier", + core.LogAndAddError(ctx, &resp.Diagnostics, + "Unexpected import identifier", fmt.Sprintf("Expected import identifier with format: [project_id],[instance_id] Got: %q", req.ID), ) return diff --git a/stackit/services/postgresflex/user/datasource.go b/stackit/services/postgresflex/user/datasource.go index eaa7cecf6..08de46a76 100644 --- a/stackit/services/postgresflex/user/datasource.go +++ b/stackit/services/postgresflex/user/datasource.go @@ -45,7 +45,7 @@ func (r *userDataSource) Configure(ctx context.Context, req datasource.Configure providerData, ok := req.ProviderData.(core.ProviderData) if !ok { - resp.Diagnostics.AddError("Unexpected Data Source Configure Type", fmt.Sprintf("Expected stackit.ProviderData, got %T", req.ProviderData)) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error configuring API client", fmt.Sprintf("Expected configure type stackit.ProviderData, got %T", req.ProviderData)) return } @@ -64,12 +64,12 @@ func (r *userDataSource) Configure(ctx context.Context, req datasource.Configure } if err != nil { - resp.Diagnostics.AddError("Could not Configure API Client", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error configuring API client", fmt.Sprintf("Configuring client: %v", err)) return } - tflog.Info(ctx, "Postgresflex user client configured") r.client = apiClient + tflog.Info(ctx, "PostgresFlex user client configured") } // Schema defines the schema for the resource. @@ -150,19 +150,22 @@ func (r *userDataSource) Read(ctx context.Context, req datasource.ReadRequest, r recordSetResp, err := r.client.GetUser(ctx, projectId, instanceId, userId).Execute() if err != nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading user", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading user", fmt.Sprintf("Calling API: %v", err)) return } - // Map response body to schema and populate Computed attribute values + // Map response body to schema err = mapFields(recordSetResp, &model) if err != nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error mapping fields", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading user", fmt.Sprintf("Processing API payload: %v", err)) return } // Set refreshed state diags = resp.State.Set(ctx, model) resp.Diagnostics.Append(diags...) - tflog.Info(ctx, "Postgresql user read") + if resp.Diagnostics.HasError() { + return + } + tflog.Info(ctx, "PostgresFlex user read") } diff --git a/stackit/services/postgresflex/user/resource.go b/stackit/services/postgresflex/user/resource.go index 2e7da20e3..cdc395844 100644 --- a/stackit/services/postgresflex/user/resource.go +++ b/stackit/services/postgresflex/user/resource.go @@ -69,7 +69,7 @@ func (r *userResource) Configure(ctx context.Context, req resource.ConfigureRequ providerData, ok := req.ProviderData.(core.ProviderData) if !ok { - resp.Diagnostics.AddError("Unexpected Data Source Configure Type", fmt.Sprintf("Expected stackit.ProviderData, got %T", req.ProviderData)) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error configuring API client", fmt.Sprintf("Expected configure type stackit.ProviderData, got %T", req.ProviderData)) return } @@ -88,12 +88,12 @@ func (r *userResource) Configure(ctx context.Context, req resource.ConfigureRequ } if err != nil { - resp.Diagnostics.AddError("Could not Configure API Client", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error configuring API client", fmt.Sprintf("Configuring client: %v", err)) return } - tflog.Info(ctx, "Postgresflex user client configured") r.client = apiClient + tflog.Info(ctx, "PostgresFlex user client configured") } // Schema defines the schema for the resource. @@ -217,22 +217,25 @@ func (r *userResource) Create(ctx context.Context, req resource.CreateRequest, r return } if userResp == nil || userResp.Item == nil || userResp.Item.Id == nil || *userResp.Item.Id == "" { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating user", "Didn't get ID of created user. A user might have been created") + core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating user", "API didn't return user Id. A user might have been created") return } userId := *userResp.Item.Id ctx = tflog.SetField(ctx, "user_id", userId) - // Map response body to schema and populate Computed attribute values + // Map response body to schema err = mapFieldsCreate(userResp, &model) if err != nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error mapping fields", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating user", fmt.Sprintf("Processing API payload: %v", err)) return } // Set state to fully populated data diags = resp.State.Set(ctx, model) resp.Diagnostics.Append(diags...) - tflog.Info(ctx, "Postgresflex user created") + if resp.Diagnostics.HasError() { + return + } + tflog.Info(ctx, "PostgresFlex user created") } // Read refreshes the Terraform state with the latest data. @@ -252,27 +255,30 @@ func (r *userResource) Read(ctx context.Context, req resource.ReadRequest, resp recordSetResp, err := r.client.GetUser(ctx, projectId, instanceId, userId).Execute() if err != nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading user", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading user", fmt.Sprintf("Calling API: %v", err)) return } - // Map response body to schema and populate Computed attribute values + // Map response body to schema err = mapFields(recordSetResp, &model) if err != nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error mapping fields", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading user", fmt.Sprintf("Processing API payload: %v", err)) return } // Set refreshed state diags = resp.State.Set(ctx, model) resp.Diagnostics.Append(diags...) - tflog.Info(ctx, "Postgresflex user read") + if resp.Diagnostics.HasError() { + return + } + tflog.Info(ctx, "PostgresFlex user read") } // Update updates the resource and sets the updated Terraform state on success. -func (r *userResource) Update(_ context.Context, _ resource.UpdateRequest, resp *resource.UpdateResponse) { // nolint:gocritic // function signature required by Terraform +func (r *userResource) Update(ctx context.Context, _ resource.UpdateRequest, resp *resource.UpdateResponse) { // nolint:gocritic // function signature required by Terraform // Update shouldn't be called - resp.Diagnostics.AddError("Error updating user", "user can't be updated") + core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating user", "User can't be updated") } // Delete deletes the resource and removes the Terraform state on success. @@ -295,14 +301,14 @@ func (r *userResource) Delete(ctx context.Context, req resource.DeleteRequest, r // Delete existing record set err := r.client.DeleteUser(ctx, projectId, instanceId, userId).Execute() if err != nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error deleting user", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error deleting user", fmt.Sprintf("Calling API: %v", err)) } _, err = postgresflex.DeleteUserWaitHandler(ctx, r.client, projectId, instanceId, userId).SetTimeout(1 * time.Minute).WaitWithContext(ctx) if err != nil { core.LogAndAddError(ctx, &resp.Diagnostics, "Error deleting user", fmt.Sprintf("Instance deletion waiting: %v", err)) return } - tflog.Info(ctx, "Postgresflex user deleted") + tflog.Info(ctx, "PostgresFlex user deleted") } // ImportState imports a resource into the Terraform state on success. @@ -311,7 +317,7 @@ func (r *userResource) ImportState(ctx context.Context, req resource.ImportState idParts := strings.Split(req.ID, core.Separator) if len(idParts) != 3 || idParts[0] == "" || idParts[1] == "" || idParts[2] == "" { core.LogAndAddError(ctx, &resp.Diagnostics, - "Unexpected Import Identifier", + "Unexpected import identifier", fmt.Sprintf("Expected import identifier with format [project_id],[instance_id],[user_id], got %q", req.ID), ) return diff --git a/stackit/services/postgresql/credentials/datasource.go b/stackit/services/postgresql/credentials/datasource.go index a55b88b6e..e4a03c4f3 100644 --- a/stackit/services/postgresql/credentials/datasource.go +++ b/stackit/services/postgresql/credentials/datasource.go @@ -45,7 +45,7 @@ func (r *credentialsDataSource) Configure(ctx context.Context, req datasource.Co providerData, ok := req.ProviderData.(core.ProviderData) if !ok { - resp.Diagnostics.AddError("Unexpected Data Source Configure Type", fmt.Sprintf("Expected stackit.ProviderData, got %T. Please report this issue to the provider developers.", req.ProviderData)) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error configuring API client", fmt.Sprintf("Expected configure type stackit.ProviderData, got %T", req.ProviderData)) return } @@ -64,12 +64,12 @@ func (r *credentialsDataSource) Configure(ctx context.Context, req datasource.Co } if err != nil { - resp.Diagnostics.AddError("Could not Configure API Client", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error configuring API client", fmt.Sprintf("Configuring client: %v", err)) return } - tflog.Info(ctx, "Postgresql zone client configured") r.client = apiClient + tflog.Info(ctx, "PostgreSQL credentials client configured") } // Schema defines the schema for the resource. @@ -160,19 +160,22 @@ func (r *credentialsDataSource) Read(ctx context.Context, req datasource.ReadReq recordSetResp, err := r.client.GetCredentials(ctx, projectId, instanceId, credentialsId).Execute() if err != nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading credentials", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading credentials", fmt.Sprintf("Calling API: %v", err)) return } - // Map response body to schema and populate Computed attribute values + // Map response body to schema err = mapFields(recordSetResp, &model) if err != nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error mapping fields", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading credentials", fmt.Sprintf("Processing API payload: %v", err)) return } // Set refreshed state diags = resp.State.Set(ctx, model) resp.Diagnostics.Append(diags...) - tflog.Info(ctx, "Postgresql credentials read") + if resp.Diagnostics.HasError() { + return + } + tflog.Info(ctx, "PostgreSQL credentials read") } diff --git a/stackit/services/postgresql/credentials/resource.go b/stackit/services/postgresql/credentials/resource.go index c6a581896..8985654e9 100644 --- a/stackit/services/postgresql/credentials/resource.go +++ b/stackit/services/postgresql/credentials/resource.go @@ -25,9 +25,9 @@ import ( // Ensure the implementation satisfies the expected interfaces. var ( - _ resource.Resource = &credentialsResource{} - _ resource.ResourceWithConfigure = &credentialsResource{} - _ resource.ResourceWithImportState = &credentialsResource{} + _ resource.Resource = &postgresqlCredentialsResource{} + _ resource.ResourceWithConfigure = &postgresqlCredentialsResource{} + _ resource.ResourceWithImportState = &postgresqlCredentialsResource{} ) type Model struct { @@ -47,21 +47,21 @@ type Model struct { // NewCredentialsResource is a helper function to simplify the provider implementation. func NewCredentialsResource() resource.Resource { - return &credentialsResource{} + return &postgresqlCredentialsResource{} } // credentialsResource is the resource implementation. -type credentialsResource struct { +type postgresqlCredentialsResource struct { client *postgresql.APIClient } // Metadata returns the resource type name. -func (r *credentialsResource) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { +func (r *postgresqlCredentialsResource) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { resp.TypeName = req.ProviderTypeName + "_postgresql_credentials" } // Configure adds the provider configured client to the resource. -func (r *credentialsResource) Configure(ctx context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { +func (r *postgresqlCredentialsResource) Configure(ctx context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { // Prevent panic if the provider has not been configured. if req.ProviderData == nil { return @@ -69,7 +69,7 @@ func (r *credentialsResource) Configure(ctx context.Context, req resource.Config providerData, ok := req.ProviderData.(core.ProviderData) if !ok { - resp.Diagnostics.AddError("Unexpected Resource Configure Type", fmt.Sprintf("Expected stackit.ProviderData, got %T. Please report this issue to the provider developers.", req.ProviderData)) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error configuring API client", fmt.Sprintf("Expected configure type stackit.ProviderData, got %T", req.ProviderData)) return } @@ -88,16 +88,16 @@ func (r *credentialsResource) Configure(ctx context.Context, req resource.Config } if err != nil { - resp.Diagnostics.AddError("Could not Configure API Client", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error configuring API client", fmt.Sprintf("Configuring client: %v", err)) return } - tflog.Info(ctx, "Postgresql zone client configured") r.client = apiClient + tflog.Info(ctx, "PostgreSQL credentials client configured") } // Schema defines the schema for the resource. -func (r *credentialsResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) { +func (r *postgresqlCredentialsResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) { descriptions := map[string]string{ "main": "PostgreSQL credentials resource schema.", "id": "Terraform's internal resource identifier. It is structured as \"`project_id`,`instance_id`,`credentials_id`\".", @@ -182,7 +182,7 @@ func (r *credentialsResource) Schema(_ context.Context, _ resource.SchemaRequest } // Create creates the resource and sets the initial Terraform state. -func (r *credentialsResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { // nolint:gocritic // function signature required by Terraform +func (r *postgresqlCredentialsResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { // nolint:gocritic // function signature required by Terraform var model Model diags := req.Plan.Get(ctx, &model) resp.Diagnostics.Append(diags...) @@ -218,19 +218,22 @@ func (r *credentialsResource) Create(ctx context.Context, req resource.CreateReq return } - // Map response body to schema and populate Computed attribute values + // Map response body to schema err = mapFields(got, &model) if err != nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error mapping fields", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating credentials", fmt.Sprintf("Processing API payload: %v", err)) return } diags = resp.State.Set(ctx, model) resp.Diagnostics.Append(diags...) - tflog.Info(ctx, "Postgresql credentials created") + if resp.Diagnostics.HasError() { + return + } + tflog.Info(ctx, "PostgreSQL credentials created") } // Read refreshes the Terraform state with the latest data. -func (r *credentialsResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { // nolint:gocritic // function signature required by Terraform +func (r *postgresqlCredentialsResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { // nolint:gocritic // function signature required by Terraform var model Model diags := req.State.Get(ctx, &model) resp.Diagnostics.Append(diags...) @@ -246,31 +249,34 @@ func (r *credentialsResource) Read(ctx context.Context, req resource.ReadRequest recordSetResp, err := r.client.GetCredentials(ctx, projectId, instanceId, credentialsId).Execute() if err != nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading credentials", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading credentials", fmt.Sprintf("Calling API: %v", err)) return } - // Map response body to schema and populate Computed attribute values + // Map response body to schema err = mapFields(recordSetResp, &model) if err != nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error mapping fields", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading credentials", fmt.Sprintf("Processing API payload: %v", err)) return } // Set refreshed state diags = resp.State.Set(ctx, model) resp.Diagnostics.Append(diags...) - tflog.Info(ctx, "Postgresql credentials read") + if resp.Diagnostics.HasError() { + return + } + tflog.Info(ctx, "PostgreSQL credentials read") } // Update updates the resource and sets the updated Terraform state on success. -func (r *credentialsResource) Update(_ context.Context, _ resource.UpdateRequest, resp *resource.UpdateResponse) { // nolint:gocritic // function signature required by Terraform +func (r *postgresqlCredentialsResource) Update(ctx context.Context, _ resource.UpdateRequest, resp *resource.UpdateResponse) { // nolint:gocritic // function signature required by Terraform // Update shouldn't be called - resp.Diagnostics.AddError("Error updating credentials", "credentials can't be updated") + core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating credentials", "Credentials can't be updated") } // Delete deletes the resource and removes the Terraform state on success. -func (r *credentialsResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { // nolint:gocritic // function signature required by Terraform +func (r *postgresqlCredentialsResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { // nolint:gocritic // function signature required by Terraform var model Model diags := req.State.Get(ctx, &model) resp.Diagnostics.Append(diags...) @@ -288,23 +294,23 @@ func (r *credentialsResource) Delete(ctx context.Context, req resource.DeleteReq // Delete existing record set err := r.client.DeleteCredentials(ctx, projectId, instanceId, credentialsId).Execute() if err != nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error deleting credentials", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error deleting credentials", fmt.Sprintf("Calling API: %v", err)) } _, err = postgresql.DeleteCredentialsWaitHandler(ctx, r.client, projectId, instanceId, credentialsId).SetTimeout(1 * time.Minute).WaitWithContext(ctx) if err != nil { core.LogAndAddError(ctx, &resp.Diagnostics, "Error deleting credentials", fmt.Sprintf("Instance deletion waiting: %v", err)) return } - tflog.Info(ctx, "Postgresql credentials deleted") + tflog.Info(ctx, "PostgreSQL credentials deleted") } // ImportState imports a resource into the Terraform state on success. // The expected format of the resource import identifier is: project_id,instance_id,credentials_id -func (r *credentialsResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { +func (r *postgresqlCredentialsResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { idParts := strings.Split(req.ID, core.Separator) if len(idParts) != 3 || idParts[0] == "" || idParts[1] == "" || idParts[2] == "" { core.LogAndAddError(ctx, &resp.Diagnostics, - "Unexpected Import Identifier", + "Unexpected import identifier", fmt.Sprintf("Expected import identifier with format [project_id],[instance_id],[credentials_id], got %q", req.ID), ) return @@ -313,7 +319,7 @@ func (r *credentialsResource) ImportState(ctx context.Context, req resource.Impo resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("project_id"), idParts[0])...) resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("instance_id"), idParts[1])...) resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("credentials_id"), idParts[2])...) - tflog.Info(ctx, "Postgresql credentials state imported") + tflog.Info(ctx, "PostgreSQL credentials state imported") } func mapFields(credentialsResp *postgresql.CredentialsResponse, model *Model) error { diff --git a/stackit/services/postgresql/instance/datasource.go b/stackit/services/postgresql/instance/datasource.go index 181813d9c..82fac9698 100644 --- a/stackit/services/postgresql/instance/datasource.go +++ b/stackit/services/postgresql/instance/datasource.go @@ -6,12 +6,12 @@ import ( "github.com/hashicorp/terraform-plugin-framework/datasource" "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/terraform-provider-stackit/stackit/core" "github.com/stackitcloud/terraform-provider-stackit/stackit/validate" "github.com/hashicorp/terraform-plugin-framework/datasource/schema" - "github.com/hashicorp/terraform-plugin-framework/types" "github.com/stackitcloud/stackit-sdk-go/core/config" "github.com/stackitcloud/stackit-sdk-go/services/postgresql" ) @@ -45,7 +45,7 @@ func (r *instanceDataSource) Configure(ctx context.Context, req datasource.Confi providerData, ok := req.ProviderData.(core.ProviderData) if !ok { - resp.Diagnostics.AddError("Unexpected Data Source Configure Type", fmt.Sprintf("Expected stackit.ProviderData, got %T. Please report this issue to the provider developers.", req.ProviderData)) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error configuring API client", fmt.Sprintf("Expected configure type stackit.ProviderData, got %T", req.ProviderData)) return } @@ -64,19 +64,19 @@ func (r *instanceDataSource) Configure(ctx context.Context, req datasource.Confi } if err != nil { - resp.Diagnostics.AddError("Could not Configure API Client", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error configuring API client", fmt.Sprintf("Configuring client: %v", err)) return } - tflog.Info(ctx, "Postgresql zone client configured") r.client = apiClient + tflog.Info(ctx, "PostgreSQL zone client configured") } // Schema defines the schema for the resource. func (r *instanceDataSource) Schema(_ context.Context, _ datasource.SchemaRequest, resp *datasource.SchemaResponse) { descriptions := map[string]string{ "main": "PostgreSQL instance data source schema.", - "id": "Terraform's internal resource identifier. It is structured as \"`project_id`,`instance_id`\".", + "id": "Terraform's internal resource identifier. It is structured as \"`project_id`,`zone_id`\".", "instance_id": "ID of the PostgreSQL instance.", "project_id": "STACKIT Project ID to which the instance is associated.", "name": "Instance name.", @@ -169,37 +169,41 @@ func (r *instanceDataSource) Schema(_ context.Context, _ datasource.SchemaReques // 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 - var state Model - diags := req.Config.Get(ctx, &state) + var model Model + diags := req.Config.Get(ctx, &model) resp.Diagnostics.Append(diags...) if resp.Diagnostics.HasError() { return } - - projectId := state.ProjectId.ValueString() - instanceId := state.InstanceId.ValueString() + projectId := model.ProjectId.ValueString() + instanceId := model.InstanceId.ValueString() ctx = tflog.SetField(ctx, "project_id", projectId) ctx = tflog.SetField(ctx, "instance_id", instanceId) + instanceResp, err := r.client.GetInstance(ctx, projectId, instanceId).Execute() if err != nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Unable to read instance", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading instance", fmt.Sprintf("Calling API: %v", err)) return } - err = mapFields(instanceResp, &state) + err = mapFields(instanceResp, &model) if err != nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Mapping fields", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading instance", fmt.Sprintf("Processing API payload: %v", err)) return } // Compute and store values not present in the API response - loadPlanNameAndVersion(ctx, r.client, &resp.Diagnostics, &state) - if resp.Diagnostics.HasError() { + err = loadPlanNameAndVersion(ctx, r.client, &model) + if err != nil { + core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading instance", fmt.Sprintf("Loading service plan details: %v", err)) return } // Set refreshed state - diags = resp.State.Set(ctx, &state) + diags = resp.State.Set(ctx, &model) resp.Diagnostics.Append(diags...) - tflog.Info(ctx, "Postgresql instance read") + if resp.Diagnostics.HasError() { + return + } + tflog.Info(ctx, "PostgreSQL instance read") } diff --git a/stackit/services/postgresql/instance/resource.go b/stackit/services/postgresql/instance/resource.go index e3b0d0c0b..d703e6e09 100644 --- a/stackit/services/postgresql/instance/resource.go +++ b/stackit/services/postgresql/instance/resource.go @@ -8,21 +8,21 @@ import ( "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator" "github.com/hashicorp/terraform-plugin-framework/attr" - "github.com/hashicorp/terraform-plugin-framework/diag" + "github.com/hashicorp/terraform-plugin-framework/schema/validator" + "github.com/hashicorp/terraform-plugin-framework/types/basetypes" + "github.com/hashicorp/terraform-plugin-log/tflog" + "github.com/stackitcloud/terraform-provider-stackit/stackit/conversion" + "github.com/stackitcloud/terraform-provider-stackit/stackit/core" + "github.com/stackitcloud/terraform-provider-stackit/stackit/validate" + "github.com/hashicorp/terraform-plugin-framework/path" "github.com/hashicorp/terraform-plugin-framework/resource" "github.com/hashicorp/terraform-plugin-framework/resource/schema" "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier" - "github.com/hashicorp/terraform-plugin-framework/schema/validator" "github.com/hashicorp/terraform-plugin-framework/types" - "github.com/hashicorp/terraform-plugin-framework/types/basetypes" - "github.com/hashicorp/terraform-plugin-log/tflog" "github.com/stackitcloud/stackit-sdk-go/core/config" "github.com/stackitcloud/stackit-sdk-go/services/postgresql" - "github.com/stackitcloud/terraform-provider-stackit/stackit/conversion" - "github.com/stackitcloud/terraform-provider-stackit/stackit/core" - "github.com/stackitcloud/terraform-provider-stackit/stackit/validate" ) // Ensure the implementation satisfies the expected interfaces. @@ -92,7 +92,7 @@ func (r *instanceResource) Configure(ctx context.Context, req resource.Configure providerData, ok := req.ProviderData.(core.ProviderData) if !ok { - resp.Diagnostics.AddError("Unexpected Resource Configure Type", fmt.Sprintf("Expected stackit.ProviderData, got %T. Please report this issue to the provider developers.", req.ProviderData)) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error configuring API client", fmt.Sprintf("Expected configure type stackit.ProviderData, got %T", req.ProviderData)) return } @@ -111,12 +111,12 @@ func (r *instanceResource) Configure(ctx context.Context, req resource.Configure } if err != nil { - resp.Diagnostics.AddError("Could not Configure API Client", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error configuring API client", fmt.Sprintf("Configuring client: %v", err)) return } - tflog.Info(ctx, "Postgresql zone client configured") r.client = apiClient + tflog.Info(ctx, "PostgreSQL instance client configured") } // Schema defines the schema for the resource. @@ -250,7 +250,6 @@ func (r *instanceResource) Schema(_ context.Context, _ resource.SchemaRequest, r // Create creates the resource and sets the initial Terraform state. func (r *instanceResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { // nolint:gocritic // function signature required by Terraform - // Retrieve values from plan var model Model diags := req.Plan.Get(ctx, &model) resp.Diagnostics.Append(diags...) @@ -260,11 +259,6 @@ func (r *instanceResource) Create(ctx context.Context, req resource.CreateReques projectId := model.ProjectId.ValueString() ctx = tflog.SetField(ctx, "project_id", projectId) - r.loadPlanId(ctx, &resp.Diagnostics, &model) - if resp.Diagnostics.HasError() { - return - } - var parameters = ¶metersModel{} var parametersPlugins *[]string if !(model.Parameters.IsNull() || model.Parameters.IsUnknown()) { @@ -288,6 +282,12 @@ func (r *instanceResource) Create(ctx context.Context, req resource.CreateReques } } + err := r.loadPlanId(ctx, &model) + if err != nil { + core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating instance", fmt.Sprintf("Loading service plan: %v", err)) + return + } + // Generate API request body from model payload, err := toCreatePayload(&model, parameters, parametersPlugins) if err != nil { @@ -313,15 +313,26 @@ func (r *instanceResource) Create(ctx context.Context, req resource.CreateReques return } - // Map response body to schema and populate Computed attribute values + // Map response body to schema err = mapFields(got, &model) if err != nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error mapping fields", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating instance", fmt.Sprintf("Processing API payload: %v", err)) return } + + // Compute and store values not present in the API response + err = loadPlanNameAndVersion(ctx, r.client, &model) + if err != nil { + core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading instance", fmt.Sprintf("Loading service plan details: %v", err)) + return + } + // Set state to fully populated data diags = resp.State.Set(ctx, model) resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } tflog.Info(ctx, "Postgresql instance created") } @@ -352,40 +363,44 @@ func toCreatePayload(model *Model, parameters *parametersModel, parametersPlugin // 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 - var state Model - diags := req.State.Get(ctx, &state) + var model Model + diags := req.State.Get(ctx, &model) resp.Diagnostics.Append(diags...) if resp.Diagnostics.HasError() { return } - projectId := state.ProjectId.ValueString() - instanceId := state.InstanceId.ValueString() + projectId := model.ProjectId.ValueString() + instanceId := model.InstanceId.ValueString() ctx = tflog.SetField(ctx, "project_id", projectId) ctx = tflog.SetField(ctx, "instance_id", instanceId) instanceResp, err := r.client.GetInstance(ctx, projectId, instanceId).Execute() if err != nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading instances", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading instance", fmt.Sprintf("Calling API: %v", err)) return } - // Map response body to schema and populate Computed attribute values - err = mapFields(instanceResp, &state) + // Map response body to schema + err = mapFields(instanceResp, &model) if err != nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error mapping fields", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading instance", fmt.Sprintf("Processing API payload: %v", err)) return } // Compute and store values not present in the API response - loadPlanNameAndVersion(ctx, r.client, &resp.Diagnostics, &state) - if resp.Diagnostics.HasError() { + err = loadPlanNameAndVersion(ctx, r.client, &model) + if err != nil { + core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading instance", fmt.Sprintf("Loading service plan details: %v", err)) return } // Set refreshed state - diags = resp.State.Set(ctx, state) + diags = resp.State.Set(ctx, model) resp.Diagnostics.Append(diags...) - tflog.Info(ctx, "Postgresql instance read") + if resp.Diagnostics.HasError() { + return + } + tflog.Info(ctx, "PostgreSQL instance read") } // Update updates the resource and sets the updated Terraform state on success. @@ -401,11 +416,6 @@ func (r *instanceResource) Update(ctx context.Context, req resource.UpdateReques ctx = tflog.SetField(ctx, "project_id", projectId) ctx = tflog.SetField(ctx, "instance_id", instanceId) - r.loadPlanId(ctx, &resp.Diagnostics, &model) - if resp.Diagnostics.HasError() { - return - } - var parameters = ¶metersModel{} var parametersPlugins *[]string if !(model.Parameters.IsNull() || model.Parameters.IsUnknown()) { @@ -426,16 +436,22 @@ func (r *instanceResource) Update(ctx context.Context, req resource.UpdateReques } } + err := r.loadPlanId(ctx, &model) + if err != nil { + core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating instance", fmt.Sprintf("Loading service plan: %v", err)) + return + } + // Generate API request body from model payload, err := toUpdatePayload(&model, parameters, parametersPlugins) if err != nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating instance", fmt.Sprintf("Could not create API payload: %v", err)) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating instance", fmt.Sprintf("Creating API payload: %v", err)) return } // Update existing instance err = r.client.UpdateInstance(ctx, projectId, instanceId).UpdateInstancePayload(*payload).Execute() if err != nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating instance", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating instance", fmt.Sprintf("Calling API: %v", err)) return } wr, err := postgresql.UpdateInstanceWaitHandler(ctx, r.client, projectId, instanceId).SetTimeout(15 * time.Minute).WaitWithContext(ctx) @@ -449,15 +465,26 @@ func (r *instanceResource) Update(ctx context.Context, req resource.UpdateReques return } - // Map response body to schema and populate Computed attribute values + // Map response body to schema err = mapFields(got, &model) if err != nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error mapping fields in update", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating instance", fmt.Sprintf("Processing API payload: %v", err)) + return + } + + // Compute and store values not present in the API response + err = loadPlanNameAndVersion(ctx, r.client, &model) + if err != nil { + core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading instance", fmt.Sprintf("Loading service plan details: %v", err)) return } + diags = resp.State.Set(ctx, model) resp.Diagnostics.Append(diags...) - tflog.Info(ctx, "Postgresql instance updated") + if resp.Diagnostics.HasError() { + return + } + tflog.Info(ctx, "PostgreSQL instance updated") } func toUpdatePayload(model *Model, parameters *parametersModel, parametersPlugins *[]string) (*postgresql.UpdateInstancePayload, error) { @@ -500,7 +527,7 @@ func (r *instanceResource) Delete(ctx context.Context, req resource.DeleteReques // Delete existing instance err := r.client.DeleteInstance(ctx, projectId, instanceId).Execute() if err != nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error deleting instance", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error deleting instance", fmt.Sprintf("Calling API: %v", err)) return } _, err = postgresql.DeleteInstanceWaitHandler(ctx, r.client, projectId, instanceId).SetTimeout(15 * time.Minute).WaitWithContext(ctx) @@ -508,7 +535,7 @@ func (r *instanceResource) Delete(ctx context.Context, req resource.DeleteReques core.LogAndAddError(ctx, &resp.Diagnostics, "Error deleting instance", fmt.Sprintf("Instance deletion waiting: %v", err)) return } - tflog.Info(ctx, "Postgresql instance deleted") + tflog.Info(ctx, "PostgreSQL instance deleted") } // ImportState imports a resource into the Terraform state on success. @@ -517,8 +544,8 @@ func (r *instanceResource) ImportState(ctx context.Context, req resource.ImportS idParts := strings.Split(req.ID, core.Separator) if len(idParts) != 2 || idParts[0] == "" || idParts[1] == "" { - resp.Diagnostics.AddError( - "Unexpected Import Identifier", + core.LogAndAddError(ctx, &resp.Diagnostics, + "Unexpected import identifier", fmt.Sprintf("Expected import identifier with format: [project_id],[instance_id] Got: %q", req.ID), ) return @@ -526,7 +553,7 @@ func (r *instanceResource) ImportState(ctx context.Context, req resource.ImportS resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("project_id"), idParts[0])...) resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("instance_id"), idParts[1])...) - tflog.Info(ctx, "Postgresql instance state imported") + tflog.Info(ctx, "PostgreSQL instance state imported") } func mapFields(instance *postgresql.Instance, model *Model) error { @@ -669,12 +696,11 @@ func mapParameters(params map[string]interface{}) (types.Object, error) { return output, nil } -func (r *instanceResource) loadPlanId(ctx context.Context, diags *diag.Diagnostics, model *Model) { +func (r *instanceResource) loadPlanId(ctx context.Context, model *Model) error { projectId := model.ProjectId.ValueString() res, err := r.client.GetOfferings(ctx, projectId).Execute() if err != nil { - diags.AddError("Failed to list PostgreSQL offerings", err.Error()) - return + return fmt.Errorf("getting PostgreSQL offerings: %v", err) } version := model.Version.ValueString() @@ -695,26 +721,24 @@ func (r *instanceResource) loadPlanId(ctx context.Context, diags *diag.Diagnosti } if strings.EqualFold(*plan.Name, planName) && plan.Id != nil { model.PlanId = types.StringPointerValue(plan.Id) - return + return nil } availablePlanNames = fmt.Sprintf("%s\n- %s", availablePlanNames, *plan.Name) } } if !isValidVersion { - diags.AddError("Invalid version", fmt.Sprintf("Couldn't find version '%s', available versions are:%s", version, availableVersions)) - return + return fmt.Errorf("couldn't find version '%s', available versions are: %s", version, availableVersions) } - diags.AddError("Invalid plan_name", fmt.Sprintf("Couldn't find plan_name '%s' for version %s, available names are:%s", planName, version, availablePlanNames)) + return fmt.Errorf("couldn't find plan_name '%s' for version %s, available names are: %s", planName, version, availablePlanNames) } -func loadPlanNameAndVersion(ctx context.Context, client *postgresql.APIClient, diags *diag.Diagnostics, model *Model) { +func loadPlanNameAndVersion(ctx context.Context, client *postgresql.APIClient, model *Model) error { projectId := model.ProjectId.ValueString() planId := model.PlanId.ValueString() res, err := client.GetOfferings(ctx, projectId).Execute() if err != nil { - diags.AddError("Failed to list PostgreSQL offerings", err.Error()) - return + return fmt.Errorf("getting PostgreSQL offerings: %v", err) } for _, offer := range *res.Offerings { @@ -722,10 +746,10 @@ func loadPlanNameAndVersion(ctx context.Context, client *postgresql.APIClient, d if strings.EqualFold(*plan.Id, planId) && plan.Id != nil { model.PlanName = types.StringPointerValue(plan.Name) model.Version = types.StringPointerValue(offer.Version) - return + return nil } } } - diags.AddWarning("Failed to get plan_name and version", fmt.Sprintf("Couldn't find plan_name and version for plan_id = %s", planId)) + return fmt.Errorf("couldn't find plan_name and version for plan_id '%s'", planId) } diff --git a/stackit/services/rabbitmq/credentials/datasource.go b/stackit/services/rabbitmq/credentials/datasource.go index 515856859..a87f3aeac 100644 --- a/stackit/services/rabbitmq/credentials/datasource.go +++ b/stackit/services/rabbitmq/credentials/datasource.go @@ -45,7 +45,7 @@ func (r *credentialsDataSource) Configure(ctx context.Context, req datasource.Co providerData, ok := req.ProviderData.(core.ProviderData) if !ok { - resp.Diagnostics.AddError("Unexpected Data Source Configure Type", fmt.Sprintf("Expected stackit.ProviderData, got %T. Please report this issue to the provider developers.", req.ProviderData)) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error configuring API client", fmt.Sprintf("Expected configure type stackit.ProviderData, got %T", req.ProviderData)) return } @@ -64,12 +64,12 @@ func (r *credentialsDataSource) Configure(ctx context.Context, req datasource.Co } if err != nil { - resp.Diagnostics.AddError("Could not Configure API Client", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error configuring API client", fmt.Sprintf("Configuring client: %v", err)) return } - tflog.Info(ctx, "RabbitMQ zone client configured") r.client = apiClient + tflog.Info(ctx, "RabbitMQ credentials client configured") } // Schema defines the schema for the resource. @@ -160,19 +160,22 @@ func (r *credentialsDataSource) Read(ctx context.Context, req datasource.ReadReq recordSetResp, err := r.client.GetCredentials(ctx, projectId, instanceId, credentialsId).Execute() if err != nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading credentials", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading credentials", fmt.Sprintf("Calling API: %v", err)) return } - // Map response body to schema and populate Computed attribute values + // Map response body to schema err = mapFields(recordSetResp, &model) if err != nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error mapping fields", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading credentials", fmt.Sprintf("Processing API payload: %v", err)) return } // Set refreshed state diags = resp.State.Set(ctx, model) resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } tflog.Info(ctx, "RabbitMQ credentials read") } diff --git a/stackit/services/rabbitmq/credentials/resource.go b/stackit/services/rabbitmq/credentials/resource.go index 9de8cc905..5b2ce9b73 100644 --- a/stackit/services/rabbitmq/credentials/resource.go +++ b/stackit/services/rabbitmq/credentials/resource.go @@ -25,9 +25,9 @@ import ( // Ensure the implementation satisfies the expected interfaces. var ( - _ resource.Resource = &rabbitMQCredentialsResource{} - _ resource.ResourceWithConfigure = &rabbitMQCredentialsResource{} - _ resource.ResourceWithImportState = &rabbitMQCredentialsResource{} + _ resource.Resource = &rabbitmqCredentialsResource{} + _ resource.ResourceWithConfigure = &rabbitmqCredentialsResource{} + _ resource.ResourceWithImportState = &rabbitmqCredentialsResource{} ) type Model struct { @@ -47,21 +47,21 @@ type Model struct { // NewCredentialsResource is a helper function to simplify the provider implementation. func NewCredentialsResource() resource.Resource { - return &rabbitMQCredentialsResource{} + return &rabbitmqCredentialsResource{} } // credentialsResource is the resource implementation. -type rabbitMQCredentialsResource struct { +type rabbitmqCredentialsResource struct { client *rabbitmq.APIClient } // Metadata returns the resource type name. -func (r *rabbitMQCredentialsResource) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { +func (r *rabbitmqCredentialsResource) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { resp.TypeName = req.ProviderTypeName + "_rabbitmq_credentials" } // Configure adds the provider configured client to the resource. -func (r *rabbitMQCredentialsResource) Configure(ctx context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { +func (r *rabbitmqCredentialsResource) Configure(ctx context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { // Prevent panic if the provider has not been configured. if req.ProviderData == nil { return @@ -69,7 +69,7 @@ func (r *rabbitMQCredentialsResource) Configure(ctx context.Context, req resourc providerData, ok := req.ProviderData.(core.ProviderData) if !ok { - resp.Diagnostics.AddError("Unexpected Resource Configure Type", fmt.Sprintf("Expected stackit.ProviderData, got %T. Please report this issue to the provider developers.", req.ProviderData)) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error configuring API client", fmt.Sprintf("Expected configure type stackit.ProviderData, got %T", req.ProviderData)) return } @@ -88,16 +88,16 @@ func (r *rabbitMQCredentialsResource) Configure(ctx context.Context, req resourc } if err != nil { - resp.Diagnostics.AddError("Could not Configure API Client", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error configuring API client", fmt.Sprintf("Configuring client: %v", err)) return } - tflog.Info(ctx, "RabbitMQ zone client configured") r.client = apiClient + tflog.Info(ctx, "RabbitMQ credentials client configured") } // Schema defines the schema for the resource. -func (r *rabbitMQCredentialsResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) { +func (r *rabbitmqCredentialsResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) { descriptions := map[string]string{ "main": "RabbitMQ credentials resource schema.", "id": "Terraform's internal resource identifier. It is structured as \"`project_id`,`instance_id`,`credentials_id`\".", @@ -182,7 +182,7 @@ func (r *rabbitMQCredentialsResource) Schema(_ context.Context, _ resource.Schem } // Create creates the resource and sets the initial Terraform state. -func (r *rabbitMQCredentialsResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { // nolint:gocritic // function signature required by Terraform +func (r *rabbitmqCredentialsResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { // nolint:gocritic // function signature required by Terraform var model Model diags := req.Plan.Get(ctx, &model) resp.Diagnostics.Append(diags...) @@ -218,19 +218,22 @@ func (r *rabbitMQCredentialsResource) Create(ctx context.Context, req resource.C return } - // Map response body to schema and populate Computed attribute values + // Map response body to schema err = mapFields(got, &model) if err != nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error mapping fields", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating credentials", fmt.Sprintf("Processing API payload: %v", err)) return } diags = resp.State.Set(ctx, model) resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } tflog.Info(ctx, "RabbitMQ credentials created") } // Read refreshes the Terraform state with the latest data. -func (r *rabbitMQCredentialsResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { // nolint:gocritic // function signature required by Terraform +func (r *rabbitmqCredentialsResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { // nolint:gocritic // function signature required by Terraform var model Model diags := req.State.Get(ctx, &model) resp.Diagnostics.Append(diags...) @@ -246,31 +249,34 @@ func (r *rabbitMQCredentialsResource) Read(ctx context.Context, req resource.Rea recordSetResp, err := r.client.GetCredentials(ctx, projectId, instanceId, credentialsId).Execute() if err != nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading credentials", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading credentials", fmt.Sprintf("Calling API: %v", err)) return } - // Map response body to schema and populate Computed attribute values + // Map response body to schema err = mapFields(recordSetResp, &model) if err != nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error mapping fields", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading credentials", fmt.Sprintf("Processing API payload: %v", err)) return } // Set refreshed state diags = resp.State.Set(ctx, model) resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } tflog.Info(ctx, "RabbitMQ credentials read") } // Update updates the resource and sets the updated Terraform state on success. -func (r *rabbitMQCredentialsResource) Update(_ context.Context, _ resource.UpdateRequest, resp *resource.UpdateResponse) { // nolint:gocritic // function signature required by Terraform +func (r *rabbitmqCredentialsResource) Update(ctx context.Context, _ resource.UpdateRequest, resp *resource.UpdateResponse) { // nolint:gocritic // function signature required by Terraform // Update shouldn't be called - resp.Diagnostics.AddError("Error updating credentials", "credentials can't be updated") + core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating credentials", "Credentials can't be updated") } // Delete deletes the resource and removes the Terraform state on success. -func (r *rabbitMQCredentialsResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { // nolint:gocritic // function signature required by Terraform +func (r *rabbitmqCredentialsResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { // nolint:gocritic // function signature required by Terraform var model Model diags := req.State.Get(ctx, &model) resp.Diagnostics.Append(diags...) @@ -288,7 +294,7 @@ func (r *rabbitMQCredentialsResource) Delete(ctx context.Context, req resource.D // Delete existing record set err := r.client.DeleteCredentials(ctx, projectId, instanceId, credentialsId).Execute() if err != nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error deleting credentials", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error deleting credentials", fmt.Sprintf("Calling API: %v", err)) } _, err = rabbitmq.DeleteCredentialsWaitHandler(ctx, r.client, projectId, instanceId, credentialsId).SetTimeout(1 * time.Minute).WaitWithContext(ctx) if err != nil { @@ -300,11 +306,11 @@ func (r *rabbitMQCredentialsResource) Delete(ctx context.Context, req resource.D // ImportState imports a resource into the Terraform state on success. // The expected format of the resource import identifier is: project_id,instance_id,credentials_id -func (r *rabbitMQCredentialsResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { +func (r *rabbitmqCredentialsResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { idParts := strings.Split(req.ID, core.Separator) if len(idParts) != 3 || idParts[0] == "" || idParts[1] == "" || idParts[2] == "" { core.LogAndAddError(ctx, &resp.Diagnostics, - "Unexpected Import Identifier", + "Unexpected import identifier", fmt.Sprintf("Expected import identifier with format [project_id],[instance_id],[credentials_id], got %q", req.ID), ) return diff --git a/stackit/services/rabbitmq/instance/datasource.go b/stackit/services/rabbitmq/instance/datasource.go index dad85ee2d..87631477a 100644 --- a/stackit/services/rabbitmq/instance/datasource.go +++ b/stackit/services/rabbitmq/instance/datasource.go @@ -44,7 +44,7 @@ func (r *instanceDataSource) Configure(ctx context.Context, req datasource.Confi providerData, ok := req.ProviderData.(core.ProviderData) if !ok { - resp.Diagnostics.AddError("Unexpected Data Source Configure Type", fmt.Sprintf("Expected stackit.ProviderData, got %T. Please report this issue to the provider developers.", req.ProviderData)) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error configuring API client", fmt.Sprintf("Expected configure type stackit.ProviderData, got %T", req.ProviderData)) return } @@ -63,19 +63,19 @@ func (r *instanceDataSource) Configure(ctx context.Context, req datasource.Confi } if err != nil { - resp.Diagnostics.AddError("Could not Configure API Client", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error configuring API client", fmt.Sprintf("Configuring client: %v", err)) return } - tflog.Info(ctx, "RabbitMQ zone client configured") r.client = apiClient + tflog.Info(ctx, "RabbitMQ zone client configured") } // Schema defines the schema for the resource. func (r *instanceDataSource) Schema(_ context.Context, _ datasource.SchemaRequest, resp *datasource.SchemaResponse) { descriptions := map[string]string{ "main": "RabbitMQ instance data source schema.", - "id": "Terraform's internal resource identifier. It is structured as \"`project_id`,`instance_id`\".", + "id": "Terraform's internal resource identifier. It is structured as \"`project_id`,`zone_id`\".", "instance_id": "ID of the RabbitMQ instance.", "project_id": "STACKIT Project ID to which the instance is associated.", "name": "Instance name.", @@ -152,37 +152,41 @@ func (r *instanceDataSource) Schema(_ context.Context, _ datasource.SchemaReques // 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 - var state Model - diags := req.Config.Get(ctx, &state) + var model Model + diags := req.Config.Get(ctx, &model) resp.Diagnostics.Append(diags...) if resp.Diagnostics.HasError() { return } - - projectId := state.ProjectId.ValueString() - instanceId := state.InstanceId.ValueString() + projectId := model.ProjectId.ValueString() + instanceId := model.InstanceId.ValueString() ctx = tflog.SetField(ctx, "project_id", projectId) ctx = tflog.SetField(ctx, "instance_id", instanceId) + instanceResp, err := r.client.GetInstance(ctx, projectId, instanceId).Execute() if err != nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Unable to read instance", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading instance", fmt.Sprintf("Calling API: %v", err)) return } - err = mapFields(instanceResp, &state) + err = mapFields(instanceResp, &model) if err != nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Mapping fields", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading instance", fmt.Sprintf("Processing API payload: %v", err)) return } // Compute and store values not present in the API response - loadPlanNameAndVersion(ctx, r.client, &resp.Diagnostics, &state) - if resp.Diagnostics.HasError() { + err = loadPlanNameAndVersion(ctx, r.client, &model) + if err != nil { + core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading instance", fmt.Sprintf("Loading service plan details: %v", err)) return } // Set refreshed state - diags = resp.State.Set(ctx, &state) + diags = resp.State.Set(ctx, &model) resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } tflog.Info(ctx, "RabbitMQ instance read") } diff --git a/stackit/services/rabbitmq/instance/resource.go b/stackit/services/rabbitmq/instance/resource.go index 0cd3b17da..acee1d3dd 100644 --- a/stackit/services/rabbitmq/instance/resource.go +++ b/stackit/services/rabbitmq/instance/resource.go @@ -8,8 +8,6 @@ import ( "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator" "github.com/hashicorp/terraform-plugin-framework/attr" - "github.com/hashicorp/terraform-plugin-framework/diag" - "github.com/hashicorp/terraform-plugin-framework/resource/schema/objectplanmodifier" "github.com/hashicorp/terraform-plugin-framework/schema/validator" "github.com/hashicorp/terraform-plugin-framework/types/basetypes" "github.com/hashicorp/terraform-plugin-log/tflog" @@ -83,7 +81,7 @@ func (r *instanceResource) Configure(ctx context.Context, req resource.Configure providerData, ok := req.ProviderData.(core.ProviderData) if !ok { - resp.Diagnostics.AddError("Unexpected Resource Configure Type", fmt.Sprintf("Expected stackit.ProviderData, got %T. Please report this issue to the provider developers.", req.ProviderData)) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error configuring API client", fmt.Sprintf("Expected configure type stackit.ProviderData, got %T", req.ProviderData)) return } @@ -102,12 +100,12 @@ func (r *instanceResource) Configure(ctx context.Context, req resource.Configure } if err != nil { - resp.Diagnostics.AddError("Could not Configure API Client", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error configuring API client", fmt.Sprintf("Configuring client: %v", err)) return } - tflog.Info(ctx, "rabbitmq zone client configured") r.client = apiClient + tflog.Info(ctx, "RabbitMQ instance client configured") } // Schema defines the schema for the resource. @@ -184,34 +182,40 @@ func (r *instanceResource) Schema(_ context.Context, _ resource.SchemaRequest, r "sgw_acl": schema.StringAttribute{ Optional: true, Computed: true, - Validators: []validator.String{ - stringvalidator.LengthAtLeast(1), - }, - PlanModifiers: []planmodifier.String{ - stringplanmodifier.UseStateForUnknown(), - }, }, }, Optional: true, Computed: true, - PlanModifiers: []planmodifier.Object{ - objectplanmodifier.UseStateForUnknown(), - }, }, "cf_guid": schema.StringAttribute{ Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, }, "cf_space_guid": schema.StringAttribute{ Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, }, "dashboard_url": schema.StringAttribute{ Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, }, "image_url": schema.StringAttribute{ Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, }, "cf_organization_guid": schema.StringAttribute{ Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, }, }, } @@ -228,11 +232,6 @@ func (r *instanceResource) Create(ctx context.Context, req resource.CreateReques projectId := model.ProjectId.ValueString() ctx = tflog.SetField(ctx, "project_id", projectId) - r.loadPlanId(ctx, &resp.Diagnostics, &model) - if resp.Diagnostics.HasError() { - return - } - var parameters = ¶metersModel{} if !(model.Parameters.IsNull() || model.Parameters.IsUnknown()) { diags = model.Parameters.As(ctx, parameters, basetypes.ObjectAsOptions{}) @@ -242,6 +241,12 @@ func (r *instanceResource) Create(ctx context.Context, req resource.CreateReques } } + err := r.loadPlanId(ctx, &model) + if err != nil { + core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating instance", fmt.Sprintf("Loading service plan: %v", err)) + return + } + // Generate API request body from model payload, err := toCreatePayload(&model, parameters) if err != nil { @@ -267,75 +272,69 @@ func (r *instanceResource) Create(ctx context.Context, req resource.CreateReques return } - // Map response body to schema and populate Computed attribute values + // Map response body to schema err = mapFields(got, &model) if err != nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error mapping fields", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating instance", fmt.Sprintf("Processing API payload: %v", err)) return } + + // Compute and store values not present in the API response + err = loadPlanNameAndVersion(ctx, r.client, &model) + if err != nil { + core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading instance", fmt.Sprintf("Loading service plan details: %v", err)) + return + } + // Set state to fully populated data diags = resp.State.Set(ctx, model) resp.Diagnostics.Append(diags...) - tflog.Info(ctx, "rabbitmq instance created") -} - -func toCreatePayload(model *Model, parameters *parametersModel) (*rabbitmq.CreateInstancePayload, error) { - if model == nil { - return nil, fmt.Errorf("nil model") - } - if parameters == nil { - return &rabbitmq.CreateInstancePayload{ - InstanceName: model.Name.ValueStringPointer(), - PlanId: model.PlanId.ValueStringPointer(), - }, nil - } - payloadParams := &rabbitmq.InstanceParameters{} - if parameters.SgwAcl.ValueString() != "" { - payloadParams.SgwAcl = parameters.SgwAcl.ValueStringPointer() + if resp.Diagnostics.HasError() { + return } - return &rabbitmq.CreateInstancePayload{ - InstanceName: model.Name.ValueStringPointer(), - Parameters: payloadParams, - PlanId: model.PlanId.ValueStringPointer(), - }, nil + tflog.Info(ctx, "RabbitMQ instance created") } // 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 - var state Model - diags := req.State.Get(ctx, &state) + var model Model + diags := req.State.Get(ctx, &model) resp.Diagnostics.Append(diags...) if resp.Diagnostics.HasError() { return } - projectId := state.ProjectId.ValueString() - instanceId := state.InstanceId.ValueString() + projectId := model.ProjectId.ValueString() + instanceId := model.InstanceId.ValueString() ctx = tflog.SetField(ctx, "project_id", projectId) ctx = tflog.SetField(ctx, "instance_id", instanceId) instanceResp, err := r.client.GetInstance(ctx, projectId, instanceId).Execute() if err != nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading instances", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading instance", fmt.Sprintf("Calling API: %v", err)) return } - // Map response body to schema and populate Computed attribute values - err = mapFields(instanceResp, &state) + // Map response body to schema + err = mapFields(instanceResp, &model) if err != nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error mapping fields", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading instance", fmt.Sprintf("Processing API payload: %v", err)) return } // Compute and store values not present in the API response - loadPlanNameAndVersion(ctx, r.client, &resp.Diagnostics, &state) - if resp.Diagnostics.HasError() { + err = loadPlanNameAndVersion(ctx, r.client, &model) + if err != nil { + core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading instance", fmt.Sprintf("Loading service plan details: %v", err)) return } // Set refreshed state - diags = resp.State.Set(ctx, state) + diags = resp.State.Set(ctx, model) resp.Diagnostics.Append(diags...) - tflog.Info(ctx, "rabbitmq instance read") + if resp.Diagnostics.HasError() { + return + } + tflog.Info(ctx, "RabbitMQ instance read") } // Update updates the resource and sets the updated Terraform state on success. @@ -351,11 +350,6 @@ func (r *instanceResource) Update(ctx context.Context, req resource.UpdateReques ctx = tflog.SetField(ctx, "project_id", projectId) ctx = tflog.SetField(ctx, "instance_id", instanceId) - r.loadPlanId(ctx, &resp.Diagnostics, &model) - if resp.Diagnostics.HasError() { - return - } - var parameters = ¶metersModel{} if !(model.Parameters.IsNull() || model.Parameters.IsUnknown()) { diags = model.Parameters.As(ctx, parameters, basetypes.ObjectAsOptions{}) @@ -365,16 +359,22 @@ func (r *instanceResource) Update(ctx context.Context, req resource.UpdateReques } } + err := r.loadPlanId(ctx, &model) + if err != nil { + core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating instance", fmt.Sprintf("Loading service plan: %v", err)) + return + } + // Generate API request body from model payload, err := toUpdatePayload(&model, parameters) if err != nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating instance", fmt.Sprintf("Could not create API payload: %v", err)) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating instance", fmt.Sprintf("Creating API payload: %v", err)) return } // Update existing instance err = r.client.UpdateInstance(ctx, projectId, instanceId).UpdateInstancePayload(*payload).Execute() if err != nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating instance", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating instance", fmt.Sprintf("Calling API: %v", err)) return } wr, err := rabbitmq.UpdateInstanceWaitHandler(ctx, r.client, projectId, instanceId).SetTimeout(15 * time.Minute).WaitWithContext(ctx) @@ -388,37 +388,31 @@ func (r *instanceResource) Update(ctx context.Context, req resource.UpdateReques return } - // Map response body to schema and populate Computed attribute values + // Map response body to schema err = mapFields(got, &model) if err != nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error mapping fields in update", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating instance", fmt.Sprintf("Processing API payload: %v", err)) return } - diags = resp.State.Set(ctx, model) - resp.Diagnostics.Append(diags...) - tflog.Info(ctx, "rabbitmq instance updated") -} -func toUpdatePayload(model *Model, parameters *parametersModel) (*rabbitmq.UpdateInstancePayload, error) { - if model == nil { - return nil, fmt.Errorf("nil model") + // Compute and store values not present in the API response + err = loadPlanNameAndVersion(ctx, r.client, &model) + if err != nil { + core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading instance", fmt.Sprintf("Loading service plan details: %v", err)) + return } - if parameters == nil { - return &rabbitmq.UpdateInstancePayload{ - PlanId: model.PlanId.ValueStringPointer(), - }, nil + diags = resp.State.Set(ctx, model) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return } - return &rabbitmq.UpdateInstancePayload{ - Parameters: &rabbitmq.InstanceParameters{ - SgwAcl: parameters.SgwAcl.ValueStringPointer(), - }, - PlanId: model.PlanId.ValueStringPointer(), - }, nil + tflog.Info(ctx, "RabbitMQ instance updated") } // 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 + // Retrieve values from state var model Model diags := req.State.Get(ctx, &model) resp.Diagnostics.Append(diags...) @@ -433,7 +427,7 @@ func (r *instanceResource) Delete(ctx context.Context, req resource.DeleteReques // Delete existing instance err := r.client.DeleteInstance(ctx, projectId, instanceId).Execute() if err != nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error deleting instance", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error deleting instance", fmt.Sprintf("Calling API: %v", err)) return } _, err = rabbitmq.DeleteInstanceWaitHandler(ctx, r.client, projectId, instanceId).SetTimeout(15 * time.Minute).WaitWithContext(ctx) @@ -441,7 +435,7 @@ func (r *instanceResource) Delete(ctx context.Context, req resource.DeleteReques core.LogAndAddError(ctx, &resp.Diagnostics, "Error deleting instance", fmt.Sprintf("Instance deletion waiting: %v", err)) return } - tflog.Info(ctx, "rabbitmq instance deleted") + tflog.Info(ctx, "RabbitMQ instance deleted") } // ImportState imports a resource into the Terraform state on success. @@ -450,8 +444,8 @@ func (r *instanceResource) ImportState(ctx context.Context, req resource.ImportS idParts := strings.Split(req.ID, core.Separator) if len(idParts) != 2 || idParts[0] == "" || idParts[1] == "" { - resp.Diagnostics.AddError( - "Unexpected Import Identifier", + core.LogAndAddError(ctx, &resp.Diagnostics, + "Unexpected import identifier", fmt.Sprintf("Expected import identifier with format: [project_id],[instance_id] Got: %q", req.ID), ) return @@ -602,12 +596,50 @@ func mapParameters(params map[string]interface{}) (types.Object, error) { return output, nil } -func (r *instanceResource) loadPlanId(ctx context.Context, diags *diag.Diagnostics, model *Model) { +func toCreatePayload(model *Model, parameters *parametersModel) (*rabbitmq.CreateInstancePayload, error) { + if model == nil { + return nil, fmt.Errorf("nil model") + } + if parameters == nil { + return &rabbitmq.CreateInstancePayload{ + InstanceName: model.Name.ValueStringPointer(), + PlanId: model.PlanId.ValueStringPointer(), + }, nil + } + payloadParams := &rabbitmq.InstanceParameters{} + if parameters.SgwAcl.ValueString() != "" { + payloadParams.SgwAcl = parameters.SgwAcl.ValueStringPointer() + } + return &rabbitmq.CreateInstancePayload{ + InstanceName: model.Name.ValueStringPointer(), + Parameters: payloadParams, + PlanId: model.PlanId.ValueStringPointer(), + }, nil +} + +func toUpdatePayload(model *Model, parameters *parametersModel) (*rabbitmq.UpdateInstancePayload, error) { + if model == nil { + return nil, fmt.Errorf("nil model") + } + + if parameters == nil { + return &rabbitmq.UpdateInstancePayload{ + PlanId: model.PlanId.ValueStringPointer(), + }, nil + } + return &rabbitmq.UpdateInstancePayload{ + Parameters: &rabbitmq.InstanceParameters{ + SgwAcl: parameters.SgwAcl.ValueStringPointer(), + }, + PlanId: model.PlanId.ValueStringPointer(), + }, nil +} + +func (r *instanceResource) loadPlanId(ctx context.Context, model *Model) error { projectId := model.ProjectId.ValueString() res, err := r.client.GetOfferings(ctx, projectId).Execute() if err != nil { - diags.AddError("Failed to list RabbitMQ offerings", err.Error()) - return + return fmt.Errorf("getting RabbitMQ offerings: %v", err) } version := model.Version.ValueString() @@ -628,26 +660,24 @@ func (r *instanceResource) loadPlanId(ctx context.Context, diags *diag.Diagnosti } if strings.EqualFold(*plan.Name, planName) && plan.Id != nil { model.PlanId = types.StringPointerValue(plan.Id) - return + return nil } availablePlanNames = fmt.Sprintf("%s\n- %s", availablePlanNames, *plan.Name) } } if !isValidVersion { - diags.AddError("Invalid version", fmt.Sprintf("Couldn't find version '%s', available versions are:%s", version, availableVersions)) - return + return fmt.Errorf("couldn't find version '%s', available versions are: %s", version, availableVersions) } - diags.AddError("Invalid plan_name", fmt.Sprintf("Couldn't find plan_name '%s' for version %s, available names are:%s", planName, version, availablePlanNames)) + return fmt.Errorf("couldn't find plan_name '%s' for version %s, available names are: %s", planName, version, availablePlanNames) } -func loadPlanNameAndVersion(ctx context.Context, client *rabbitmq.APIClient, diags *diag.Diagnostics, model *Model) { +func loadPlanNameAndVersion(ctx context.Context, client *rabbitmq.APIClient, model *Model) error { projectId := model.ProjectId.ValueString() planId := model.PlanId.ValueString() res, err := client.GetOfferings(ctx, projectId).Execute() if err != nil { - diags.AddError("Failed to list RabbitMQ offerings", err.Error()) - return + return fmt.Errorf("getting RabbitMQ offerings: %v", err) } for _, offer := range *res.Offerings { @@ -655,10 +685,10 @@ func loadPlanNameAndVersion(ctx context.Context, client *rabbitmq.APIClient, dia if strings.EqualFold(*plan.Id, planId) && plan.Id != nil { model.PlanName = types.StringPointerValue(plan.Name) model.Version = types.StringPointerValue(offer.Version) - return + return nil } } } - diags.AddWarning("Failed to get plan_name and version", fmt.Sprintf("Couldn't find plan_name and version for plan_id = %s", planId)) + return fmt.Errorf("couldn't find plan_name and version for plan_id '%s'", planId) } diff --git a/stackit/services/redis/credentials/datasource.go b/stackit/services/redis/credentials/datasource.go index a7bcb8ba3..56b9f7dc5 100644 --- a/stackit/services/redis/credentials/datasource.go +++ b/stackit/services/redis/credentials/datasource.go @@ -45,7 +45,7 @@ func (r *credentialsDataSource) Configure(ctx context.Context, req datasource.Co providerData, ok := req.ProviderData.(core.ProviderData) if !ok { - resp.Diagnostics.AddError("Unexpected Data Source Configure Type", fmt.Sprintf("Expected stackit.ProviderData, got %T. Please report this issue to the provider developers.", req.ProviderData)) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error configuring API client", fmt.Sprintf("Expected configure type stackit.ProviderData, got %T", req.ProviderData)) return } @@ -64,12 +64,12 @@ func (r *credentialsDataSource) Configure(ctx context.Context, req datasource.Co } if err != nil { - resp.Diagnostics.AddError("Could not Configure API Client", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error configuring API client", fmt.Sprintf("Configuring client: %v", err)) return } - tflog.Info(ctx, "Redis zone client configured") r.client = apiClient + tflog.Info(ctx, "Redis credentials client configured") } // Schema defines the schema for the resource. @@ -160,19 +160,22 @@ func (r *credentialsDataSource) Read(ctx context.Context, req datasource.ReadReq recordSetResp, err := r.client.GetCredentials(ctx, projectId, instanceId, credentialsId).Execute() if err != nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading credentials", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading credentials", fmt.Sprintf("Calling API: %v", err)) return } - // Map response body to schema and populate Computed attribute values + // Map response body to schema err = mapFields(recordSetResp, &model) if err != nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error mapping fields", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading credentials", fmt.Sprintf("Processing API payload: %v", err)) return } // Set refreshed state diags = resp.State.Set(ctx, model) resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } tflog.Info(ctx, "Redis credentials read") } diff --git a/stackit/services/redis/credentials/resource.go b/stackit/services/redis/credentials/resource.go index 5844d42d1..75a9e150a 100644 --- a/stackit/services/redis/credentials/resource.go +++ b/stackit/services/redis/credentials/resource.go @@ -6,13 +6,13 @@ import ( "strings" "time" - "github.com/hashicorp/terraform-plugin-framework/attr" "github.com/hashicorp/terraform-plugin-framework/schema/validator" "github.com/hashicorp/terraform-plugin-log/tflog" "github.com/stackitcloud/terraform-provider-stackit/stackit/conversion" "github.com/stackitcloud/terraform-provider-stackit/stackit/core" "github.com/stackitcloud/terraform-provider-stackit/stackit/validate" + "github.com/hashicorp/terraform-plugin-framework/attr" "github.com/hashicorp/terraform-plugin-framework/path" "github.com/hashicorp/terraform-plugin-framework/resource" "github.com/hashicorp/terraform-plugin-framework/resource/schema" @@ -25,9 +25,9 @@ import ( // Ensure the implementation satisfies the expected interfaces. var ( - _ resource.Resource = &postgresCredentialsResource{} - _ resource.ResourceWithConfigure = &postgresCredentialsResource{} - _ resource.ResourceWithImportState = &postgresCredentialsResource{} + _ resource.Resource = &redisCredentialsResource{} + _ resource.ResourceWithConfigure = &redisCredentialsResource{} + _ resource.ResourceWithImportState = &redisCredentialsResource{} ) type Model struct { @@ -47,21 +47,21 @@ type Model struct { // NewCredentialsResource is a helper function to simplify the provider implementation. func NewCredentialsResource() resource.Resource { - return &postgresCredentialsResource{} + return &redisCredentialsResource{} } // credentialsResource is the resource implementation. -type postgresCredentialsResource struct { +type redisCredentialsResource struct { client *redis.APIClient } // Metadata returns the resource type name. -func (r *postgresCredentialsResource) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { +func (r *redisCredentialsResource) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { resp.TypeName = req.ProviderTypeName + "_redis_credentials" } // Configure adds the provider configured client to the resource. -func (r *postgresCredentialsResource) Configure(ctx context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { +func (r *redisCredentialsResource) Configure(ctx context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { // Prevent panic if the provider has not been configured. if req.ProviderData == nil { return @@ -69,7 +69,7 @@ func (r *postgresCredentialsResource) Configure(ctx context.Context, req resourc providerData, ok := req.ProviderData.(core.ProviderData) if !ok { - resp.Diagnostics.AddError("Unexpected Resource Configure Type", fmt.Sprintf("Expected stackit.ProviderData, got %T. Please report this issue to the provider developers.", req.ProviderData)) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error configuring API client", fmt.Sprintf("Expected configure type stackit.ProviderData, got %T", req.ProviderData)) return } @@ -88,16 +88,16 @@ func (r *postgresCredentialsResource) Configure(ctx context.Context, req resourc } if err != nil { - resp.Diagnostics.AddError("Could not Configure API Client", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error configuring API client", fmt.Sprintf("Configuring client: %v", err)) return } - tflog.Info(ctx, "Redis zone client configured") r.client = apiClient + tflog.Info(ctx, "Redis credentials client configured") } // Schema defines the schema for the resource. -func (r *postgresCredentialsResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) { +func (r *redisCredentialsResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) { descriptions := map[string]string{ "main": "Redis credentials resource schema.", "id": "Terraform's internal resource identifier. It is structured as \"`project_id`,`instance_id`,`credentials_id`\".", @@ -182,7 +182,7 @@ func (r *postgresCredentialsResource) Schema(_ context.Context, _ resource.Schem } // Create creates the resource and sets the initial Terraform state. -func (r *postgresCredentialsResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { // nolint:gocritic // function signature required by Terraform +func (r *redisCredentialsResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { // nolint:gocritic // function signature required by Terraform var model Model diags := req.Plan.Get(ctx, &model) resp.Diagnostics.Append(diags...) @@ -218,19 +218,22 @@ func (r *postgresCredentialsResource) Create(ctx context.Context, req resource.C return } - // Map response body to schema and populate Computed attribute values + // Map response body to schema err = mapFields(got, &model) if err != nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error mapping fields", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating credentials", fmt.Sprintf("Processing API payload: %v", err)) return } diags = resp.State.Set(ctx, model) resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } tflog.Info(ctx, "Redis credentials created") } // Read refreshes the Terraform state with the latest data. -func (r *postgresCredentialsResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { // nolint:gocritic // function signature required by Terraform +func (r *redisCredentialsResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { // nolint:gocritic // function signature required by Terraform var model Model diags := req.State.Get(ctx, &model) resp.Diagnostics.Append(diags...) @@ -246,31 +249,34 @@ func (r *postgresCredentialsResource) Read(ctx context.Context, req resource.Rea recordSetResp, err := r.client.GetCredentials(ctx, projectId, instanceId, credentialsId).Execute() if err != nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading credentials", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading credentials", fmt.Sprintf("Calling API: %v", err)) return } - // Map response body to schema and populate Computed attribute values + // Map response body to schema err = mapFields(recordSetResp, &model) if err != nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error mapping fields", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading credentials", fmt.Sprintf("Processing API payload: %v", err)) return } // Set refreshed state diags = resp.State.Set(ctx, model) resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } tflog.Info(ctx, "Redis credentials read") } // Update updates the resource and sets the updated Terraform state on success. -func (r *postgresCredentialsResource) Update(_ context.Context, _ resource.UpdateRequest, resp *resource.UpdateResponse) { // nolint:gocritic // function signature required by Terraform +func (r *redisCredentialsResource) Update(ctx context.Context, _ resource.UpdateRequest, resp *resource.UpdateResponse) { // nolint:gocritic // function signature required by Terraform // Update shouldn't be called - resp.Diagnostics.AddError("Error updating credentials", "credentials can't be updated") + core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating credentials", "Credentials can't be updated") } // Delete deletes the resource and removes the Terraform state on success. -func (r *postgresCredentialsResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { // nolint:gocritic // function signature required by Terraform +func (r *redisCredentialsResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { // nolint:gocritic // function signature required by Terraform var model Model diags := req.State.Get(ctx, &model) resp.Diagnostics.Append(diags...) @@ -288,7 +294,7 @@ func (r *postgresCredentialsResource) Delete(ctx context.Context, req resource.D // Delete existing record set err := r.client.DeleteCredentials(ctx, projectId, instanceId, credentialsId).Execute() if err != nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error deleting credentials", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error deleting credentials", fmt.Sprintf("Calling API: %v", err)) } _, err = redis.DeleteCredentialsWaitHandler(ctx, r.client, projectId, instanceId, credentialsId).SetTimeout(1 * time.Minute).WaitWithContext(ctx) if err != nil { @@ -300,11 +306,11 @@ func (r *postgresCredentialsResource) Delete(ctx context.Context, req resource.D // ImportState imports a resource into the Terraform state on success. // The expected format of the resource import identifier is: project_id,instance_id,credentials_id -func (r *postgresCredentialsResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { +func (r *redisCredentialsResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { idParts := strings.Split(req.ID, core.Separator) if len(idParts) != 3 || idParts[0] == "" || idParts[1] == "" || idParts[2] == "" { core.LogAndAddError(ctx, &resp.Diagnostics, - "Unexpected Import Identifier", + "Unexpected import identifier", fmt.Sprintf("Expected import identifier with format [project_id],[instance_id],[credentials_id], got %q", req.ID), ) return diff --git a/stackit/services/redis/instance/datasource.go b/stackit/services/redis/instance/datasource.go index 662c5f002..7c2da1f48 100644 --- a/stackit/services/redis/instance/datasource.go +++ b/stackit/services/redis/instance/datasource.go @@ -44,7 +44,7 @@ func (r *instanceDataSource) Configure(ctx context.Context, req datasource.Confi providerData, ok := req.ProviderData.(core.ProviderData) if !ok { - resp.Diagnostics.AddError("Unexpected Data Source Configure Type", fmt.Sprintf("Expected stackit.ProviderData, got %T. Please report this issue to the provider developers.", req.ProviderData)) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error configuring API client", fmt.Sprintf("Expected configure type stackit.ProviderData, got %T", req.ProviderData)) return } @@ -63,19 +63,19 @@ func (r *instanceDataSource) Configure(ctx context.Context, req datasource.Confi } if err != nil { - resp.Diagnostics.AddError("Could not Configure API Client", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error configuring API client", fmt.Sprintf("Configuring client: %v", err)) return } - tflog.Info(ctx, "Redis zone client configured") r.client = apiClient + tflog.Info(ctx, "Redis zone client configured") } // Schema defines the schema for the resource. func (r *instanceDataSource) Schema(_ context.Context, _ datasource.SchemaRequest, resp *datasource.SchemaResponse) { descriptions := map[string]string{ "main": "Redis instance data source schema.", - "id": "Terraform's internal resource identifier. It is structured as \"`project_id`,`instance_id`\".", + "id": "Terraform's internal resource identifier. It is structured as \"`project_id`,`zone_id`\".", "instance_id": "ID of the Redis instance.", "project_id": "STACKIT Project ID to which the instance is associated.", "name": "Instance name.", @@ -152,37 +152,41 @@ func (r *instanceDataSource) Schema(_ context.Context, _ datasource.SchemaReques // 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 - var state Model - diags := req.Config.Get(ctx, &state) + var model Model + diags := req.Config.Get(ctx, &model) resp.Diagnostics.Append(diags...) if resp.Diagnostics.HasError() { return } - - projectId := state.ProjectId.ValueString() - instanceId := state.InstanceId.ValueString() + projectId := model.ProjectId.ValueString() + instanceId := model.InstanceId.ValueString() ctx = tflog.SetField(ctx, "project_id", projectId) ctx = tflog.SetField(ctx, "instance_id", instanceId) + instanceResp, err := r.client.GetInstance(ctx, projectId, instanceId).Execute() if err != nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Unable to read instance", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading instance", fmt.Sprintf("Calling API: %v", err)) return } - err = mapFields(instanceResp, &state) + err = mapFields(instanceResp, &model) if err != nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Mapping fields", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading instance", fmt.Sprintf("Processing API payload: %v", err)) return } // Compute and store values not present in the API response - loadPlanNameAndVersion(ctx, r.client, &resp.Diagnostics, &state) - if resp.Diagnostics.HasError() { + err = loadPlanNameAndVersion(ctx, r.client, &model) + if err != nil { + core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading instance", fmt.Sprintf("Loading service plan details: %v", err)) return } // Set refreshed state - diags = resp.State.Set(ctx, state) + diags = resp.State.Set(ctx, &model) resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } tflog.Info(ctx, "Redis instance read") } diff --git a/stackit/services/redis/instance/resource.go b/stackit/services/redis/instance/resource.go index 774966501..e15e7690d 100644 --- a/stackit/services/redis/instance/resource.go +++ b/stackit/services/redis/instance/resource.go @@ -8,8 +8,6 @@ import ( "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator" "github.com/hashicorp/terraform-plugin-framework/attr" - "github.com/hashicorp/terraform-plugin-framework/diag" - "github.com/hashicorp/terraform-plugin-framework/resource/schema/objectplanmodifier" "github.com/hashicorp/terraform-plugin-framework/schema/validator" "github.com/hashicorp/terraform-plugin-framework/types/basetypes" "github.com/hashicorp/terraform-plugin-log/tflog" @@ -83,7 +81,7 @@ func (r *instanceResource) Configure(ctx context.Context, req resource.Configure providerData, ok := req.ProviderData.(core.ProviderData) if !ok { - resp.Diagnostics.AddError("Unexpected Resource Configure Type", fmt.Sprintf("Expected stackit.ProviderData, got %T. Please report this issue to the provider developers.", req.ProviderData)) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error configuring API client", fmt.Sprintf("Expected configure type stackit.ProviderData, got %T", req.ProviderData)) return } @@ -102,12 +100,12 @@ func (r *instanceResource) Configure(ctx context.Context, req resource.Configure } if err != nil { - resp.Diagnostics.AddError("Could not Configure API Client", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error configuring API client", fmt.Sprintf("Configuring client: %v", err)) return } - tflog.Info(ctx, "redis client configured") r.client = apiClient + tflog.Info(ctx, "Redis instance client configured") } // Schema defines the schema for the resource. @@ -129,6 +127,9 @@ func (r *instanceResource) Schema(_ context.Context, _ resource.SchemaRequest, r "id": schema.StringAttribute{ Description: descriptions["id"], Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, }, "instance_id": schema.StringAttribute{ Description: descriptions["instance_id"], @@ -181,34 +182,40 @@ func (r *instanceResource) Schema(_ context.Context, _ resource.SchemaRequest, r "sgw_acl": schema.StringAttribute{ Optional: true, Computed: true, - Validators: []validator.String{ - stringvalidator.LengthAtLeast(1), - }, - PlanModifiers: []planmodifier.String{ - stringplanmodifier.UseStateForUnknown(), - }, }, }, Optional: true, Computed: true, - PlanModifiers: []planmodifier.Object{ - objectplanmodifier.UseStateForUnknown(), - }, }, "cf_guid": schema.StringAttribute{ Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, }, "cf_space_guid": schema.StringAttribute{ Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, }, "dashboard_url": schema.StringAttribute{ Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, }, "image_url": schema.StringAttribute{ Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, }, "cf_organization_guid": schema.StringAttribute{ Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, }, }, } @@ -225,11 +232,6 @@ func (r *instanceResource) Create(ctx context.Context, req resource.CreateReques projectId := model.ProjectId.ValueString() ctx = tflog.SetField(ctx, "project_id", projectId) - r.loadPlanId(ctx, &resp.Diagnostics, &model) - if resp.Diagnostics.HasError() { - return - } - var parameters = ¶metersModel{} if !(model.Parameters.IsNull() || model.Parameters.IsUnknown()) { diags = model.Parameters.As(ctx, parameters, basetypes.ObjectAsOptions{}) @@ -239,6 +241,12 @@ func (r *instanceResource) Create(ctx context.Context, req resource.CreateReques } } + err := r.loadPlanId(ctx, &model) + if err != nil { + core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating instance", fmt.Sprintf("Loading service plan: %v", err)) + return + } + // Generate API request body from model payload, err := toCreatePayload(&model, parameters) if err != nil { @@ -264,75 +272,69 @@ func (r *instanceResource) Create(ctx context.Context, req resource.CreateReques return } - // Map response body to schema and populate Computed attribute values + // Map response body to schema err = mapFields(got, &model) if err != nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error mapping fields", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating instance", fmt.Sprintf("Processing API payload: %v", err)) return } + + // Compute and store values not present in the API response + err = loadPlanNameAndVersion(ctx, r.client, &model) + if err != nil { + core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading instance", fmt.Sprintf("Loading service plan details: %v", err)) + return + } + // Set state to fully populated data diags = resp.State.Set(ctx, model) resp.Diagnostics.Append(diags...) - tflog.Info(ctx, "redis instance created") -} - -func toCreatePayload(model *Model, parameters *parametersModel) (*redis.CreateInstancePayload, error) { - if model == nil { - return nil, fmt.Errorf("nil model") - } - if parameters == nil { - return &redis.CreateInstancePayload{ - InstanceName: model.Name.ValueStringPointer(), - PlanId: model.PlanId.ValueStringPointer(), - }, nil - } - payloadParams := &redis.InstanceParameters{} - if parameters.SgwAcl.ValueString() != "" { - payloadParams.SgwAcl = parameters.SgwAcl.ValueStringPointer() + if resp.Diagnostics.HasError() { + return } - return &redis.CreateInstancePayload{ - InstanceName: model.Name.ValueStringPointer(), - Parameters: payloadParams, - PlanId: model.PlanId.ValueStringPointer(), - }, nil + tflog.Info(ctx, "Redis instance created") } // 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 - var state Model - diags := req.State.Get(ctx, &state) + var model Model + diags := req.State.Get(ctx, &model) resp.Diagnostics.Append(diags...) if resp.Diagnostics.HasError() { return } - projectId := state.ProjectId.ValueString() - instanceId := state.InstanceId.ValueString() + projectId := model.ProjectId.ValueString() + instanceId := model.InstanceId.ValueString() ctx = tflog.SetField(ctx, "project_id", projectId) ctx = tflog.SetField(ctx, "instance_id", instanceId) instanceResp, err := r.client.GetInstance(ctx, projectId, instanceId).Execute() if err != nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading instances", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading instance", fmt.Sprintf("Calling API: %v", err)) return } - // Map response body to schema and populate Computed attribute values - err = mapFields(instanceResp, &state) + // Map response body to schema + err = mapFields(instanceResp, &model) if err != nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error mapping fields", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading instance", fmt.Sprintf("Processing API payload: %v", err)) return } // Compute and store values not present in the API response - loadPlanNameAndVersion(ctx, r.client, &resp.Diagnostics, &state) - if resp.Diagnostics.HasError() { + err = loadPlanNameAndVersion(ctx, r.client, &model) + if err != nil { + core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading instance", fmt.Sprintf("Loading service plan details: %v", err)) return } // Set refreshed state - diags = resp.State.Set(ctx, state) + diags = resp.State.Set(ctx, model) resp.Diagnostics.Append(diags...) - tflog.Info(ctx, "redis instance read") + if resp.Diagnostics.HasError() { + return + } + tflog.Info(ctx, "Redis instance read") } // Update updates the resource and sets the updated Terraform state on success. @@ -348,11 +350,6 @@ func (r *instanceResource) Update(ctx context.Context, req resource.UpdateReques ctx = tflog.SetField(ctx, "project_id", projectId) ctx = tflog.SetField(ctx, "instance_id", instanceId) - r.loadPlanId(ctx, &resp.Diagnostics, &model) - if resp.Diagnostics.HasError() { - return - } - var parameters = ¶metersModel{} if !(model.Parameters.IsNull() || model.Parameters.IsUnknown()) { diags = model.Parameters.As(ctx, parameters, basetypes.ObjectAsOptions{}) @@ -362,16 +359,22 @@ func (r *instanceResource) Update(ctx context.Context, req resource.UpdateReques } } + err := r.loadPlanId(ctx, &model) + if err != nil { + core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating instance", fmt.Sprintf("Loading service plan: %v", err)) + return + } + // Generate API request body from model payload, err := toUpdatePayload(&model, parameters) if err != nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating instance", fmt.Sprintf("Could not create API payload: %v", err)) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating instance", fmt.Sprintf("Creating API payload: %v", err)) return } // Update existing instance err = r.client.UpdateInstance(ctx, projectId, instanceId).UpdateInstancePayload(*payload).Execute() if err != nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating instance", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating instance", fmt.Sprintf("Calling API: %v", err)) return } wr, err := redis.UpdateInstanceWaitHandler(ctx, r.client, projectId, instanceId).SetTimeout(15 * time.Minute).WaitWithContext(ctx) @@ -385,37 +388,31 @@ func (r *instanceResource) Update(ctx context.Context, req resource.UpdateReques return } - // Map response body to schema and populate Computed attribute values + // Map response body to schema err = mapFields(got, &model) if err != nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error mapping fields in update", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating instance", fmt.Sprintf("Processing API payload: %v", err)) return } - diags = resp.State.Set(ctx, model) - resp.Diagnostics.Append(diags...) - tflog.Info(ctx, "redis instance updated") -} -func toUpdatePayload(model *Model, parameters *parametersModel) (*redis.UpdateInstancePayload, error) { - if model == nil { - return nil, fmt.Errorf("nil model") + // Compute and store values not present in the API response + err = loadPlanNameAndVersion(ctx, r.client, &model) + if err != nil { + core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading instance", fmt.Sprintf("Loading service plan details: %v", err)) + return } - if parameters == nil { - return &redis.UpdateInstancePayload{ - PlanId: model.PlanId.ValueStringPointer(), - }, nil + diags = resp.State.Set(ctx, model) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return } - return &redis.UpdateInstancePayload{ - Parameters: &redis.InstanceParameters{ - SgwAcl: parameters.SgwAcl.ValueStringPointer(), - }, - PlanId: model.PlanId.ValueStringPointer(), - }, nil + tflog.Info(ctx, "Redis instance updated") } // 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 + // Retrieve values from state var model Model diags := req.State.Get(ctx, &model) resp.Diagnostics.Append(diags...) @@ -430,7 +427,7 @@ func (r *instanceResource) Delete(ctx context.Context, req resource.DeleteReques // Delete existing instance err := r.client.DeleteInstance(ctx, projectId, instanceId).Execute() if err != nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error deleting instance", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error deleting instance", fmt.Sprintf("Calling API: %v", err)) return } _, err = redis.DeleteInstanceWaitHandler(ctx, r.client, projectId, instanceId).SetTimeout(15 * time.Minute).WaitWithContext(ctx) @@ -438,7 +435,7 @@ func (r *instanceResource) Delete(ctx context.Context, req resource.DeleteReques core.LogAndAddError(ctx, &resp.Diagnostics, "Error deleting instance", fmt.Sprintf("Instance deletion waiting: %v", err)) return } - tflog.Info(ctx, "redis instance deleted") + tflog.Info(ctx, "Redis instance deleted") } // ImportState imports a resource into the Terraform state on success. @@ -447,8 +444,8 @@ func (r *instanceResource) ImportState(ctx context.Context, req resource.ImportS idParts := strings.Split(req.ID, core.Separator) if len(idParts) != 2 || idParts[0] == "" || idParts[1] == "" { - resp.Diagnostics.AddError( - "Unexpected Import Identifier", + core.LogAndAddError(ctx, &resp.Diagnostics, + "Unexpected import identifier", fmt.Sprintf("Expected import identifier with format: [project_id],[instance_id] Got: %q", req.ID), ) return @@ -599,12 +596,50 @@ func mapParameters(params map[string]interface{}) (types.Object, error) { return output, nil } -func (r *instanceResource) loadPlanId(ctx context.Context, diags *diag.Diagnostics, model *Model) { +func toCreatePayload(model *Model, parameters *parametersModel) (*redis.CreateInstancePayload, error) { + if model == nil { + return nil, fmt.Errorf("nil model") + } + if parameters == nil { + return &redis.CreateInstancePayload{ + InstanceName: model.Name.ValueStringPointer(), + PlanId: model.PlanId.ValueStringPointer(), + }, nil + } + payloadParams := &redis.InstanceParameters{} + if parameters.SgwAcl.ValueString() != "" { + payloadParams.SgwAcl = parameters.SgwAcl.ValueStringPointer() + } + return &redis.CreateInstancePayload{ + InstanceName: model.Name.ValueStringPointer(), + Parameters: payloadParams, + PlanId: model.PlanId.ValueStringPointer(), + }, nil +} + +func toUpdatePayload(model *Model, parameters *parametersModel) (*redis.UpdateInstancePayload, error) { + if model == nil { + return nil, fmt.Errorf("nil model") + } + + if parameters == nil { + return &redis.UpdateInstancePayload{ + PlanId: model.PlanId.ValueStringPointer(), + }, nil + } + return &redis.UpdateInstancePayload{ + Parameters: &redis.InstanceParameters{ + SgwAcl: parameters.SgwAcl.ValueStringPointer(), + }, + PlanId: model.PlanId.ValueStringPointer(), + }, nil +} + +func (r *instanceResource) loadPlanId(ctx context.Context, model *Model) error { projectId := model.ProjectId.ValueString() res, err := r.client.GetOfferings(ctx, projectId).Execute() if err != nil { - diags.AddError("Failed to list Redis offerings", err.Error()) - return + return fmt.Errorf("getting Redis offerings: %v", err) } version := model.Version.ValueString() @@ -625,26 +660,24 @@ func (r *instanceResource) loadPlanId(ctx context.Context, diags *diag.Diagnosti } if strings.EqualFold(*plan.Name, planName) && plan.Id != nil { model.PlanId = types.StringPointerValue(plan.Id) - return + return nil } availablePlanNames = fmt.Sprintf("%s\n- %s", availablePlanNames, *plan.Name) } } if !isValidVersion { - diags.AddError("Invalid version", fmt.Sprintf("Couldn't find version '%s', available versions are:%s", version, availableVersions)) - return + return fmt.Errorf("couldn't find version '%s', available versions are: %s", version, availableVersions) } - diags.AddError("Invalid plan_name", fmt.Sprintf("Couldn't find plan_name '%s' for version %s, available names are:%s", planName, version, availablePlanNames)) + return fmt.Errorf("couldn't find plan_name '%s' for version %s, available names are: %s", planName, version, availablePlanNames) } -func loadPlanNameAndVersion(ctx context.Context, client *redis.APIClient, diags *diag.Diagnostics, model *Model) { +func loadPlanNameAndVersion(ctx context.Context, client *redis.APIClient, model *Model) error { projectId := model.ProjectId.ValueString() planId := model.PlanId.ValueString() res, err := client.GetOfferings(ctx, projectId).Execute() if err != nil { - diags.AddError("Failed to list Redis offerings", err.Error()) - return + return fmt.Errorf("getting Redis offerings: %v", err) } for _, offer := range *res.Offerings { @@ -652,10 +685,10 @@ func loadPlanNameAndVersion(ctx context.Context, client *redis.APIClient, diags if strings.EqualFold(*plan.Id, planId) && plan.Id != nil { model.PlanName = types.StringPointerValue(plan.Name) model.Version = types.StringPointerValue(offer.Version) - return + return nil } } } - diags.AddWarning("Failed to get plan_name and version", fmt.Sprintf("Couldn't find plan_name and version for plan_id = %s", planId)) + return fmt.Errorf("couldn't find plan_name and version for plan_id '%s'", planId) } diff --git a/stackit/services/resourcemanager/project/datasource.go b/stackit/services/resourcemanager/project/datasource.go index a04518018..e05dac196 100644 --- a/stackit/services/resourcemanager/project/datasource.go +++ b/stackit/services/resourcemanager/project/datasource.go @@ -26,7 +26,7 @@ var ( _ datasource.DataSource = &projectDataSource{} ) -type ProjectData struct { +type ModelData struct { Id types.String `tfsdk:"id"` // needed by TF ContainerId types.String `tfsdk:"container_id"` ContainerParentId types.String `tfsdk:"parent_container_id"` @@ -60,7 +60,7 @@ func (d *projectDataSource) Configure(ctx context.Context, req datasource.Config providerData, ok := req.ProviderData.(core.ProviderData) if !ok { - resp.Diagnostics.AddError("Unexpected Data Source Configure Type", fmt.Sprintf("Expected stackit.ProviderData, got %T. Please report this issue to the provider developers.", req.ProviderData)) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error configuring API client", fmt.Sprintf("Expected configure type stackit.ProviderData, got %T", req.ProviderData)) return } @@ -78,15 +78,12 @@ func (d *projectDataSource) Configure(ctx context.Context, req datasource.Config ) } if err != nil { - resp.Diagnostics.AddError( - "Could not Configure API Client", - err.Error(), - ) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error configuring API client", fmt.Sprintf("Configuring client: %v", err)) return } - tflog.Info(ctx, "Resource Manager project client configured") d.client = apiClient + tflog.Info(ctx, "Resource Manager project client configured") } // Schema defines the schema for the data source. @@ -152,7 +149,7 @@ func (d *projectDataSource) Schema(_ context.Context, _ datasource.SchemaRequest // Read refreshes the Terraform state with the latest data. func (d *projectDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { // nolint:gocritic // function signature required by Terraform - var state ProjectData + var state ModelData diags := req.Config.Get(ctx, &state) resp.Diagnostics.Append(diags...) if resp.Diagnostics.HasError() { @@ -163,13 +160,13 @@ func (d *projectDataSource) Read(ctx context.Context, req datasource.ReadRequest projectResp, err := d.client.GetProject(ctx, containerId).Execute() if err != nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Unable to Read Project", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading project", fmt.Sprintf("Calling API: %v", err)) return } err = mapDataFields(ctx, projectResp, &state) if err != nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Mapping fields", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading project", fmt.Sprintf("Processing API payload: %v", err)) return } diags = resp.State.Set(ctx, &state) @@ -180,7 +177,7 @@ func (d *projectDataSource) Read(ctx context.Context, req datasource.ReadRequest tflog.Info(ctx, "Resource Manager project read") } -func mapDataFields(ctx context.Context, projectResp *resourcemanager.ProjectResponseWithParents, model *ProjectData) (err error) { +func mapDataFields(ctx context.Context, projectResp *resourcemanager.ProjectResponseWithParents, model *ModelData) (err error) { if projectResp == nil { return fmt.Errorf("response input is nil") } diff --git a/stackit/services/resourcemanager/project/resource.go b/stackit/services/resourcemanager/project/resource.go index f06b8b428..45d2106c9 100644 --- a/stackit/services/resourcemanager/project/resource.go +++ b/stackit/services/resourcemanager/project/resource.go @@ -70,7 +70,7 @@ func (r *projectResource) Configure(ctx context.Context, req resource.ConfigureR providerData, ok := req.ProviderData.(core.ProviderData) if !ok { - resp.Diagnostics.AddError("Unexpected Resource Configure Type", fmt.Sprintf("Expected stackit.ProviderData, got %T. Please report this issue to the provider developers.", req.ProviderData)) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error configuring API client", fmt.Sprintf("Expected configure type stackit.ProviderData, got %T", req.ProviderData)) return } @@ -92,12 +92,12 @@ func (r *projectResource) Configure(ctx context.Context, req resource.ConfigureR } if err != nil { - resp.Diagnostics.AddError("Could not Configure API Client", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error configuring API client", fmt.Sprintf("Configuring client: %v", err)) return } - tflog.Info(ctx, "Resource Manager project client configured") r.client = apiClient + tflog.Info(ctx, "Resource Manager project client configured") } // Schema defines the schema for the resource. @@ -186,7 +186,7 @@ func (r *projectResource) Create(ctx context.Context, req resource.CreateRequest serviceAccountEmail := r.client.GetConfig().ServiceAccountEmail if serviceAccountEmail == "" { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating project", "The service account e-mail cannot be empty: set it in the provider configuration or through the STACKIT_SERVICE_ACCOUNT_EMAIL or in your credentials file (default filepath is ~/stackit/.credentials.json)") + core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating project", "The service account e-mail cannot be empty: set it in the provider configuration or through the STACKIT_SERVICE_ACCOUNT_EMAIL or in your credentials file (default filepath is ~/.stackit/credentials.json)") return } @@ -203,10 +203,6 @@ func (r *projectResource) Create(ctx context.Context, req resource.CreateRequest return } respContainerId := *createResp.ContainerId - if respContainerId == "" { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating project", "API didn't return project id") - return - } // If the request has not been processed yet and the containerId doesnt exist, // the waiter will fail with authentication error, so wait some time before checking the creation @@ -221,44 +217,50 @@ func (r *projectResource) Create(ctx context.Context, req resource.CreateRequest return } - // Map response body to schema and populate Computed attribute values + // Map response body to schema err = mapFields(ctx, got, &model) if err != nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error mapping fields", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating project", fmt.Sprintf("Processing API payload: %v", err)) return } // Set state to fully populated data diags = resp.State.Set(ctx, model) resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } tflog.Info(ctx, "Resource Manager project created") } // Read refreshes the Terraform state with the latest data. func (r *projectResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { // nolint:gocritic // function signature required by Terraform - var state = &Model{} - diags := req.State.Get(ctx, state) + var model Model + diags := req.State.Get(ctx, model) resp.Diagnostics.Append(diags...) if resp.Diagnostics.HasError() { return } - containerId := state.ContainerId.ValueString() + containerId := model.ContainerId.ValueString() ctx = tflog.SetField(ctx, "container_id", containerId) projectResp, err := r.client.GetProject(ctx, containerId).Execute() if err != nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading project", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading project", fmt.Sprintf("Calling API: %v", err)) return } - // Map response body to schema and populate Computed attribute values - err = mapFields(ctx, projectResp, state) + // Map response body to schema + err = mapFields(ctx, projectResp, &model) if err != nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error mapping fields", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading project", fmt.Sprintf("Processing API payload: %v", err)) return } - // Set refreshed state - diags = resp.State.Set(ctx, *state) + // Set refreshed model + diags = resp.State.Set(ctx, model) resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } tflog.Info(ctx, "Resource Manager project read") } @@ -277,18 +279,32 @@ func (r *projectResource) Update(ctx context.Context, req resource.UpdateRequest // Generate API request body from model payload, err := toUpdatePayload(&model) if err != nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating project", fmt.Sprintf("Could not create API payload: %v", err)) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating project", fmt.Sprintf("Creating API payload: %v", err)) return } // Update existing project _, err = r.client.UpdateProject(ctx, containerId).UpdateProjectPayload(*payload).Execute() if err != nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating project", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating project", fmt.Sprintf("Calling API: %v", err)) return } - diags = resp.State.Set(ctx, &model) + // Fetch updated zone + projectResp, err := r.client.GetProject(ctx, containerId).Execute() + if err != nil { + core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating zone", fmt.Sprintf("Calling API for updated data: %v", err)) + return + } + err = mapFields(ctx, projectResp, &model) + if err != nil { + core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating zone", fmt.Sprintf("Processing API payload: %v", err)) + return + } + diags = resp.State.Set(ctx, model) resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } tflog.Info(ctx, "Resource Manager project updated") } @@ -308,7 +324,7 @@ func (r *projectResource) Delete(ctx context.Context, req resource.DeleteRequest // Delete existing project err := r.client.DeleteProject(ctx, containerId).Execute() if err != nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error deleting project", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error deleting project", fmt.Sprintf("Calling API: %v", err)) return } @@ -326,8 +342,8 @@ func (r *projectResource) Delete(ctx context.Context, req resource.DeleteRequest func (r *projectResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { idParts := strings.Split(req.ID, core.Separator) if len(idParts) != 1 || idParts[0] == "" { - resp.Diagnostics.AddError( - "Unexpected Import Identifier", + core.LogAndAddError(ctx, &resp.Diagnostics, + "Unexpected import identifier", fmt.Sprintf("Expected import identifier with format: [container_id] Got: %q", req.ID), ) return diff --git a/stackit/services/ske/cluster/datasource.go b/stackit/services/ske/cluster/datasource.go index 1430c9987..83ef3f0ac 100644 --- a/stackit/services/ske/cluster/datasource.go +++ b/stackit/services/ske/cluster/datasource.go @@ -45,7 +45,7 @@ func (r *clusterDataSource) Configure(ctx context.Context, req datasource.Config providerData, ok := req.ProviderData.(core.ProviderData) if !ok { - resp.Diagnostics.AddError("Unexpected Data Source Configure Type", fmt.Sprintf("Expected stackit.ProviderData, got %T. Please report this issue to the provider developers.", req.ProviderData)) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error configuring API client", fmt.Sprintf("Expected configure type stackit.ProviderData, got %T", req.ProviderData)) return } @@ -64,12 +64,12 @@ func (r *clusterDataSource) Configure(ctx context.Context, req datasource.Config } if err != nil { - resp.Diagnostics.AddError("Could not Configure API Client", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error configuring API client", fmt.Sprintf("Configuring client: %v", err)) return } - tflog.Info(ctx, "SKE client configured") r.client = apiClient + tflog.Info(ctx, "SKE client configured") } func (r *clusterDataSource) Schema(_ context.Context, _ datasource.SchemaRequest, resp *datasource.SchemaResponse) { resp.Schema = schema.Schema{ @@ -292,19 +292,22 @@ func (r *clusterDataSource) Read(ctx context.Context, req datasource.ReadRequest ctx = tflog.SetField(ctx, "name", name) clusterResp, err := r.client.GetCluster(ctx, projectId, name).Execute() if err != nil { - core.LogAndAddError(ctx, &resp.Diagnostics, fmt.Sprintf("Unable to read cluster, project_id = %s, name = %s", projectId, name), err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading cluster", fmt.Sprintf("Calling API: %v", err)) return } err = mapFields(ctx, clusterResp, &state) if err != nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Mapping fields", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading cluster", fmt.Sprintf("Processing API payload: %v", err)) return } r.getCredential(ctx, &diags, &state) // Set refreshed state diags = resp.State.Set(ctx, state) resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } tflog.Info(ctx, "SKE cluster read") } diff --git a/stackit/services/ske/cluster/resource.go b/stackit/services/ske/cluster/resource.go index 772932c7f..7abd25987 100644 --- a/stackit/services/ske/cluster/resource.go +++ b/stackit/services/ske/cluster/resource.go @@ -148,7 +148,7 @@ func (r *clusterResource) Configure(ctx context.Context, req resource.ConfigureR providerData, ok := req.ProviderData.(core.ProviderData) if !ok { - resp.Diagnostics.AddError("Unexpected Resource Configure Type", fmt.Sprintf("Expected stackit.ProviderData, got %T. Please report this issue to the provider developers.", req.ProviderData)) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error configuring API client", fmt.Sprintf("Expected configure type stackit.ProviderData, got %T", req.ProviderData)) return } @@ -167,12 +167,12 @@ func (r *clusterResource) Configure(ctx context.Context, req resource.ConfigureR } if err != nil { - resp.Diagnostics.AddError("Could not Configure API Client", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error configuring API client", fmt.Sprintf("Configuring client: %v", err)) return } - tflog.Info(ctx, "SKE cluster client configured") r.client = apiClient + tflog.Info(ctx, "SKE cluster client configured") } // Schema defines the schema for the resource. @@ -502,8 +502,9 @@ func (r *clusterResource) Create(ctx context.Context, req resource.CreateRequest ctx = tflog.SetField(ctx, "project_id", projectId) ctx = tflog.SetField(ctx, "name", clusterName) - availableVersions := r.loadAvaiableVersions(ctx, &resp.Diagnostics) - if resp.Diagnostics.HasError() { + availableVersions, err := r.loadAvaiableVersions(ctx) + if err != nil { + core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating cluster", fmt.Sprintf("Loading available Kubernetes versions: %v", err)) return } @@ -512,34 +513,27 @@ func (r *clusterResource) Create(ctx context.Context, req resource.CreateRequest return } - // handle credential - r.getCredential(ctx, &resp.Diagnostics, &model) - if resp.Diagnostics.HasError() { - return - } - diags = resp.State.Set(ctx, model) resp.Diagnostics.Append(diags...) if resp.Diagnostics.HasError() { return } + tflog.Info(ctx, "SKE cluster created") } -func (r *clusterResource) loadAvaiableVersions(ctx context.Context, diags *diag.Diagnostics) []ske.KubernetesVersion { +func (r *clusterResource) loadAvaiableVersions(ctx context.Context) ([]ske.KubernetesVersion, error) { c := r.client res, err := c.GetOptions(ctx).Execute() if err != nil { - diags.AddError("Failed loading cluster available versions: getting cluster options", err.Error()) - return nil + return nil, fmt.Errorf("calling API: %v", err) } if res.KubernetesVersions == nil { - diags.AddError("Failed loading cluster available versions: nil kubernetesVersions", err.Error()) - return nil + return nil, fmt.Errorf("API response has nil kubernetesVersions") } - return *res.KubernetesVersions + return *res.KubernetesVersions, nil } func (r *clusterResource) createOrUpdateCluster(ctx context.Context, diags *diag.Diagnostics, model *Cluster, availableVersions []ske.KubernetesVersion) { @@ -548,23 +542,22 @@ func (r *clusterResource) createOrUpdateCluster(ctx context.Context, diags *diag name := model.Name.ValueString() kubernetes, hasDeprecatedVersion, err := toKubernetesPayload(model, availableVersions) if err != nil { - diags.AddError("Failed to create cluster config payload", err.Error()) + core.LogAndAddError(ctx, diags, "Error creating/updating cluster", fmt.Sprintf("Creating cluster config API payload: %v", err)) return } if hasDeprecatedVersion { - warningMessage := fmt.Sprintf("Using deprecated kubernetes version %s", *kubernetes.Version) - diags.AddWarning(warningMessage, "") + diags.AddWarning("Deprecated Kubernetes version", fmt.Sprintf("Version %s of Kubernetes is deprecated, please update it", *kubernetes.Version)) } nodePools := toNodepoolsPayload(ctx, model) maintenance, err := toMaintenancePayload(ctx, model) if err != nil { - diags.AddError("Failed to create maintenance payload", err.Error()) + core.LogAndAddError(ctx, diags, "Error creating/updating cluster", fmt.Sprintf("Creating maintenance API payload: %v", err)) return } hibernations := toHibernationsPayload(model) extensions, err := toExtensionsPayload(ctx, model) if err != nil { - diags.AddError("Failed to create extension payload", err.Error()) + core.LogAndAddError(ctx, diags, "Error creating/updating cluster", fmt.Sprintf("Creating extension API payload: %v", err)) return } @@ -577,35 +570,42 @@ func (r *clusterResource) createOrUpdateCluster(ctx context.Context, diags *diag } _, err = r.client.CreateOrUpdateCluster(ctx, projectId, name).CreateOrUpdateClusterPayload(payload).Execute() if err != nil { - diags.AddError("failed during SKE create/update", err.Error()) + core.LogAndAddError(ctx, diags, "Error creating/updating cluster", fmt.Sprintf("Calling API: %v", err)) return } wr, err := ske.CreateOrUpdateClusterWaitHandler(ctx, r.client, projectId, name).SetTimeout(30 * time.Minute).WaitWithContext(ctx) if err != nil { - diags.AddError("Error creating cluster", fmt.Sprintf("Cluster creation waiting: %v", err)) + core.LogAndAddError(ctx, diags, "Error creating/updating cluster", fmt.Sprintf("Cluster creation waiting: %v", err)) return } got, ok := wr.(*ske.ClusterResponse) if !ok { - diags.AddError("Error creating cluster", fmt.Sprintf("Wait result conversion, got %+v", got)) + core.LogAndAddError(ctx, diags, "Error creating/updating cluster", fmt.Sprintf("Wait result conversion, got %+v", got)) return } err = mapFields(ctx, got, model) if err != nil { - diags.AddError("Mapping cluster fields", err.Error()) + core.LogAndAddError(ctx, diags, "Error creating/updating cluster", fmt.Sprintf("Processing API payload: %v", err)) + return + } + + // Handle credential + err = r.getCredential(ctx, model) + if err != nil { + core.LogAndAddError(ctx, diags, "Error creating/updating cluster", fmt.Sprintf("Getting credential: %v", err)) return } } -func (r *clusterResource) getCredential(ctx context.Context, diags *diag.Diagnostics, model *Cluster) { +func (r *clusterResource) getCredential(ctx context.Context, model *Cluster) error { c := r.client res, err := c.GetCredentials(ctx, model.ProjectId.ValueString(), model.Name.ValueString()).Execute() if err != nil { - diags.AddError("failed fetching cluster credentials", err.Error()) - return + return fmt.Errorf("fetching cluster credentials: %v", err) } model.KubeConfig = types.StringPointerValue(res.Kubeconfig) + return nil } func toNodepoolsPayload(ctx context.Context, m *Cluster) []ske.Nodepool { @@ -1079,17 +1079,20 @@ func (r *clusterResource) Read(ctx context.Context, req resource.ReadRequest, re clResp, err := r.client.GetCluster(ctx, projectId, name).Execute() if err != nil { - core.LogAndAddError(ctx, &resp.Diagnostics, fmt.Sprintf("Unable to read cluster, project_id = %s, name = %s", projectId, name), err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading cluster", fmt.Sprintf("Calling API: %v", err)) return } err = mapFields(ctx, clResp, &state) if err != nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error mapping fields", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading cluster", fmt.Sprintf("Processing API payload: %v", err)) return } diags = resp.State.Set(ctx, state) resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } tflog.Info(ctx, "SKE cluster read") } @@ -1105,8 +1108,9 @@ func (r *clusterResource) Update(ctx context.Context, req resource.UpdateRequest ctx = tflog.SetField(ctx, "project_id", projectId) ctx = tflog.SetField(ctx, "name", clName) - availableVersions := r.loadAvaiableVersions(ctx, &resp.Diagnostics) - if resp.Diagnostics.HasError() { + availableVersions, err := r.loadAvaiableVersions(ctx) + if err != nil { + core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating cluster", fmt.Sprintf("Loading available Kubernetes versions: %v", err)) return } @@ -1115,14 +1119,11 @@ func (r *clusterResource) Update(ctx context.Context, req resource.UpdateRequest return } - // handle credential - r.getCredential(ctx, &resp.Diagnostics, &model) + diags = resp.State.Set(ctx, model) + resp.Diagnostics.Append(diags...) if resp.Diagnostics.HasError() { return } - - diags = resp.State.Set(ctx, model) - resp.Diagnostics.Append(diags...) tflog.Info(ctx, "SKE cluster updated") } @@ -1140,7 +1141,7 @@ func (r *clusterResource) Delete(ctx context.Context, req resource.DeleteRequest c := r.client _, err := c.DeleteCluster(ctx, projectId, name).Execute() if err != nil { - resp.Diagnostics.AddError("failed deleting cluster", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error deleting cluster", fmt.Sprintf("Calling API: %v", err)) return } _, err = ske.DeleteClusterWaitHandler(ctx, r.client, projectId, name).SetTimeout(15 * time.Minute).WaitWithContext(ctx) @@ -1157,8 +1158,8 @@ func (r *clusterResource) ImportState(ctx context.Context, req resource.ImportSt idParts := strings.Split(req.ID, core.Separator) if len(idParts) != 2 || idParts[0] == "" || idParts[1] == "" { - resp.Diagnostics.AddError( - "Unexpected Import Identifier", + core.LogAndAddError(ctx, &resp.Diagnostics, + "Unexpected import identifier", fmt.Sprintf("Expected import identifier with format: [project_id],[name] Got: %q", req.ID), ) return diff --git a/stackit/services/ske/project/datasource.go b/stackit/services/ske/project/datasource.go index c3b2a46f4..5e47db80f 100644 --- a/stackit/services/ske/project/datasource.go +++ b/stackit/services/ske/project/datasource.go @@ -44,7 +44,7 @@ func (r *projectDataSource) Configure(ctx context.Context, req datasource.Config providerData, ok := req.ProviderData.(core.ProviderData) if !ok { - resp.Diagnostics.AddError("Unexpected Data Source Configure Type", fmt.Sprintf("Expected stackit.ProviderData, got %T. Please report this issue to the provider developers.", req.ProviderData)) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error configuring API client", fmt.Sprintf("Expected configure type stackit.ProviderData, got %T", req.ProviderData)) return } @@ -63,12 +63,12 @@ func (r *projectDataSource) Configure(ctx context.Context, req datasource.Config } if err != nil { - resp.Diagnostics.AddError("Could not Configure API Client", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error configuring API client", fmt.Sprintf("Configuring client: %v", err)) return } - tflog.Info(ctx, "SKE client configured") r.client = apiClient + tflog.Info(ctx, "SKE client configured") } // Schema defines the schema for the resource. @@ -93,23 +93,26 @@ func (r *projectDataSource) Schema(_ context.Context, _ datasource.SchemaRequest // Read refreshes the Terraform state with the latest data. func (r *projectDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { // nolint:gocritic // function signature required by Terraform - var state Model - diags := req.Config.Get(ctx, &state) + var model Model + diags := req.Config.Get(ctx, &model) resp.Diagnostics.Append(diags...) if resp.Diagnostics.HasError() { return } - projectId := state.ProjectId.ValueString() + projectId := model.ProjectId.ValueString() ctx = tflog.SetField(ctx, "project_id", projectId) _, err := r.client.GetProject(ctx, projectId).Execute() if err != nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Unable to read project", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading project", fmt.Sprintf("Calling API: %v", err)) return } - state.Id = types.StringValue(projectId) - state.ProjectId = types.StringValue(projectId) - diags = resp.State.Set(ctx, state) + model.Id = types.StringValue(projectId) + model.ProjectId = types.StringValue(projectId) + diags = resp.State.Set(ctx, model) resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } tflog.Info(ctx, "SKE project read") } diff --git a/stackit/services/ske/project/resource.go b/stackit/services/ske/project/resource.go index 2c46a270d..541e0cfe4 100644 --- a/stackit/services/ske/project/resource.go +++ b/stackit/services/ske/project/resource.go @@ -56,7 +56,7 @@ func (r *projectResource) Configure(ctx context.Context, req resource.ConfigureR providerData, ok := req.ProviderData.(core.ProviderData) if !ok { - resp.Diagnostics.AddError("Unexpected Resource Configure Type", fmt.Sprintf("Expected stackit.ProviderData, got %T. Please report this issue to the provider developers.", req.ProviderData)) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error configuring API client", fmt.Sprintf("Expected configure type stackit.ProviderData, got %T", req.ProviderData)) return } @@ -75,12 +75,12 @@ func (r *projectResource) Configure(ctx context.Context, req resource.ConfigureR } if err != nil { - resp.Diagnostics.AddError("Could not Configure API Client", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error configuring API client", fmt.Sprintf("Configuring client: %v", err)) return } - tflog.Info(ctx, "SKE project client configured") r.client = apiClient + tflog.Info(ctx, "SKE project client configured") } // Schema returns the Terraform schema structure @@ -119,19 +119,19 @@ func (r *projectResource) Create(ctx context.Context, req resource.CreateRequest projectId := model.ProjectId.ValueString() _, err := r.client.CreateProject(ctx, projectId).Execute() if err != nil { - resp.Diagnostics.AddError("failed during SKE project creation", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating project", fmt.Sprintf("Calling API: %v", err)) return } model.Id = types.StringValue(projectId) wr, err := ske.CreateProjectWaitHandler(ctx, r.client, projectId).SetTimeout(5 * time.Minute).WaitWithContext(ctx) if err != nil { - resp.Diagnostics.AddError("Error creating cluster", fmt.Sprintf("Project creation waiting: %v", err)) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating cluster", fmt.Sprintf("Project creation waiting: %v", err)) return } got, ok := wr.(*ske.ProjectResponse) if !ok { - resp.Diagnostics.AddError("Error creating cluster", fmt.Sprintf("Wait result conversion, got %+v", got)) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating cluster", fmt.Sprintf("Wait result conversion, got %+v", got)) return } diags := resp.State.Set(ctx, model) @@ -139,7 +139,7 @@ func (r *projectResource) Create(ctx context.Context, req resource.CreateRequest if resp.Diagnostics.HasError() { return } - tflog.Info(ctx, "SKE project created or updated") + tflog.Info(ctx, "SKE project created") } // Read refreshes the Terraform state with the latest data. @@ -151,23 +151,25 @@ func (r *projectResource) Read(ctx context.Context, req resource.ReadRequest, re return } projectId := model.ProjectId.ValueString() - // read _, err := r.client.GetProject(ctx, projectId).Execute() if err != nil { - resp.Diagnostics.AddError("failed during SKE project read", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading project", fmt.Sprintf("Calling API: %v", err)) return } model.Id = types.StringValue(projectId) model.ProjectId = types.StringValue(projectId) diags = resp.State.Set(ctx, model) resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } tflog.Info(ctx, "SKE project read") } // Update updates the resource and sets the updated Terraform state on success. -func (r *projectResource) Update(_ context.Context, _ resource.UpdateRequest, resp *resource.UpdateResponse) { // nolint:gocritic // function signature required by Terraform +func (r *projectResource) Update(ctx context.Context, _ resource.UpdateRequest, resp *resource.UpdateResponse) { // nolint:gocritic // function signature required by Terraform // Update shouldn't be called - resp.Diagnostics.AddError("Error updating ", "project can't be updated") + core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating project", "Project can't be updated") } // Delete deletes the resource and removes the Terraform state on success. @@ -183,12 +185,12 @@ func (r *projectResource) Delete(ctx context.Context, req resource.DeleteRequest c := r.client _, err := c.DeleteProject(ctx, projectId).Execute() if err != nil { - resp.Diagnostics.AddError("failed deleting project", err.Error()) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error deleting credential", fmt.Sprintf("Calling API: %v", err)) return } _, err = ske.DeleteProjectWaitHandler(ctx, r.client, projectId).SetTimeout(10 * time.Minute).WaitWithContext(ctx) if err != nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error deleting project", fmt.Sprintf("Project deletion waiting: %v", err)) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error deleting credential", fmt.Sprintf("Project deletion waiting: %v", err)) return } tflog.Info(ctx, "SKE project deleted") @@ -199,8 +201,8 @@ func (r *projectResource) Delete(ctx context.Context, req resource.DeleteRequest func (r *projectResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { // nolint:gocritic // function signature required by Terraform idParts := strings.Split(req.ID, core.Separator) if len(idParts) != 1 || idParts[0] == "" { - resp.Diagnostics.AddError( - "Unexpected Import Identifier", + core.LogAndAddError(ctx, &resp.Diagnostics, + "Unexpected import identifier", fmt.Sprintf("Expected import identifier with format: [project_id] Got: %q", req.ID), ) return From e13b86b58e64f57943ec836ae0e3266041fa8f48 Mon Sep 17 00:00:00 2001 From: Henrique Santos Date: Wed, 20 Sep 2023 14:24:51 +0100 Subject: [PATCH 04/17] Standardize validators --- stackit/validate/validate.go | 41 +++++++++++++++++++++++++++++------- 1 file changed, 33 insertions(+), 8 deletions(-) diff --git a/stackit/validate/validate.go b/stackit/validate/validate.go index 7aab712ad..4c9bc1cfa 100644 --- a/stackit/validate/validate.go +++ b/stackit/validate/validate.go @@ -8,6 +8,7 @@ import ( "strings" "github.com/google/uuid" + "github.com/hashicorp/terraform-plugin-framework-validators/helpers/validatordiag" "github.com/hashicorp/terraform-plugin-framework/schema/validator" "github.com/stackitcloud/terraform-provider-stackit/stackit/core" ) @@ -38,47 +39,71 @@ func (v *Validator) ValidateString(ctx context.Context, req validator.StringRequ } func UUID() *Validator { + description := "value must be an UUID" + return &Validator{ - description: "validate string is UUID", + description: description, validate: func(ctx context.Context, req validator.StringRequest, resp *validator.StringResponse) { if _, err := uuid.Parse(req.ConfigValue.ValueString()); err != nil { - resp.Diagnostics.AddError("not a valid UUID", err.Error()) + resp.Diagnostics.Append(validatordiag.InvalidAttributeValueDiagnostic( + req.Path, + description, + req.ConfigValue.ValueString(), + )) } }, } } func IP() *Validator { + description := "value must be an IP address" + return &Validator{ - description: "validate string is IP address", + description: description, validate: func(ctx context.Context, req validator.StringRequest, resp *validator.StringResponse) { if net.ParseIP(req.ConfigValue.ValueString()) == nil { - resp.Diagnostics.AddError("not a valid IP address", "") + resp.Diagnostics.Append(validatordiag.InvalidAttributeValueDiagnostic( + req.Path, + description, + req.ConfigValue.ValueString(), + )) } }, } } func NoSeparator() *Validator { + description := fmt.Sprintf("value must not contain identifier separator '%s'", core.Separator) + return &Validator{ - description: "validate string does not contain internal separator", + description: description, validate: func(ctx context.Context, req validator.StringRequest, resp *validator.StringResponse) { if strings.Contains(req.ConfigValue.ValueString(), core.Separator) { - resp.Diagnostics.AddError("Invalid character found.", fmt.Sprintf("The string should not contain a '%s'", core.Separator)) + resp.Diagnostics.Append(validatordiag.InvalidAttributeValueDiagnostic( + req.Path, + description, + req.ConfigValue.ValueString(), + )) } }, } } func SemanticMinorVersion() *Validator { + description := "value must be a major + minor version number, without a leading 'v': '[MAJOR].[MINOR]'" + return &Validator{ - description: "validate string does not contain internal separator", + description: description, validate: func(ctx context.Context, req validator.StringRequest, resp *validator.StringResponse) { exp := `^\d+\.\d+?$` r := regexp.MustCompile(exp) version := req.ConfigValue.ValueString() if !r.MatchString(version) { - resp.Diagnostics.AddError("Invalid version.", "The version should be a valid semantic version only containing major and minor version. The version should not contain a leading `v`. Got "+version) + resp.Diagnostics.Append(validatordiag.InvalidAttributeValueDiagnostic( + req.Path, + description, + req.ConfigValue.ValueString(), + )) } }, } From 7d67b6cc9594128420da9356541098fefa91d3d4 Mon Sep 17 00:00:00 2001 From: Henrique Santos Date: Wed, 20 Sep 2023 14:25:41 +0100 Subject: [PATCH 05/17] Rename version validator --- stackit/services/ske/cluster/resource.go | 2 +- stackit/validate/validate.go | 4 ++-- stackit/validate/validate_test.go | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/stackit/services/ske/cluster/resource.go b/stackit/services/ske/cluster/resource.go index 7abd25987..eb562bf07 100644 --- a/stackit/services/ske/cluster/resource.go +++ b/stackit/services/ske/cluster/resource.go @@ -213,7 +213,7 @@ func (r *clusterResource) Schema(_ context.Context, _ resource.SchemaRequest, re Description: "Kubernetes version. Must only contain major and minor version (e.g. 1.22)", Required: true, Validators: []validator.String{ - validate.SemanticMinorVersion(), + validate.MinorVersionNumber(), }, }, "kubernetes_version_used": schema.StringAttribute{ diff --git a/stackit/validate/validate.go b/stackit/validate/validate.go index 4c9bc1cfa..8beaaea52 100644 --- a/stackit/validate/validate.go +++ b/stackit/validate/validate.go @@ -89,8 +89,8 @@ func NoSeparator() *Validator { } } -func SemanticMinorVersion() *Validator { - description := "value must be a major + minor version number, without a leading 'v': '[MAJOR].[MINOR]'" +func MinorVersionNumber() *Validator { + description := "value must be a minor version number, without a leading 'v': '[MAJOR].[MINOR]'" return &Validator{ description: description, diff --git a/stackit/validate/validate_test.go b/stackit/validate/validate_test.go index 39bdfaf96..9ea438b31 100644 --- a/stackit/validate/validate_test.go +++ b/stackit/validate/validate_test.go @@ -145,7 +145,7 @@ func TestNoSeparator(t *testing.T) { } } -func TestSemanticMinorVersion(t *testing.T) { +func TestMinorVersionNumber(t *testing.T) { tests := []struct { description string input string @@ -195,7 +195,7 @@ func TestSemanticMinorVersion(t *testing.T) { for _, tt := range tests { t.Run(tt.description, func(t *testing.T) { r := validator.StringResponse{} - SemanticMinorVersion().ValidateString(context.Background(), validator.StringRequest{ + MinorVersionNumber().ValidateString(context.Background(), validator.StringRequest{ ConfigValue: types.StringValue(tt.input), }, &r) From 022e97d719c8e29a9d0d9c08167f1349a481eecb Mon Sep 17 00:00:00 2001 From: Henrique Santos Date: Wed, 20 Sep 2023 17:43:49 +0100 Subject: [PATCH 06/17] Fix lint --- stackit/services/logme/instance/resource.go | 4 ++-- stackit/services/mariadb/instance/resource.go | 4 ++-- stackit/services/opensearch/instance/resource.go | 4 ++-- stackit/services/postgresql/instance/resource.go | 4 ++-- stackit/services/rabbitmq/instance/resource.go | 4 ++-- stackit/services/redis/instance/resource.go | 4 ++-- 6 files changed, 12 insertions(+), 12 deletions(-) diff --git a/stackit/services/logme/instance/resource.go b/stackit/services/logme/instance/resource.go index 0bf583b8c..d1169abc1 100644 --- a/stackit/services/logme/instance/resource.go +++ b/stackit/services/logme/instance/resource.go @@ -639,7 +639,7 @@ func (r *instanceResource) loadPlanId(ctx context.Context, model *Model) error { projectId := model.ProjectId.ValueString() res, err := r.client.GetOfferings(ctx, projectId).Execute() if err != nil { - return fmt.Errorf("getting LogMe offerings: %v", err) + return fmt.Errorf("getting LogMe offerings: %w", err) } version := model.Version.ValueString() @@ -677,7 +677,7 @@ func loadPlanNameAndVersion(ctx context.Context, client *logme.APIClient, model planId := model.PlanId.ValueString() res, err := client.GetOfferings(ctx, projectId).Execute() if err != nil { - return fmt.Errorf("getting LogMe offerings: %v", err) + return fmt.Errorf("getting LogMe offerings: %w", err) } for _, offer := range *res.Offerings { diff --git a/stackit/services/mariadb/instance/resource.go b/stackit/services/mariadb/instance/resource.go index cfbf870bf..1bc2cf831 100644 --- a/stackit/services/mariadb/instance/resource.go +++ b/stackit/services/mariadb/instance/resource.go @@ -639,7 +639,7 @@ func (r *instanceResource) loadPlanId(ctx context.Context, model *Model) error { projectId := model.ProjectId.ValueString() res, err := r.client.GetOfferings(ctx, projectId).Execute() if err != nil { - return fmt.Errorf("getting MariaDB offerings: %v", err) + return fmt.Errorf("getting MariaDB offerings: %w", err) } version := model.Version.ValueString() @@ -677,7 +677,7 @@ func loadPlanNameAndVersion(ctx context.Context, client *mariadb.APIClient, mode planId := model.PlanId.ValueString() res, err := client.GetOfferings(ctx, projectId).Execute() if err != nil { - return fmt.Errorf("getting MariaDB offerings: %v", err) + return fmt.Errorf("getting MariaDB offerings: %w", err) } for _, offer := range *res.Offerings { diff --git a/stackit/services/opensearch/instance/resource.go b/stackit/services/opensearch/instance/resource.go index 4df4c5007..dc03615e8 100644 --- a/stackit/services/opensearch/instance/resource.go +++ b/stackit/services/opensearch/instance/resource.go @@ -639,7 +639,7 @@ func (r *instanceResource) loadPlanId(ctx context.Context, model *Model) error { projectId := model.ProjectId.ValueString() res, err := r.client.GetOfferings(ctx, projectId).Execute() if err != nil { - return fmt.Errorf("getting OpenSearch offerings: %v", err) + return fmt.Errorf("getting OpenSearch offerings: %w", err) } version := model.Version.ValueString() @@ -677,7 +677,7 @@ func loadPlanNameAndVersion(ctx context.Context, client *opensearch.APIClient, m planId := model.PlanId.ValueString() res, err := client.GetOfferings(ctx, projectId).Execute() if err != nil { - return fmt.Errorf("getting OpenSearch offerings: %v", err) + return fmt.Errorf("getting OpenSearch offerings: %w", err) } for _, offer := range *res.Offerings { diff --git a/stackit/services/postgresql/instance/resource.go b/stackit/services/postgresql/instance/resource.go index d703e6e09..eb4da69cb 100644 --- a/stackit/services/postgresql/instance/resource.go +++ b/stackit/services/postgresql/instance/resource.go @@ -700,7 +700,7 @@ func (r *instanceResource) loadPlanId(ctx context.Context, model *Model) error { projectId := model.ProjectId.ValueString() res, err := r.client.GetOfferings(ctx, projectId).Execute() if err != nil { - return fmt.Errorf("getting PostgreSQL offerings: %v", err) + return fmt.Errorf("getting PostgreSQL offerings: %w", err) } version := model.Version.ValueString() @@ -738,7 +738,7 @@ func loadPlanNameAndVersion(ctx context.Context, client *postgresql.APIClient, m planId := model.PlanId.ValueString() res, err := client.GetOfferings(ctx, projectId).Execute() if err != nil { - return fmt.Errorf("getting PostgreSQL offerings: %v", err) + return fmt.Errorf("getting PostgreSQL offerings: %w", err) } for _, offer := range *res.Offerings { diff --git a/stackit/services/rabbitmq/instance/resource.go b/stackit/services/rabbitmq/instance/resource.go index acee1d3dd..6e4c0f03f 100644 --- a/stackit/services/rabbitmq/instance/resource.go +++ b/stackit/services/rabbitmq/instance/resource.go @@ -639,7 +639,7 @@ func (r *instanceResource) loadPlanId(ctx context.Context, model *Model) error { projectId := model.ProjectId.ValueString() res, err := r.client.GetOfferings(ctx, projectId).Execute() if err != nil { - return fmt.Errorf("getting RabbitMQ offerings: %v", err) + return fmt.Errorf("getting RabbitMQ offerings: %w", err) } version := model.Version.ValueString() @@ -677,7 +677,7 @@ func loadPlanNameAndVersion(ctx context.Context, client *rabbitmq.APIClient, mod planId := model.PlanId.ValueString() res, err := client.GetOfferings(ctx, projectId).Execute() if err != nil { - return fmt.Errorf("getting RabbitMQ offerings: %v", err) + return fmt.Errorf("getting RabbitMQ offerings: %w", err) } for _, offer := range *res.Offerings { diff --git a/stackit/services/redis/instance/resource.go b/stackit/services/redis/instance/resource.go index e15e7690d..29eaa1ace 100644 --- a/stackit/services/redis/instance/resource.go +++ b/stackit/services/redis/instance/resource.go @@ -639,7 +639,7 @@ func (r *instanceResource) loadPlanId(ctx context.Context, model *Model) error { projectId := model.ProjectId.ValueString() res, err := r.client.GetOfferings(ctx, projectId).Execute() if err != nil { - return fmt.Errorf("getting Redis offerings: %v", err) + return fmt.Errorf("getting Redis offerings: %w", err) } version := model.Version.ValueString() @@ -677,7 +677,7 @@ func loadPlanNameAndVersion(ctx context.Context, client *redis.APIClient, model planId := model.PlanId.ValueString() res, err := client.GetOfferings(ctx, projectId).Execute() if err != nil { - return fmt.Errorf("getting Redis offerings: %v", err) + return fmt.Errorf("getting Redis offerings: %w", err) } for _, offer := range *res.Offerings { From 715280939fe1115051731f948b50e346d76cb767 Mon Sep 17 00:00:00 2001 From: Henrique Santos Date: Wed, 20 Sep 2023 17:44:26 +0100 Subject: [PATCH 07/17] Fix lint --- stackit/services/ske/cluster/resource.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/stackit/services/ske/cluster/resource.go b/stackit/services/ske/cluster/resource.go index eb562bf07..901ba07b7 100644 --- a/stackit/services/ske/cluster/resource.go +++ b/stackit/services/ske/cluster/resource.go @@ -526,7 +526,7 @@ func (r *clusterResource) loadAvaiableVersions(ctx context.Context) ([]ske.Kuber c := r.client res, err := c.GetOptions(ctx).Execute() if err != nil { - return nil, fmt.Errorf("calling API: %v", err) + return nil, fmt.Errorf("calling API: %w", err) } if res.KubernetesVersions == nil { @@ -602,7 +602,7 @@ func (r *clusterResource) getCredential(ctx context.Context, model *Cluster) err c := r.client res, err := c.GetCredentials(ctx, model.ProjectId.ValueString(), model.Name.ValueString()).Execute() if err != nil { - return fmt.Errorf("fetching cluster credentials: %v", err) + return fmt.Errorf("fetching cluster credentials: %w", err) } model.KubeConfig = types.StringPointerValue(res.Kubeconfig) return nil From 2eb48a11e43ff3607b231f1fa43da1ab2e913c43 Mon Sep 17 00:00:00 2001 From: Henrique Santos Date: Wed, 20 Sep 2023 17:51:53 +0100 Subject: [PATCH 08/17] Generate docs --- docs/data-sources/mariadb_credentials.md | 8 ++++---- docs/data-sources/mariadb_instance.md | 2 +- docs/data-sources/opensearch_instance.md | 2 +- docs/data-sources/postgresql_instance.md | 2 +- docs/data-sources/rabbitmq_instance.md | 2 +- docs/data-sources/redis_instance.md | 2 +- docs/resources/mariadb_credentials.md | 2 +- 7 files changed, 10 insertions(+), 10 deletions(-) diff --git a/docs/data-sources/mariadb_credentials.md b/docs/data-sources/mariadb_credentials.md index f948838bb..c8fbe4126 100644 --- a/docs/data-sources/mariadb_credentials.md +++ b/docs/data-sources/mariadb_credentials.md @@ -3,12 +3,12 @@ page_title: "stackit_mariadb_credentials Data Source - stackit" subcategory: "" description: |- - MariaDB credentials data source schema. + mariadb credentials data source schema. --- # stackit_mariadb_credentials (Data Source) -MariaDB credentials data source schema. +mariadb credentials data source schema. ## Example Usage @@ -26,7 +26,7 @@ data "stackit_mariadb_credentials" "example" { ### Required - `credentials_id` (String) The credentials ID. -- `instance_id` (String) ID of the MariaDB instance. +- `instance_id` (String) ID of the mariadb instance. - `project_id` (String) STACKIT project ID to which the instance is associated. ### Read-Only @@ -34,7 +34,7 @@ data "stackit_mariadb_credentials" "example" { - `host` (String) - `hosts` (List of String) - `http_api_uri` (String) -- `id` (String) Terraform's internal resource ID. It is structured as "`project_id`,`instance_id`,`credentials_id`". +- `id` (String) Terraform's internal resource identifier. It is structured as "`project_id`,`instance_id`,`credentials_id`". - `name` (String) - `password` (String, Sensitive) - `port` (Number) diff --git a/docs/data-sources/mariadb_instance.md b/docs/data-sources/mariadb_instance.md index e6150d9dd..c69120caa 100644 --- a/docs/data-sources/mariadb_instance.md +++ b/docs/data-sources/mariadb_instance.md @@ -33,7 +33,7 @@ data "stackit_mariadb_instance" "example" { - `cf_organization_guid` (String) - `cf_space_guid` (String) - `dashboard_url` (String) -- `id` (String) Terraform's internal resource ID. It is structured as "`project_id`,`instance_id`". +- `id` (String) Terraform's internal resource identifier. It is structured as "`project_id`,`zone_id`". - `image_url` (String) - `name` (String) Instance name. - `parameters` (Attributes) (see [below for nested schema](#nestedatt--parameters)) diff --git a/docs/data-sources/opensearch_instance.md b/docs/data-sources/opensearch_instance.md index 329f6b0b4..506b4f052 100644 --- a/docs/data-sources/opensearch_instance.md +++ b/docs/data-sources/opensearch_instance.md @@ -33,7 +33,7 @@ data "stackit_opensearch_instance" "example" { - `cf_organization_guid` (String) - `cf_space_guid` (String) - `dashboard_url` (String) -- `id` (String) Terraform's internal resource identifier. It is structured as "`project_id`,`instance_id`". +- `id` (String) Terraform's internal resource identifier. It is structured as "`project_id`,`zone_id`". - `image_url` (String) - `name` (String) Instance name. - `parameters` (Attributes) (see [below for nested schema](#nestedatt--parameters)) diff --git a/docs/data-sources/postgresql_instance.md b/docs/data-sources/postgresql_instance.md index aa6fa73e1..ad06f6c85 100644 --- a/docs/data-sources/postgresql_instance.md +++ b/docs/data-sources/postgresql_instance.md @@ -33,7 +33,7 @@ data "stackit_postgresql_instance" "example" { - `cf_organization_guid` (String) - `cf_space_guid` (String) - `dashboard_url` (String) -- `id` (String) Terraform's internal resource identifier. It is structured as "`project_id`,`instance_id`". +- `id` (String) Terraform's internal resource identifier. It is structured as "`project_id`,`zone_id`". - `image_url` (String) - `name` (String) Instance name. - `parameters` (Attributes) (see [below for nested schema](#nestedatt--parameters)) diff --git a/docs/data-sources/rabbitmq_instance.md b/docs/data-sources/rabbitmq_instance.md index b5e5e1439..a865df514 100644 --- a/docs/data-sources/rabbitmq_instance.md +++ b/docs/data-sources/rabbitmq_instance.md @@ -33,7 +33,7 @@ data "stackit_rabbitmq_instance" "example" { - `cf_organization_guid` (String) - `cf_space_guid` (String) - `dashboard_url` (String) -- `id` (String) Terraform's internal resource identifier. It is structured as "`project_id`,`instance_id`". +- `id` (String) Terraform's internal resource identifier. It is structured as "`project_id`,`zone_id`". - `image_url` (String) - `name` (String) Instance name. - `parameters` (Attributes) (see [below for nested schema](#nestedatt--parameters)) diff --git a/docs/data-sources/redis_instance.md b/docs/data-sources/redis_instance.md index 2cf6de0b5..ffd2494a7 100644 --- a/docs/data-sources/redis_instance.md +++ b/docs/data-sources/redis_instance.md @@ -33,7 +33,7 @@ data "stackit_redis_instance" "example" { - `cf_organization_guid` (String) - `cf_space_guid` (String) - `dashboard_url` (String) -- `id` (String) Terraform's internal resource identifier. It is structured as "`project_id`,`instance_id`". +- `id` (String) Terraform's internal resource identifier. It is structured as "`project_id`,`zone_id`". - `image_url` (String) - `name` (String) Instance name. - `parameters` (Attributes) (see [below for nested schema](#nestedatt--parameters)) diff --git a/docs/resources/mariadb_credentials.md b/docs/resources/mariadb_credentials.md index 6eb348018..22c495d11 100644 --- a/docs/resources/mariadb_credentials.md +++ b/docs/resources/mariadb_credentials.md @@ -33,7 +33,7 @@ resource "stackit_mariadb_credentials" "example" { - `host` (String) - `hosts` (List of String) - `http_api_uri` (String) -- `id` (String) Terraform's internal resource ID. It is structured as "`project_id`,`instance_id`,`credentials_id`". +- `id` (String) Terraform's internal resource identifier. It is structured as "`project_id`,`instance_id`,`credentials_id`". - `name` (String) - `password` (String, Sensitive) - `port` (Number) From 5c49e054c67f9bdef182e3ce9272b9dc18bdba82 Mon Sep 17 00:00:00 2001 From: Henrique Santos Date: Wed, 20 Sep 2023 18:02:09 +0100 Subject: [PATCH 09/17] Fix wrong id description --- docs/data-sources/mariadb_credentials.md | 4 ++-- docs/data-sources/mariadb_instance.md | 2 +- docs/data-sources/opensearch_instance.md | 2 +- docs/data-sources/postgresql_instance.md | 2 +- docs/data-sources/rabbitmq_instance.md | 2 +- docs/data-sources/redis_instance.md | 2 +- stackit/services/mariadb/credentials/datasource.go | 2 +- stackit/services/mariadb/instance/datasource.go | 2 +- stackit/services/opensearch/instance/datasource.go | 2 +- stackit/services/postgresql/instance/datasource.go | 2 +- stackit/services/rabbitmq/instance/datasource.go | 2 +- stackit/services/redis/instance/datasource.go | 2 +- 12 files changed, 13 insertions(+), 13 deletions(-) diff --git a/docs/data-sources/mariadb_credentials.md b/docs/data-sources/mariadb_credentials.md index c8fbe4126..81e30d79c 100644 --- a/docs/data-sources/mariadb_credentials.md +++ b/docs/data-sources/mariadb_credentials.md @@ -3,12 +3,12 @@ page_title: "stackit_mariadb_credentials Data Source - stackit" subcategory: "" description: |- - mariadb credentials data source schema. + MariaDB credentials data source schema. --- # stackit_mariadb_credentials (Data Source) -mariadb credentials data source schema. +MariaDB credentials data source schema. ## Example Usage diff --git a/docs/data-sources/mariadb_instance.md b/docs/data-sources/mariadb_instance.md index c69120caa..e3af58c2c 100644 --- a/docs/data-sources/mariadb_instance.md +++ b/docs/data-sources/mariadb_instance.md @@ -33,7 +33,7 @@ data "stackit_mariadb_instance" "example" { - `cf_organization_guid` (String) - `cf_space_guid` (String) - `dashboard_url` (String) -- `id` (String) Terraform's internal resource identifier. It is structured as "`project_id`,`zone_id`". +- `id` (String) Terraform's internal resource identifier. It is structured as "`project_id`,`instance_id`". - `image_url` (String) - `name` (String) Instance name. - `parameters` (Attributes) (see [below for nested schema](#nestedatt--parameters)) diff --git a/docs/data-sources/opensearch_instance.md b/docs/data-sources/opensearch_instance.md index 506b4f052..329f6b0b4 100644 --- a/docs/data-sources/opensearch_instance.md +++ b/docs/data-sources/opensearch_instance.md @@ -33,7 +33,7 @@ data "stackit_opensearch_instance" "example" { - `cf_organization_guid` (String) - `cf_space_guid` (String) - `dashboard_url` (String) -- `id` (String) Terraform's internal resource identifier. It is structured as "`project_id`,`zone_id`". +- `id` (String) Terraform's internal resource identifier. It is structured as "`project_id`,`instance_id`". - `image_url` (String) - `name` (String) Instance name. - `parameters` (Attributes) (see [below for nested schema](#nestedatt--parameters)) diff --git a/docs/data-sources/postgresql_instance.md b/docs/data-sources/postgresql_instance.md index ad06f6c85..aa6fa73e1 100644 --- a/docs/data-sources/postgresql_instance.md +++ b/docs/data-sources/postgresql_instance.md @@ -33,7 +33,7 @@ data "stackit_postgresql_instance" "example" { - `cf_organization_guid` (String) - `cf_space_guid` (String) - `dashboard_url` (String) -- `id` (String) Terraform's internal resource identifier. It is structured as "`project_id`,`zone_id`". +- `id` (String) Terraform's internal resource identifier. It is structured as "`project_id`,`instance_id`". - `image_url` (String) - `name` (String) Instance name. - `parameters` (Attributes) (see [below for nested schema](#nestedatt--parameters)) diff --git a/docs/data-sources/rabbitmq_instance.md b/docs/data-sources/rabbitmq_instance.md index a865df514..b5e5e1439 100644 --- a/docs/data-sources/rabbitmq_instance.md +++ b/docs/data-sources/rabbitmq_instance.md @@ -33,7 +33,7 @@ data "stackit_rabbitmq_instance" "example" { - `cf_organization_guid` (String) - `cf_space_guid` (String) - `dashboard_url` (String) -- `id` (String) Terraform's internal resource identifier. It is structured as "`project_id`,`zone_id`". +- `id` (String) Terraform's internal resource identifier. It is structured as "`project_id`,`instance_id`". - `image_url` (String) - `name` (String) Instance name. - `parameters` (Attributes) (see [below for nested schema](#nestedatt--parameters)) diff --git a/docs/data-sources/redis_instance.md b/docs/data-sources/redis_instance.md index ffd2494a7..2cf6de0b5 100644 --- a/docs/data-sources/redis_instance.md +++ b/docs/data-sources/redis_instance.md @@ -33,7 +33,7 @@ data "stackit_redis_instance" "example" { - `cf_organization_guid` (String) - `cf_space_guid` (String) - `dashboard_url` (String) -- `id` (String) Terraform's internal resource identifier. It is structured as "`project_id`,`zone_id`". +- `id` (String) Terraform's internal resource identifier. It is structured as "`project_id`,`instance_id`". - `image_url` (String) - `name` (String) Instance name. - `parameters` (Attributes) (see [below for nested schema](#nestedatt--parameters)) diff --git a/stackit/services/mariadb/credentials/datasource.go b/stackit/services/mariadb/credentials/datasource.go index f8014670e..9df78ce93 100644 --- a/stackit/services/mariadb/credentials/datasource.go +++ b/stackit/services/mariadb/credentials/datasource.go @@ -75,7 +75,7 @@ func (r *credentialsDataSource) Configure(ctx context.Context, req datasource.Co // Schema defines the schema for the resource. func (r *credentialsDataSource) Schema(_ context.Context, _ datasource.SchemaRequest, resp *datasource.SchemaResponse) { descriptions := map[string]string{ - "main": "mariadb credentials data source schema.", + "main": "MariaDB credentials data source schema.", "id": "Terraform's internal resource identifier. It is structured as \"`project_id`,`instance_id`,`credentials_id`\".", "credentials_id": "The credentials ID.", "instance_id": "ID of the mariadb instance.", diff --git a/stackit/services/mariadb/instance/datasource.go b/stackit/services/mariadb/instance/datasource.go index b8d77867b..63233d0cc 100644 --- a/stackit/services/mariadb/instance/datasource.go +++ b/stackit/services/mariadb/instance/datasource.go @@ -75,7 +75,7 @@ func (r *instanceDataSource) Configure(ctx context.Context, req datasource.Confi func (r *instanceDataSource) Schema(_ context.Context, _ datasource.SchemaRequest, resp *datasource.SchemaResponse) { descriptions := map[string]string{ "main": "MariaDB instance data source schema.", - "id": "Terraform's internal resource identifier. It is structured as \"`project_id`,`zone_id`\".", + "id": "Terraform's internal resource identifier. It is structured as \"`project_id`,`instance_id`\".", "instance_id": "ID of the MariaDB instance.", "project_id": "STACKIT Project ID to which the instance is associated.", "name": "Instance name.", diff --git a/stackit/services/opensearch/instance/datasource.go b/stackit/services/opensearch/instance/datasource.go index 7427e8c27..885ce4397 100644 --- a/stackit/services/opensearch/instance/datasource.go +++ b/stackit/services/opensearch/instance/datasource.go @@ -75,7 +75,7 @@ func (r *instanceDataSource) Configure(ctx context.Context, req datasource.Confi func (r *instanceDataSource) Schema(_ context.Context, _ datasource.SchemaRequest, resp *datasource.SchemaResponse) { descriptions := map[string]string{ "main": "OpenSearch instance data source schema.", - "id": "Terraform's internal resource identifier. It is structured as \"`project_id`,`zone_id`\".", + "id": "Terraform's internal resource identifier. It is structured as \"`project_id`,`instance_id`\".", "instance_id": "ID of the OpenSearch instance.", "project_id": "STACKIT Project ID to which the instance is associated.", "name": "Instance name.", diff --git a/stackit/services/postgresql/instance/datasource.go b/stackit/services/postgresql/instance/datasource.go index 82fac9698..f9afabc0a 100644 --- a/stackit/services/postgresql/instance/datasource.go +++ b/stackit/services/postgresql/instance/datasource.go @@ -76,7 +76,7 @@ func (r *instanceDataSource) Configure(ctx context.Context, req datasource.Confi func (r *instanceDataSource) Schema(_ context.Context, _ datasource.SchemaRequest, resp *datasource.SchemaResponse) { descriptions := map[string]string{ "main": "PostgreSQL instance data source schema.", - "id": "Terraform's internal resource identifier. It is structured as \"`project_id`,`zone_id`\".", + "id": "Terraform's internal resource identifier. It is structured as \"`project_id`,`instance_id`\".", "instance_id": "ID of the PostgreSQL instance.", "project_id": "STACKIT Project ID to which the instance is associated.", "name": "Instance name.", diff --git a/stackit/services/rabbitmq/instance/datasource.go b/stackit/services/rabbitmq/instance/datasource.go index 87631477a..fc7dbc9ca 100644 --- a/stackit/services/rabbitmq/instance/datasource.go +++ b/stackit/services/rabbitmq/instance/datasource.go @@ -75,7 +75,7 @@ func (r *instanceDataSource) Configure(ctx context.Context, req datasource.Confi func (r *instanceDataSource) Schema(_ context.Context, _ datasource.SchemaRequest, resp *datasource.SchemaResponse) { descriptions := map[string]string{ "main": "RabbitMQ instance data source schema.", - "id": "Terraform's internal resource identifier. It is structured as \"`project_id`,`zone_id`\".", + "id": "Terraform's internal resource identifier. It is structured as \"`project_id`,`instance_id`\".", "instance_id": "ID of the RabbitMQ instance.", "project_id": "STACKIT Project ID to which the instance is associated.", "name": "Instance name.", diff --git a/stackit/services/redis/instance/datasource.go b/stackit/services/redis/instance/datasource.go index 7c2da1f48..e97cd252b 100644 --- a/stackit/services/redis/instance/datasource.go +++ b/stackit/services/redis/instance/datasource.go @@ -75,7 +75,7 @@ func (r *instanceDataSource) Configure(ctx context.Context, req datasource.Confi func (r *instanceDataSource) Schema(_ context.Context, _ datasource.SchemaRequest, resp *datasource.SchemaResponse) { descriptions := map[string]string{ "main": "Redis instance data source schema.", - "id": "Terraform's internal resource identifier. It is structured as \"`project_id`,`zone_id`\".", + "id": "Terraform's internal resource identifier. It is structured as \"`project_id`,`instance_id`\".", "instance_id": "ID of the Redis instance.", "project_id": "STACKIT Project ID to which the instance is associated.", "name": "Instance name.", From 2fddabf8a01d9a7c3e9c490181efc4e8076e45f3 Mon Sep 17 00:00:00 2001 From: Henrique Santos Date: Wed, 20 Sep 2023 18:03:55 +0100 Subject: [PATCH 10/17] Undo name renaming --- .../services/mariadb/credentials/resource.go | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/stackit/services/mariadb/credentials/resource.go b/stackit/services/mariadb/credentials/resource.go index 745abd375..0b599185e 100644 --- a/stackit/services/mariadb/credentials/resource.go +++ b/stackit/services/mariadb/credentials/resource.go @@ -25,9 +25,9 @@ import ( // Ensure the implementation satisfies the expected interfaces. var ( - _ resource.Resource = &mariadbCredentialsResource{} - _ resource.ResourceWithConfigure = &mariadbCredentialsResource{} - _ resource.ResourceWithImportState = &mariadbCredentialsResource{} + _ resource.Resource = &mariaDBCredentialsResource{} + _ resource.ResourceWithConfigure = &mariaDBCredentialsResource{} + _ resource.ResourceWithImportState = &mariaDBCredentialsResource{} ) type Model struct { @@ -47,21 +47,21 @@ type Model struct { // NewCredentialsResource is a helper function to simplify the provider implementation. func NewCredentialsResource() resource.Resource { - return &mariadbCredentialsResource{} + return &mariaDBCredentialsResource{} } // credentialsResource is the resource implementation. -type mariadbCredentialsResource struct { +type mariaDBCredentialsResource struct { client *mariadb.APIClient } // Metadata returns the resource type name. -func (r *mariadbCredentialsResource) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { +func (r *mariaDBCredentialsResource) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { resp.TypeName = req.ProviderTypeName + "_mariadb_credentials" } // Configure adds the provider configured client to the resource. -func (r *mariadbCredentialsResource) Configure(ctx context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { +func (r *mariaDBCredentialsResource) Configure(ctx context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { // Prevent panic if the provider has not been configured. if req.ProviderData == nil { return @@ -97,7 +97,7 @@ func (r *mariadbCredentialsResource) Configure(ctx context.Context, req resource } // Schema defines the schema for the resource. -func (r *mariadbCredentialsResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) { +func (r *mariaDBCredentialsResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) { descriptions := map[string]string{ "main": "MariaDB credentials resource schema.", "id": "Terraform's internal resource identifier. It is structured as \"`project_id`,`instance_id`,`credentials_id`\".", @@ -182,7 +182,7 @@ func (r *mariadbCredentialsResource) Schema(_ context.Context, _ resource.Schema } // Create creates the resource and sets the initial Terraform state. -func (r *mariadbCredentialsResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { // nolint:gocritic // function signature required by Terraform +func (r *mariaDBCredentialsResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { // nolint:gocritic // function signature required by Terraform var model Model diags := req.Plan.Get(ctx, &model) resp.Diagnostics.Append(diags...) @@ -233,7 +233,7 @@ func (r *mariadbCredentialsResource) Create(ctx context.Context, req resource.Cr } // Read refreshes the Terraform state with the latest data. -func (r *mariadbCredentialsResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { // nolint:gocritic // function signature required by Terraform +func (r *mariaDBCredentialsResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { // nolint:gocritic // function signature required by Terraform var model Model diags := req.State.Get(ctx, &model) resp.Diagnostics.Append(diags...) @@ -270,13 +270,13 @@ func (r *mariadbCredentialsResource) Read(ctx context.Context, req resource.Read } // Update updates the resource and sets the updated Terraform state on success. -func (r *mariadbCredentialsResource) Update(ctx context.Context, _ resource.UpdateRequest, resp *resource.UpdateResponse) { // nolint:gocritic // function signature required by Terraform +func (r *mariaDBCredentialsResource) Update(ctx context.Context, _ resource.UpdateRequest, resp *resource.UpdateResponse) { // nolint:gocritic // function signature required by Terraform // Update shouldn't be called core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating credentials", "Credentials can't be updated") } // Delete deletes the resource and removes the Terraform state on success. -func (r *mariadbCredentialsResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { // nolint:gocritic // function signature required by Terraform +func (r *mariaDBCredentialsResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { // nolint:gocritic // function signature required by Terraform var model Model diags := req.State.Get(ctx, &model) resp.Diagnostics.Append(diags...) @@ -306,7 +306,7 @@ func (r *mariadbCredentialsResource) Delete(ctx context.Context, req resource.De // ImportState imports a resource into the Terraform state on success. // The expected format of the resource import identifier is: project_id,instance_id,credentials_id -func (r *mariadbCredentialsResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { +func (r *mariaDBCredentialsResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { idParts := strings.Split(req.ID, core.Separator) if len(idParts) != 3 || idParts[0] == "" || idParts[1] == "" || idParts[2] == "" { core.LogAndAddError(ctx, &resp.Diagnostics, From 083e138b5a9bcef71438d9fb374e3592f24e5432 Mon Sep 17 00:00:00 2001 From: Henrique Santos Date: Wed, 20 Sep 2023 18:04:58 +0100 Subject: [PATCH 11/17] Fix description --- docs/data-sources/mariadb_credentials.md | 2 +- stackit/services/mariadb/credentials/datasource.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/data-sources/mariadb_credentials.md b/docs/data-sources/mariadb_credentials.md index 81e30d79c..dff23677d 100644 --- a/docs/data-sources/mariadb_credentials.md +++ b/docs/data-sources/mariadb_credentials.md @@ -26,7 +26,7 @@ data "stackit_mariadb_credentials" "example" { ### Required - `credentials_id` (String) The credentials ID. -- `instance_id` (String) ID of the mariadb instance. +- `instance_id` (String) ID of the MariaDB instance. - `project_id` (String) STACKIT project ID to which the instance is associated. ### Read-Only diff --git a/stackit/services/mariadb/credentials/datasource.go b/stackit/services/mariadb/credentials/datasource.go index 9df78ce93..a878faabf 100644 --- a/stackit/services/mariadb/credentials/datasource.go +++ b/stackit/services/mariadb/credentials/datasource.go @@ -78,7 +78,7 @@ func (r *credentialsDataSource) Schema(_ context.Context, _ datasource.SchemaReq "main": "MariaDB credentials data source schema.", "id": "Terraform's internal resource identifier. It is structured as \"`project_id`,`instance_id`,`credentials_id`\".", "credentials_id": "The credentials ID.", - "instance_id": "ID of the mariadb instance.", + "instance_id": "ID of the MariaDB instance.", "project_id": "STACKIT project ID to which the instance is associated.", } From 94eb42e6a761968f94985ed3f5944acbbea353ce Mon Sep 17 00:00:00 2001 From: Henrique Santos Date: Thu, 21 Sep 2023 08:42:57 +0100 Subject: [PATCH 12/17] Fix logging wrong output after wait --- stackit/services/argus/instance/resource.go | 4 ++-- stackit/services/dns/recordset/resource.go | 6 +++--- stackit/services/dns/zone/resource.go | 6 +++--- stackit/services/logme/credentials/resource.go | 2 +- stackit/services/logme/instance/resource.go | 4 ++-- stackit/services/mariadb/credentials/resource.go | 2 +- stackit/services/mariadb/instance/resource.go | 4 ++-- stackit/services/opensearch/credentials/resource.go | 2 +- stackit/services/opensearch/instance/resource.go | 4 ++-- stackit/services/postgresflex/instance/resource.go | 4 ++-- stackit/services/postgresql/credentials/resource.go | 2 +- stackit/services/postgresql/instance/resource.go | 4 ++-- stackit/services/rabbitmq/credentials/resource.go | 2 +- stackit/services/rabbitmq/instance/resource.go | 4 ++-- stackit/services/redis/credentials/resource.go | 2 +- stackit/services/redis/instance/resource.go | 4 ++-- stackit/services/ske/cluster/resource.go | 2 +- stackit/services/ske/project/resource.go | 4 ++-- 18 files changed, 31 insertions(+), 31 deletions(-) diff --git a/stackit/services/argus/instance/resource.go b/stackit/services/argus/instance/resource.go index 4a73a01ad..a38c54547 100644 --- a/stackit/services/argus/instance/resource.go +++ b/stackit/services/argus/instance/resource.go @@ -293,7 +293,7 @@ func (r *instanceResource) Create(ctx context.Context, req resource.CreateReques } got, ok := wr.(*argus.InstanceResponse) if !ok { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating instance", fmt.Sprintf("Wait result conversion, got %+v", got)) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating instance", fmt.Sprintf("Wait result conversion, got %+v", wr)) return } @@ -383,7 +383,7 @@ func (r *instanceResource) Update(ctx context.Context, req resource.UpdateReques } got, ok := wr.(*argus.InstanceResponse) if !ok { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating instance", fmt.Sprintf("Wait result conversion, got %+v", got)) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating instance", fmt.Sprintf("Wait result conversion, got %+v", wr)) return } diff --git a/stackit/services/dns/recordset/resource.go b/stackit/services/dns/recordset/resource.go index 7c183a357..6e45277a2 100644 --- a/stackit/services/dns/recordset/resource.go +++ b/stackit/services/dns/recordset/resource.go @@ -243,7 +243,7 @@ func (r *recordSetResource) Create(ctx context.Context, req resource.CreateReque } got, ok := wr.(*dns.RecordSetResponse) if !ok { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating record set", fmt.Sprintf("Wait result conversion, got %+v", got)) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating record set", fmt.Sprintf("Wait result conversion, got %+v", wr)) return } @@ -333,9 +333,9 @@ func (r *recordSetResource) Update(ctx context.Context, req resource.UpdateReque core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating record set", fmt.Sprintf("Instance update waiting: %v", err)) return } - got, ok := wr.(*dns.RecordSetResponse) + _, ok := wr.(*dns.RecordSetResponse) if !ok { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating record set", fmt.Sprintf("Wait result conversion, got %+v", got)) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating record set", fmt.Sprintf("Wait result conversion, got %+v", wr)) return } diff --git a/stackit/services/dns/zone/resource.go b/stackit/services/dns/zone/resource.go index 0150ff371..0458946e6 100644 --- a/stackit/services/dns/zone/resource.go +++ b/stackit/services/dns/zone/resource.go @@ -328,7 +328,7 @@ func (r *zoneResource) Create(ctx context.Context, req resource.CreateRequest, r } got, ok := wr.(*dns.ZoneResponse) if !ok { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating zone", fmt.Sprintf("Wait result conversion, got %+v", got)) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating zone", fmt.Sprintf("Wait result conversion, got %+v", wr)) return } @@ -412,9 +412,9 @@ func (r *zoneResource) Update(ctx context.Context, req resource.UpdateRequest, r core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating zone", fmt.Sprintf("Zone update waiting: %v", err)) return } - got, ok := wr.(*dns.ZoneResponse) + _, ok := wr.(*dns.ZoneResponse) if !ok { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating zone", fmt.Sprintf("Wait result conversion, got %+v", got)) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating zone", fmt.Sprintf("Wait result conversion, got %+v", wr)) return } diff --git a/stackit/services/logme/credentials/resource.go b/stackit/services/logme/credentials/resource.go index 8b33384f4..36b3ff392 100644 --- a/stackit/services/logme/credentials/resource.go +++ b/stackit/services/logme/credentials/resource.go @@ -214,7 +214,7 @@ func (r *logmeCredentialsResource) Create(ctx context.Context, req resource.Crea } got, ok := wr.(*logme.CredentialsResponse) if !ok { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating credentials", fmt.Sprintf("Wait result conversion, got %+v", got)) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating credentials", fmt.Sprintf("Wait result conversion, got %+v", wr)) return } diff --git a/stackit/services/logme/instance/resource.go b/stackit/services/logme/instance/resource.go index d1169abc1..c6dc2a959 100644 --- a/stackit/services/logme/instance/resource.go +++ b/stackit/services/logme/instance/resource.go @@ -268,7 +268,7 @@ func (r *instanceResource) Create(ctx context.Context, req resource.CreateReques } got, ok := wr.(*logme.Instance) if !ok { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating instance", fmt.Sprintf("Wait result conversion, got %+v", got)) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating instance", fmt.Sprintf("Wait result conversion, got %+v", wr)) return } @@ -384,7 +384,7 @@ func (r *instanceResource) Update(ctx context.Context, req resource.UpdateReques } got, ok := wr.(*logme.Instance) if !ok { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating instance", fmt.Sprintf("Wait result conversion, got %+v", got)) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating instance", fmt.Sprintf("Wait result conversion, got %+v", wr)) return } diff --git a/stackit/services/mariadb/credentials/resource.go b/stackit/services/mariadb/credentials/resource.go index 0b599185e..93b0f1132 100644 --- a/stackit/services/mariadb/credentials/resource.go +++ b/stackit/services/mariadb/credentials/resource.go @@ -214,7 +214,7 @@ func (r *mariaDBCredentialsResource) Create(ctx context.Context, req resource.Cr } got, ok := wr.(*mariadb.CredentialsResponse) if !ok { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating credentials", fmt.Sprintf("Wait result conversion, got %+v", got)) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating credentials", fmt.Sprintf("Wait result conversion, got %+v", wr)) return } diff --git a/stackit/services/mariadb/instance/resource.go b/stackit/services/mariadb/instance/resource.go index 1bc2cf831..bfe116cdb 100644 --- a/stackit/services/mariadb/instance/resource.go +++ b/stackit/services/mariadb/instance/resource.go @@ -268,7 +268,7 @@ func (r *instanceResource) Create(ctx context.Context, req resource.CreateReques } got, ok := wr.(*mariadb.Instance) if !ok { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating instance", fmt.Sprintf("Wait result conversion, got %+v", got)) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating instance", fmt.Sprintf("Wait result conversion, got %+v", wr)) return } @@ -384,7 +384,7 @@ func (r *instanceResource) Update(ctx context.Context, req resource.UpdateReques } got, ok := wr.(*mariadb.Instance) if !ok { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating instance", fmt.Sprintf("Wait result conversion, got %+v", got)) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating instance", fmt.Sprintf("Wait result conversion, got %+v", wr)) return } diff --git a/stackit/services/opensearch/credentials/resource.go b/stackit/services/opensearch/credentials/resource.go index 5cdb7b1dd..fd077ed5a 100644 --- a/stackit/services/opensearch/credentials/resource.go +++ b/stackit/services/opensearch/credentials/resource.go @@ -214,7 +214,7 @@ func (r *opensearchCredentialsResource) Create(ctx context.Context, req resource } got, ok := wr.(*opensearch.CredentialsResponse) if !ok { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating credentials", fmt.Sprintf("Wait result conversion, got %+v", got)) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating credentials", fmt.Sprintf("Wait result conversion, got %+v", wr)) return } diff --git a/stackit/services/opensearch/instance/resource.go b/stackit/services/opensearch/instance/resource.go index dc03615e8..188aa1d75 100644 --- a/stackit/services/opensearch/instance/resource.go +++ b/stackit/services/opensearch/instance/resource.go @@ -268,7 +268,7 @@ func (r *instanceResource) Create(ctx context.Context, req resource.CreateReques } got, ok := wr.(*opensearch.Instance) if !ok { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating instance", fmt.Sprintf("Wait result conversion, got %+v", got)) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating instance", fmt.Sprintf("Wait result conversion, got %+v", wr)) return } @@ -384,7 +384,7 @@ func (r *instanceResource) Update(ctx context.Context, req resource.UpdateReques } got, ok := wr.(*opensearch.Instance) if !ok { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating instance", fmt.Sprintf("Wait result conversion, got %+v", got)) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating instance", fmt.Sprintf("Wait result conversion, got %+v", wr)) return } diff --git a/stackit/services/postgresflex/instance/resource.go b/stackit/services/postgresflex/instance/resource.go index 05449ce3c..443f8e7ff 100644 --- a/stackit/services/postgresflex/instance/resource.go +++ b/stackit/services/postgresflex/instance/resource.go @@ -295,7 +295,7 @@ func (r *instanceResource) Create(ctx context.Context, req resource.CreateReques } got, ok := wr.(*postgresflex.InstanceResponse) if !ok { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating instance", fmt.Sprintf("Wait result conversion, got %+v", got)) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating instance", fmt.Sprintf("Wait result conversion, got %+v", wr)) return } @@ -427,7 +427,7 @@ func (r *instanceResource) Update(ctx context.Context, req resource.UpdateReques } got, ok := wr.(*postgresflex.InstanceResponse) if !ok { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating instance", fmt.Sprintf("Wait result conversion, got %+v", got)) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating instance", fmt.Sprintf("Wait result conversion, got %+v", wr)) return } diff --git a/stackit/services/postgresql/credentials/resource.go b/stackit/services/postgresql/credentials/resource.go index 8985654e9..81ab66dac 100644 --- a/stackit/services/postgresql/credentials/resource.go +++ b/stackit/services/postgresql/credentials/resource.go @@ -214,7 +214,7 @@ func (r *postgresqlCredentialsResource) Create(ctx context.Context, req resource } got, ok := wr.(*postgresql.CredentialsResponse) if !ok { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating credentials", fmt.Sprintf("Wait result conversion, got %+v", got)) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating credentials", fmt.Sprintf("Wait result conversion, got %+v", wr)) return } diff --git a/stackit/services/postgresql/instance/resource.go b/stackit/services/postgresql/instance/resource.go index eb4da69cb..3c6ea955a 100644 --- a/stackit/services/postgresql/instance/resource.go +++ b/stackit/services/postgresql/instance/resource.go @@ -309,7 +309,7 @@ func (r *instanceResource) Create(ctx context.Context, req resource.CreateReques } got, ok := wr.(*postgresql.Instance) if !ok { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating instance", fmt.Sprintf("Wait result conversion, got %+v", got)) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating instance", fmt.Sprintf("Wait result conversion, got %+v", wr)) return } @@ -461,7 +461,7 @@ func (r *instanceResource) Update(ctx context.Context, req resource.UpdateReques } got, ok := wr.(*postgresql.Instance) if !ok { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating instance", fmt.Sprintf("Wait result conversion, got %+v", got)) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating instance", fmt.Sprintf("Wait result conversion, got %+v", wr)) return } diff --git a/stackit/services/rabbitmq/credentials/resource.go b/stackit/services/rabbitmq/credentials/resource.go index 5b2ce9b73..07da9ba4a 100644 --- a/stackit/services/rabbitmq/credentials/resource.go +++ b/stackit/services/rabbitmq/credentials/resource.go @@ -214,7 +214,7 @@ func (r *rabbitmqCredentialsResource) Create(ctx context.Context, req resource.C } got, ok := wr.(*rabbitmq.CredentialsResponse) if !ok { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating credentials", fmt.Sprintf("Wait result conversion, got %+v", got)) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating credentials", fmt.Sprintf("Wait result conversion, got %+v", wr)) return } diff --git a/stackit/services/rabbitmq/instance/resource.go b/stackit/services/rabbitmq/instance/resource.go index 6e4c0f03f..579047065 100644 --- a/stackit/services/rabbitmq/instance/resource.go +++ b/stackit/services/rabbitmq/instance/resource.go @@ -268,7 +268,7 @@ func (r *instanceResource) Create(ctx context.Context, req resource.CreateReques } got, ok := wr.(*rabbitmq.Instance) if !ok { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating instance", fmt.Sprintf("Wait result conversion, got %+v", got)) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating instance", fmt.Sprintf("Wait result conversion, got %+v", wr)) return } @@ -384,7 +384,7 @@ func (r *instanceResource) Update(ctx context.Context, req resource.UpdateReques } got, ok := wr.(*rabbitmq.Instance) if !ok { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating instance", fmt.Sprintf("Wait result conversion, got %+v", got)) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating instance", fmt.Sprintf("Wait result conversion, got %+v", wr)) return } diff --git a/stackit/services/redis/credentials/resource.go b/stackit/services/redis/credentials/resource.go index 75a9e150a..cf5cf91f4 100644 --- a/stackit/services/redis/credentials/resource.go +++ b/stackit/services/redis/credentials/resource.go @@ -214,7 +214,7 @@ func (r *redisCredentialsResource) Create(ctx context.Context, req resource.Crea } got, ok := wr.(*redis.CredentialsResponse) if !ok { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating credentials", fmt.Sprintf("Wait result conversion, got %+v", got)) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating credentials", fmt.Sprintf("Wait result conversion, got %+v", wr)) return } diff --git a/stackit/services/redis/instance/resource.go b/stackit/services/redis/instance/resource.go index 29eaa1ace..d7292bac5 100644 --- a/stackit/services/redis/instance/resource.go +++ b/stackit/services/redis/instance/resource.go @@ -268,7 +268,7 @@ func (r *instanceResource) Create(ctx context.Context, req resource.CreateReques } got, ok := wr.(*redis.Instance) if !ok { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating instance", fmt.Sprintf("Wait result conversion, got %+v", got)) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating instance", fmt.Sprintf("Wait result conversion, got %+v", wr)) return } @@ -384,7 +384,7 @@ func (r *instanceResource) Update(ctx context.Context, req resource.UpdateReques } got, ok := wr.(*redis.Instance) if !ok { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating instance", fmt.Sprintf("Wait result conversion, got %+v", got)) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating instance", fmt.Sprintf("Wait result conversion, got %+v", wr)) return } diff --git a/stackit/services/ske/cluster/resource.go b/stackit/services/ske/cluster/resource.go index 901ba07b7..3df3c685c 100644 --- a/stackit/services/ske/cluster/resource.go +++ b/stackit/services/ske/cluster/resource.go @@ -581,7 +581,7 @@ func (r *clusterResource) createOrUpdateCluster(ctx context.Context, diags *diag } got, ok := wr.(*ske.ClusterResponse) if !ok { - core.LogAndAddError(ctx, diags, "Error creating/updating cluster", fmt.Sprintf("Wait result conversion, got %+v", got)) + core.LogAndAddError(ctx, diags, "Error creating/updating cluster", fmt.Sprintf("Wait result conversion, got %+v", wr)) return } err = mapFields(ctx, got, model) diff --git a/stackit/services/ske/project/resource.go b/stackit/services/ske/project/resource.go index 541e0cfe4..f410cb587 100644 --- a/stackit/services/ske/project/resource.go +++ b/stackit/services/ske/project/resource.go @@ -129,9 +129,9 @@ func (r *projectResource) Create(ctx context.Context, req resource.CreateRequest core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating cluster", fmt.Sprintf("Project creation waiting: %v", err)) return } - got, ok := wr.(*ske.ProjectResponse) + _, ok := wr.(*ske.ProjectResponse) if !ok { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating cluster", fmt.Sprintf("Wait result conversion, got %+v", got)) + core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating cluster", fmt.Sprintf("Wait result conversion, got %+v", wr)) return } diags := resp.State.Set(ctx, model) From 8ae740ec3b79abfc769fdf6165b726b53fa113cc Mon Sep 17 00:00:00 2001 From: Henrique Santos Date: Thu, 21 Sep 2023 08:47:50 +0100 Subject: [PATCH 13/17] Rename symbols --- .../services/logme/credentials/resource.go | 26 +++++++++---------- .../opensearch/credentials/resource.go | 26 +++++++++---------- .../postgresql/credentials/resource.go | 26 +++++++++---------- .../services/rabbitmq/credentials/resource.go | 26 +++++++++---------- 4 files changed, 52 insertions(+), 52 deletions(-) diff --git a/stackit/services/logme/credentials/resource.go b/stackit/services/logme/credentials/resource.go index 36b3ff392..bfc25a99f 100644 --- a/stackit/services/logme/credentials/resource.go +++ b/stackit/services/logme/credentials/resource.go @@ -25,9 +25,9 @@ import ( // Ensure the implementation satisfies the expected interfaces. var ( - _ resource.Resource = &logmeCredentialsResource{} - _ resource.ResourceWithConfigure = &logmeCredentialsResource{} - _ resource.ResourceWithImportState = &logmeCredentialsResource{} + _ resource.Resource = &logMeCredentialsResource{} + _ resource.ResourceWithConfigure = &logMeCredentialsResource{} + _ resource.ResourceWithImportState = &logMeCredentialsResource{} ) type Model struct { @@ -47,21 +47,21 @@ type Model struct { // NewCredentialsResource is a helper function to simplify the provider implementation. func NewCredentialsResource() resource.Resource { - return &logmeCredentialsResource{} + return &logMeCredentialsResource{} } // credentialsResource is the resource implementation. -type logmeCredentialsResource struct { +type logMeCredentialsResource struct { client *logme.APIClient } // Metadata returns the resource type name. -func (r *logmeCredentialsResource) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { +func (r *logMeCredentialsResource) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { resp.TypeName = req.ProviderTypeName + "_logme_credentials" } // Configure adds the provider configured client to the resource. -func (r *logmeCredentialsResource) Configure(ctx context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { +func (r *logMeCredentialsResource) Configure(ctx context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { // Prevent panic if the provider has not been configured. if req.ProviderData == nil { return @@ -97,7 +97,7 @@ func (r *logmeCredentialsResource) Configure(ctx context.Context, req resource.C } // Schema defines the schema for the resource. -func (r *logmeCredentialsResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) { +func (r *logMeCredentialsResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) { descriptions := map[string]string{ "main": "LogMe credentials resource schema.", "id": "Terraform's internal resource identifier. It is structured as \"`project_id`,`instance_id`,`credentials_id`\".", @@ -182,7 +182,7 @@ func (r *logmeCredentialsResource) Schema(_ context.Context, _ resource.SchemaRe } // Create creates the resource and sets the initial Terraform state. -func (r *logmeCredentialsResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { // nolint:gocritic // function signature required by Terraform +func (r *logMeCredentialsResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { // nolint:gocritic // function signature required by Terraform var model Model diags := req.Plan.Get(ctx, &model) resp.Diagnostics.Append(diags...) @@ -233,7 +233,7 @@ func (r *logmeCredentialsResource) Create(ctx context.Context, req resource.Crea } // Read refreshes the Terraform state with the latest data. -func (r *logmeCredentialsResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { // nolint:gocritic // function signature required by Terraform +func (r *logMeCredentialsResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { // nolint:gocritic // function signature required by Terraform var model Model diags := req.State.Get(ctx, &model) resp.Diagnostics.Append(diags...) @@ -270,13 +270,13 @@ func (r *logmeCredentialsResource) Read(ctx context.Context, req resource.ReadRe } // Update updates the resource and sets the updated Terraform state on success. -func (r *logmeCredentialsResource) Update(ctx context.Context, _ resource.UpdateRequest, resp *resource.UpdateResponse) { // nolint:gocritic // function signature required by Terraform +func (r *logMeCredentialsResource) Update(ctx context.Context, _ resource.UpdateRequest, resp *resource.UpdateResponse) { // nolint:gocritic // function signature required by Terraform // Update shouldn't be called core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating credentials", "Credentials can't be updated") } // Delete deletes the resource and removes the Terraform state on success. -func (r *logmeCredentialsResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { // nolint:gocritic // function signature required by Terraform +func (r *logMeCredentialsResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { // nolint:gocritic // function signature required by Terraform var model Model diags := req.State.Get(ctx, &model) resp.Diagnostics.Append(diags...) @@ -306,7 +306,7 @@ func (r *logmeCredentialsResource) Delete(ctx context.Context, req resource.Dele // ImportState imports a resource into the Terraform state on success. // The expected format of the resource import identifier is: project_id,instance_id,credentials_id -func (r *logmeCredentialsResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { +func (r *logMeCredentialsResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { idParts := strings.Split(req.ID, core.Separator) if len(idParts) != 3 || idParts[0] == "" || idParts[1] == "" || idParts[2] == "" { core.LogAndAddError(ctx, &resp.Diagnostics, diff --git a/stackit/services/opensearch/credentials/resource.go b/stackit/services/opensearch/credentials/resource.go index fd077ed5a..f6f5171ba 100644 --- a/stackit/services/opensearch/credentials/resource.go +++ b/stackit/services/opensearch/credentials/resource.go @@ -25,9 +25,9 @@ import ( // Ensure the implementation satisfies the expected interfaces. var ( - _ resource.Resource = &opensearchCredentialsResource{} - _ resource.ResourceWithConfigure = &opensearchCredentialsResource{} - _ resource.ResourceWithImportState = &opensearchCredentialsResource{} + _ resource.Resource = &openSearchCredentialsResource{} + _ resource.ResourceWithConfigure = &openSearchCredentialsResource{} + _ resource.ResourceWithImportState = &openSearchCredentialsResource{} ) type Model struct { @@ -47,21 +47,21 @@ type Model struct { // NewCredentialsResource is a helper function to simplify the provider implementation. func NewCredentialsResource() resource.Resource { - return &opensearchCredentialsResource{} + return &openSearchCredentialsResource{} } // credentialsResource is the resource implementation. -type opensearchCredentialsResource struct { +type openSearchCredentialsResource struct { client *opensearch.APIClient } // Metadata returns the resource type name. -func (r *opensearchCredentialsResource) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { +func (r *openSearchCredentialsResource) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { resp.TypeName = req.ProviderTypeName + "_opensearch_credentials" } // Configure adds the provider configured client to the resource. -func (r *opensearchCredentialsResource) Configure(ctx context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { +func (r *openSearchCredentialsResource) Configure(ctx context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { // Prevent panic if the provider has not been configured. if req.ProviderData == nil { return @@ -97,7 +97,7 @@ func (r *opensearchCredentialsResource) Configure(ctx context.Context, req resou } // Schema defines the schema for the resource. -func (r *opensearchCredentialsResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) { +func (r *openSearchCredentialsResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) { descriptions := map[string]string{ "main": "OpenSearch credentials resource schema.", "id": "Terraform's internal resource identifier. It is structured as \"`project_id`,`instance_id`,`credentials_id`\".", @@ -182,7 +182,7 @@ func (r *opensearchCredentialsResource) Schema(_ context.Context, _ resource.Sch } // Create creates the resource and sets the initial Terraform state. -func (r *opensearchCredentialsResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { // nolint:gocritic // function signature required by Terraform +func (r *openSearchCredentialsResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { // nolint:gocritic // function signature required by Terraform var model Model diags := req.Plan.Get(ctx, &model) resp.Diagnostics.Append(diags...) @@ -233,7 +233,7 @@ func (r *opensearchCredentialsResource) Create(ctx context.Context, req resource } // Read refreshes the Terraform state with the latest data. -func (r *opensearchCredentialsResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { // nolint:gocritic // function signature required by Terraform +func (r *openSearchCredentialsResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { // nolint:gocritic // function signature required by Terraform var model Model diags := req.State.Get(ctx, &model) resp.Diagnostics.Append(diags...) @@ -270,13 +270,13 @@ func (r *opensearchCredentialsResource) Read(ctx context.Context, req resource.R } // Update updates the resource and sets the updated Terraform state on success. -func (r *opensearchCredentialsResource) Update(ctx context.Context, _ resource.UpdateRequest, resp *resource.UpdateResponse) { // nolint:gocritic // function signature required by Terraform +func (r *openSearchCredentialsResource) Update(ctx context.Context, _ resource.UpdateRequest, resp *resource.UpdateResponse) { // nolint:gocritic // function signature required by Terraform // Update shouldn't be called core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating credentials", "Credentials can't be updated") } // Delete deletes the resource and removes the Terraform state on success. -func (r *opensearchCredentialsResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { // nolint:gocritic // function signature required by Terraform +func (r *openSearchCredentialsResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { // nolint:gocritic // function signature required by Terraform var model Model diags := req.State.Get(ctx, &model) resp.Diagnostics.Append(diags...) @@ -306,7 +306,7 @@ func (r *opensearchCredentialsResource) Delete(ctx context.Context, req resource // ImportState imports a resource into the Terraform state on success. // The expected format of the resource import identifier is: project_id,instance_id,credentials_id -func (r *opensearchCredentialsResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { +func (r *openSearchCredentialsResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { idParts := strings.Split(req.ID, core.Separator) if len(idParts) != 3 || idParts[0] == "" || idParts[1] == "" || idParts[2] == "" { core.LogAndAddError(ctx, &resp.Diagnostics, diff --git a/stackit/services/postgresql/credentials/resource.go b/stackit/services/postgresql/credentials/resource.go index 81ab66dac..9f399e9bf 100644 --- a/stackit/services/postgresql/credentials/resource.go +++ b/stackit/services/postgresql/credentials/resource.go @@ -25,9 +25,9 @@ import ( // Ensure the implementation satisfies the expected interfaces. var ( - _ resource.Resource = &postgresqlCredentialsResource{} - _ resource.ResourceWithConfigure = &postgresqlCredentialsResource{} - _ resource.ResourceWithImportState = &postgresqlCredentialsResource{} + _ resource.Resource = &postgreSQLCredentialsResource{} + _ resource.ResourceWithConfigure = &postgreSQLCredentialsResource{} + _ resource.ResourceWithImportState = &postgreSQLCredentialsResource{} ) type Model struct { @@ -47,21 +47,21 @@ type Model struct { // NewCredentialsResource is a helper function to simplify the provider implementation. func NewCredentialsResource() resource.Resource { - return &postgresqlCredentialsResource{} + return &postgreSQLCredentialsResource{} } // credentialsResource is the resource implementation. -type postgresqlCredentialsResource struct { +type postgreSQLCredentialsResource struct { client *postgresql.APIClient } // Metadata returns the resource type name. -func (r *postgresqlCredentialsResource) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { +func (r *postgreSQLCredentialsResource) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { resp.TypeName = req.ProviderTypeName + "_postgresql_credentials" } // Configure adds the provider configured client to the resource. -func (r *postgresqlCredentialsResource) Configure(ctx context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { +func (r *postgreSQLCredentialsResource) Configure(ctx context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { // Prevent panic if the provider has not been configured. if req.ProviderData == nil { return @@ -97,7 +97,7 @@ func (r *postgresqlCredentialsResource) Configure(ctx context.Context, req resou } // Schema defines the schema for the resource. -func (r *postgresqlCredentialsResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) { +func (r *postgreSQLCredentialsResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) { descriptions := map[string]string{ "main": "PostgreSQL credentials resource schema.", "id": "Terraform's internal resource identifier. It is structured as \"`project_id`,`instance_id`,`credentials_id`\".", @@ -182,7 +182,7 @@ func (r *postgresqlCredentialsResource) Schema(_ context.Context, _ resource.Sch } // Create creates the resource and sets the initial Terraform state. -func (r *postgresqlCredentialsResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { // nolint:gocritic // function signature required by Terraform +func (r *postgreSQLCredentialsResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { // nolint:gocritic // function signature required by Terraform var model Model diags := req.Plan.Get(ctx, &model) resp.Diagnostics.Append(diags...) @@ -233,7 +233,7 @@ func (r *postgresqlCredentialsResource) Create(ctx context.Context, req resource } // Read refreshes the Terraform state with the latest data. -func (r *postgresqlCredentialsResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { // nolint:gocritic // function signature required by Terraform +func (r *postgreSQLCredentialsResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { // nolint:gocritic // function signature required by Terraform var model Model diags := req.State.Get(ctx, &model) resp.Diagnostics.Append(diags...) @@ -270,13 +270,13 @@ func (r *postgresqlCredentialsResource) Read(ctx context.Context, req resource.R } // Update updates the resource and sets the updated Terraform state on success. -func (r *postgresqlCredentialsResource) Update(ctx context.Context, _ resource.UpdateRequest, resp *resource.UpdateResponse) { // nolint:gocritic // function signature required by Terraform +func (r *postgreSQLCredentialsResource) Update(ctx context.Context, _ resource.UpdateRequest, resp *resource.UpdateResponse) { // nolint:gocritic // function signature required by Terraform // Update shouldn't be called core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating credentials", "Credentials can't be updated") } // Delete deletes the resource and removes the Terraform state on success. -func (r *postgresqlCredentialsResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { // nolint:gocritic // function signature required by Terraform +func (r *postgreSQLCredentialsResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { // nolint:gocritic // function signature required by Terraform var model Model diags := req.State.Get(ctx, &model) resp.Diagnostics.Append(diags...) @@ -306,7 +306,7 @@ func (r *postgresqlCredentialsResource) Delete(ctx context.Context, req resource // ImportState imports a resource into the Terraform state on success. // The expected format of the resource import identifier is: project_id,instance_id,credentials_id -func (r *postgresqlCredentialsResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { +func (r *postgreSQLCredentialsResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { idParts := strings.Split(req.ID, core.Separator) if len(idParts) != 3 || idParts[0] == "" || idParts[1] == "" || idParts[2] == "" { core.LogAndAddError(ctx, &resp.Diagnostics, diff --git a/stackit/services/rabbitmq/credentials/resource.go b/stackit/services/rabbitmq/credentials/resource.go index 07da9ba4a..9eaab8784 100644 --- a/stackit/services/rabbitmq/credentials/resource.go +++ b/stackit/services/rabbitmq/credentials/resource.go @@ -25,9 +25,9 @@ import ( // Ensure the implementation satisfies the expected interfaces. var ( - _ resource.Resource = &rabbitmqCredentialsResource{} - _ resource.ResourceWithConfigure = &rabbitmqCredentialsResource{} - _ resource.ResourceWithImportState = &rabbitmqCredentialsResource{} + _ resource.Resource = &rabbitMQCredentialsResource{} + _ resource.ResourceWithConfigure = &rabbitMQCredentialsResource{} + _ resource.ResourceWithImportState = &rabbitMQCredentialsResource{} ) type Model struct { @@ -47,21 +47,21 @@ type Model struct { // NewCredentialsResource is a helper function to simplify the provider implementation. func NewCredentialsResource() resource.Resource { - return &rabbitmqCredentialsResource{} + return &rabbitMQCredentialsResource{} } // credentialsResource is the resource implementation. -type rabbitmqCredentialsResource struct { +type rabbitMQCredentialsResource struct { client *rabbitmq.APIClient } // Metadata returns the resource type name. -func (r *rabbitmqCredentialsResource) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { +func (r *rabbitMQCredentialsResource) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { resp.TypeName = req.ProviderTypeName + "_rabbitmq_credentials" } // Configure adds the provider configured client to the resource. -func (r *rabbitmqCredentialsResource) Configure(ctx context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { +func (r *rabbitMQCredentialsResource) Configure(ctx context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { // Prevent panic if the provider has not been configured. if req.ProviderData == nil { return @@ -97,7 +97,7 @@ func (r *rabbitmqCredentialsResource) Configure(ctx context.Context, req resourc } // Schema defines the schema for the resource. -func (r *rabbitmqCredentialsResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) { +func (r *rabbitMQCredentialsResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) { descriptions := map[string]string{ "main": "RabbitMQ credentials resource schema.", "id": "Terraform's internal resource identifier. It is structured as \"`project_id`,`instance_id`,`credentials_id`\".", @@ -182,7 +182,7 @@ func (r *rabbitmqCredentialsResource) Schema(_ context.Context, _ resource.Schem } // Create creates the resource and sets the initial Terraform state. -func (r *rabbitmqCredentialsResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { // nolint:gocritic // function signature required by Terraform +func (r *rabbitMQCredentialsResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { // nolint:gocritic // function signature required by Terraform var model Model diags := req.Plan.Get(ctx, &model) resp.Diagnostics.Append(diags...) @@ -233,7 +233,7 @@ func (r *rabbitmqCredentialsResource) Create(ctx context.Context, req resource.C } // Read refreshes the Terraform state with the latest data. -func (r *rabbitmqCredentialsResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { // nolint:gocritic // function signature required by Terraform +func (r *rabbitMQCredentialsResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { // nolint:gocritic // function signature required by Terraform var model Model diags := req.State.Get(ctx, &model) resp.Diagnostics.Append(diags...) @@ -270,13 +270,13 @@ func (r *rabbitmqCredentialsResource) Read(ctx context.Context, req resource.Rea } // Update updates the resource and sets the updated Terraform state on success. -func (r *rabbitmqCredentialsResource) Update(ctx context.Context, _ resource.UpdateRequest, resp *resource.UpdateResponse) { // nolint:gocritic // function signature required by Terraform +func (r *rabbitMQCredentialsResource) Update(ctx context.Context, _ resource.UpdateRequest, resp *resource.UpdateResponse) { // nolint:gocritic // function signature required by Terraform // Update shouldn't be called core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating credentials", "Credentials can't be updated") } // Delete deletes the resource and removes the Terraform state on success. -func (r *rabbitmqCredentialsResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { // nolint:gocritic // function signature required by Terraform +func (r *rabbitMQCredentialsResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { // nolint:gocritic // function signature required by Terraform var model Model diags := req.State.Get(ctx, &model) resp.Diagnostics.Append(diags...) @@ -306,7 +306,7 @@ func (r *rabbitmqCredentialsResource) Delete(ctx context.Context, req resource.D // ImportState imports a resource into the Terraform state on success. // The expected format of the resource import identifier is: project_id,instance_id,credentials_id -func (r *rabbitmqCredentialsResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { +func (r *rabbitMQCredentialsResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { idParts := strings.Split(req.ID, core.Separator) if len(idParts) != 3 || idParts[0] == "" || idParts[1] == "" || idParts[2] == "" { core.LogAndAddError(ctx, &resp.Diagnostics, From 6fba9fb4320794e5601de7d1d5ee4dfcf4984aa6 Mon Sep 17 00:00:00 2001 From: Henrique Santos Date: Thu, 21 Sep 2023 08:51:38 +0100 Subject: [PATCH 14/17] Rename symbols --- .../services/logme/credentials/resource.go | 26 +++++++++---------- .../services/mariadb/credentials/resource.go | 26 +++++++++---------- .../opensearch/credentials/resource.go | 26 +++++++++---------- .../postgresql/credentials/resource.go | 26 +++++++++---------- .../services/rabbitmq/credentials/resource.go | 26 +++++++++---------- 5 files changed, 65 insertions(+), 65 deletions(-) diff --git a/stackit/services/logme/credentials/resource.go b/stackit/services/logme/credentials/resource.go index bfc25a99f..f0a1b6f0c 100644 --- a/stackit/services/logme/credentials/resource.go +++ b/stackit/services/logme/credentials/resource.go @@ -25,9 +25,9 @@ import ( // Ensure the implementation satisfies the expected interfaces. var ( - _ resource.Resource = &logMeCredentialsResource{} - _ resource.ResourceWithConfigure = &logMeCredentialsResource{} - _ resource.ResourceWithImportState = &logMeCredentialsResource{} + _ resource.Resource = &credentialsResource{} + _ resource.ResourceWithConfigure = &credentialsResource{} + _ resource.ResourceWithImportState = &credentialsResource{} ) type Model struct { @@ -47,21 +47,21 @@ type Model struct { // NewCredentialsResource is a helper function to simplify the provider implementation. func NewCredentialsResource() resource.Resource { - return &logMeCredentialsResource{} + return &credentialsResource{} } // credentialsResource is the resource implementation. -type logMeCredentialsResource struct { +type credentialsResource struct { client *logme.APIClient } // Metadata returns the resource type name. -func (r *logMeCredentialsResource) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { +func (r *credentialsResource) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { resp.TypeName = req.ProviderTypeName + "_logme_credentials" } // Configure adds the provider configured client to the resource. -func (r *logMeCredentialsResource) Configure(ctx context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { +func (r *credentialsResource) Configure(ctx context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { // Prevent panic if the provider has not been configured. if req.ProviderData == nil { return @@ -97,7 +97,7 @@ func (r *logMeCredentialsResource) Configure(ctx context.Context, req resource.C } // Schema defines the schema for the resource. -func (r *logMeCredentialsResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) { +func (r *credentialsResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) { descriptions := map[string]string{ "main": "LogMe credentials resource schema.", "id": "Terraform's internal resource identifier. It is structured as \"`project_id`,`instance_id`,`credentials_id`\".", @@ -182,7 +182,7 @@ func (r *logMeCredentialsResource) Schema(_ context.Context, _ resource.SchemaRe } // Create creates the resource and sets the initial Terraform state. -func (r *logMeCredentialsResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { // nolint:gocritic // function signature required by Terraform +func (r *credentialsResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { // nolint:gocritic // function signature required by Terraform var model Model diags := req.Plan.Get(ctx, &model) resp.Diagnostics.Append(diags...) @@ -233,7 +233,7 @@ func (r *logMeCredentialsResource) Create(ctx context.Context, req resource.Crea } // Read refreshes the Terraform state with the latest data. -func (r *logMeCredentialsResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { // nolint:gocritic // function signature required by Terraform +func (r *credentialsResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { // nolint:gocritic // function signature required by Terraform var model Model diags := req.State.Get(ctx, &model) resp.Diagnostics.Append(diags...) @@ -270,13 +270,13 @@ func (r *logMeCredentialsResource) Read(ctx context.Context, req resource.ReadRe } // Update updates the resource and sets the updated Terraform state on success. -func (r *logMeCredentialsResource) Update(ctx context.Context, _ resource.UpdateRequest, resp *resource.UpdateResponse) { // nolint:gocritic // function signature required by Terraform +func (r *credentialsResource) Update(ctx context.Context, _ resource.UpdateRequest, resp *resource.UpdateResponse) { // nolint:gocritic // function signature required by Terraform // Update shouldn't be called core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating credentials", "Credentials can't be updated") } // Delete deletes the resource and removes the Terraform state on success. -func (r *logMeCredentialsResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { // nolint:gocritic // function signature required by Terraform +func (r *credentialsResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { // nolint:gocritic // function signature required by Terraform var model Model diags := req.State.Get(ctx, &model) resp.Diagnostics.Append(diags...) @@ -306,7 +306,7 @@ func (r *logMeCredentialsResource) Delete(ctx context.Context, req resource.Dele // ImportState imports a resource into the Terraform state on success. // The expected format of the resource import identifier is: project_id,instance_id,credentials_id -func (r *logMeCredentialsResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { +func (r *credentialsResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { idParts := strings.Split(req.ID, core.Separator) if len(idParts) != 3 || idParts[0] == "" || idParts[1] == "" || idParts[2] == "" { core.LogAndAddError(ctx, &resp.Diagnostics, diff --git a/stackit/services/mariadb/credentials/resource.go b/stackit/services/mariadb/credentials/resource.go index 93b0f1132..b539b5cc4 100644 --- a/stackit/services/mariadb/credentials/resource.go +++ b/stackit/services/mariadb/credentials/resource.go @@ -25,9 +25,9 @@ import ( // Ensure the implementation satisfies the expected interfaces. var ( - _ resource.Resource = &mariaDBCredentialsResource{} - _ resource.ResourceWithConfigure = &mariaDBCredentialsResource{} - _ resource.ResourceWithImportState = &mariaDBCredentialsResource{} + _ resource.Resource = &credentialsResource{} + _ resource.ResourceWithConfigure = &credentialsResource{} + _ resource.ResourceWithImportState = &credentialsResource{} ) type Model struct { @@ -47,21 +47,21 @@ type Model struct { // NewCredentialsResource is a helper function to simplify the provider implementation. func NewCredentialsResource() resource.Resource { - return &mariaDBCredentialsResource{} + return &credentialsResource{} } // credentialsResource is the resource implementation. -type mariaDBCredentialsResource struct { +type credentialsResource struct { client *mariadb.APIClient } // Metadata returns the resource type name. -func (r *mariaDBCredentialsResource) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { +func (r *credentialsResource) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { resp.TypeName = req.ProviderTypeName + "_mariadb_credentials" } // Configure adds the provider configured client to the resource. -func (r *mariaDBCredentialsResource) Configure(ctx context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { +func (r *credentialsResource) Configure(ctx context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { // Prevent panic if the provider has not been configured. if req.ProviderData == nil { return @@ -97,7 +97,7 @@ func (r *mariaDBCredentialsResource) Configure(ctx context.Context, req resource } // Schema defines the schema for the resource. -func (r *mariaDBCredentialsResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) { +func (r *credentialsResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) { descriptions := map[string]string{ "main": "MariaDB credentials resource schema.", "id": "Terraform's internal resource identifier. It is structured as \"`project_id`,`instance_id`,`credentials_id`\".", @@ -182,7 +182,7 @@ func (r *mariaDBCredentialsResource) Schema(_ context.Context, _ resource.Schema } // Create creates the resource and sets the initial Terraform state. -func (r *mariaDBCredentialsResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { // nolint:gocritic // function signature required by Terraform +func (r *credentialsResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { // nolint:gocritic // function signature required by Terraform var model Model diags := req.Plan.Get(ctx, &model) resp.Diagnostics.Append(diags...) @@ -233,7 +233,7 @@ func (r *mariaDBCredentialsResource) Create(ctx context.Context, req resource.Cr } // Read refreshes the Terraform state with the latest data. -func (r *mariaDBCredentialsResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { // nolint:gocritic // function signature required by Terraform +func (r *credentialsResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { // nolint:gocritic // function signature required by Terraform var model Model diags := req.State.Get(ctx, &model) resp.Diagnostics.Append(diags...) @@ -270,13 +270,13 @@ func (r *mariaDBCredentialsResource) Read(ctx context.Context, req resource.Read } // Update updates the resource and sets the updated Terraform state on success. -func (r *mariaDBCredentialsResource) Update(ctx context.Context, _ resource.UpdateRequest, resp *resource.UpdateResponse) { // nolint:gocritic // function signature required by Terraform +func (r *credentialsResource) Update(ctx context.Context, _ resource.UpdateRequest, resp *resource.UpdateResponse) { // nolint:gocritic // function signature required by Terraform // Update shouldn't be called core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating credentials", "Credentials can't be updated") } // Delete deletes the resource and removes the Terraform state on success. -func (r *mariaDBCredentialsResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { // nolint:gocritic // function signature required by Terraform +func (r *credentialsResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { // nolint:gocritic // function signature required by Terraform var model Model diags := req.State.Get(ctx, &model) resp.Diagnostics.Append(diags...) @@ -306,7 +306,7 @@ func (r *mariaDBCredentialsResource) Delete(ctx context.Context, req resource.De // ImportState imports a resource into the Terraform state on success. // The expected format of the resource import identifier is: project_id,instance_id,credentials_id -func (r *mariaDBCredentialsResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { +func (r *credentialsResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { idParts := strings.Split(req.ID, core.Separator) if len(idParts) != 3 || idParts[0] == "" || idParts[1] == "" || idParts[2] == "" { core.LogAndAddError(ctx, &resp.Diagnostics, diff --git a/stackit/services/opensearch/credentials/resource.go b/stackit/services/opensearch/credentials/resource.go index f6f5171ba..12bd5f05a 100644 --- a/stackit/services/opensearch/credentials/resource.go +++ b/stackit/services/opensearch/credentials/resource.go @@ -25,9 +25,9 @@ import ( // Ensure the implementation satisfies the expected interfaces. var ( - _ resource.Resource = &openSearchCredentialsResource{} - _ resource.ResourceWithConfigure = &openSearchCredentialsResource{} - _ resource.ResourceWithImportState = &openSearchCredentialsResource{} + _ resource.Resource = &credentialsResource{} + _ resource.ResourceWithConfigure = &credentialsResource{} + _ resource.ResourceWithImportState = &credentialsResource{} ) type Model struct { @@ -47,21 +47,21 @@ type Model struct { // NewCredentialsResource is a helper function to simplify the provider implementation. func NewCredentialsResource() resource.Resource { - return &openSearchCredentialsResource{} + return &credentialsResource{} } // credentialsResource is the resource implementation. -type openSearchCredentialsResource struct { +type credentialsResource struct { client *opensearch.APIClient } // Metadata returns the resource type name. -func (r *openSearchCredentialsResource) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { +func (r *credentialsResource) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { resp.TypeName = req.ProviderTypeName + "_opensearch_credentials" } // Configure adds the provider configured client to the resource. -func (r *openSearchCredentialsResource) Configure(ctx context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { +func (r *credentialsResource) Configure(ctx context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { // Prevent panic if the provider has not been configured. if req.ProviderData == nil { return @@ -97,7 +97,7 @@ func (r *openSearchCredentialsResource) Configure(ctx context.Context, req resou } // Schema defines the schema for the resource. -func (r *openSearchCredentialsResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) { +func (r *credentialsResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) { descriptions := map[string]string{ "main": "OpenSearch credentials resource schema.", "id": "Terraform's internal resource identifier. It is structured as \"`project_id`,`instance_id`,`credentials_id`\".", @@ -182,7 +182,7 @@ func (r *openSearchCredentialsResource) Schema(_ context.Context, _ resource.Sch } // Create creates the resource and sets the initial Terraform state. -func (r *openSearchCredentialsResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { // nolint:gocritic // function signature required by Terraform +func (r *credentialsResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { // nolint:gocritic // function signature required by Terraform var model Model diags := req.Plan.Get(ctx, &model) resp.Diagnostics.Append(diags...) @@ -233,7 +233,7 @@ func (r *openSearchCredentialsResource) Create(ctx context.Context, req resource } // Read refreshes the Terraform state with the latest data. -func (r *openSearchCredentialsResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { // nolint:gocritic // function signature required by Terraform +func (r *credentialsResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { // nolint:gocritic // function signature required by Terraform var model Model diags := req.State.Get(ctx, &model) resp.Diagnostics.Append(diags...) @@ -270,13 +270,13 @@ func (r *openSearchCredentialsResource) Read(ctx context.Context, req resource.R } // Update updates the resource and sets the updated Terraform state on success. -func (r *openSearchCredentialsResource) Update(ctx context.Context, _ resource.UpdateRequest, resp *resource.UpdateResponse) { // nolint:gocritic // function signature required by Terraform +func (r *credentialsResource) Update(ctx context.Context, _ resource.UpdateRequest, resp *resource.UpdateResponse) { // nolint:gocritic // function signature required by Terraform // Update shouldn't be called core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating credentials", "Credentials can't be updated") } // Delete deletes the resource and removes the Terraform state on success. -func (r *openSearchCredentialsResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { // nolint:gocritic // function signature required by Terraform +func (r *credentialsResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { // nolint:gocritic // function signature required by Terraform var model Model diags := req.State.Get(ctx, &model) resp.Diagnostics.Append(diags...) @@ -306,7 +306,7 @@ func (r *openSearchCredentialsResource) Delete(ctx context.Context, req resource // ImportState imports a resource into the Terraform state on success. // The expected format of the resource import identifier is: project_id,instance_id,credentials_id -func (r *openSearchCredentialsResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { +func (r *credentialsResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { idParts := strings.Split(req.ID, core.Separator) if len(idParts) != 3 || idParts[0] == "" || idParts[1] == "" || idParts[2] == "" { core.LogAndAddError(ctx, &resp.Diagnostics, diff --git a/stackit/services/postgresql/credentials/resource.go b/stackit/services/postgresql/credentials/resource.go index 9f399e9bf..5551cecc4 100644 --- a/stackit/services/postgresql/credentials/resource.go +++ b/stackit/services/postgresql/credentials/resource.go @@ -25,9 +25,9 @@ import ( // Ensure the implementation satisfies the expected interfaces. var ( - _ resource.Resource = &postgreSQLCredentialsResource{} - _ resource.ResourceWithConfigure = &postgreSQLCredentialsResource{} - _ resource.ResourceWithImportState = &postgreSQLCredentialsResource{} + _ resource.Resource = &credentialsResource{} + _ resource.ResourceWithConfigure = &credentialsResource{} + _ resource.ResourceWithImportState = &credentialsResource{} ) type Model struct { @@ -47,21 +47,21 @@ type Model struct { // NewCredentialsResource is a helper function to simplify the provider implementation. func NewCredentialsResource() resource.Resource { - return &postgreSQLCredentialsResource{} + return &credentialsResource{} } // credentialsResource is the resource implementation. -type postgreSQLCredentialsResource struct { +type credentialsResource struct { client *postgresql.APIClient } // Metadata returns the resource type name. -func (r *postgreSQLCredentialsResource) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { +func (r *credentialsResource) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { resp.TypeName = req.ProviderTypeName + "_postgresql_credentials" } // Configure adds the provider configured client to the resource. -func (r *postgreSQLCredentialsResource) Configure(ctx context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { +func (r *credentialsResource) Configure(ctx context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { // Prevent panic if the provider has not been configured. if req.ProviderData == nil { return @@ -97,7 +97,7 @@ func (r *postgreSQLCredentialsResource) Configure(ctx context.Context, req resou } // Schema defines the schema for the resource. -func (r *postgreSQLCredentialsResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) { +func (r *credentialsResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) { descriptions := map[string]string{ "main": "PostgreSQL credentials resource schema.", "id": "Terraform's internal resource identifier. It is structured as \"`project_id`,`instance_id`,`credentials_id`\".", @@ -182,7 +182,7 @@ func (r *postgreSQLCredentialsResource) Schema(_ context.Context, _ resource.Sch } // Create creates the resource and sets the initial Terraform state. -func (r *postgreSQLCredentialsResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { // nolint:gocritic // function signature required by Terraform +func (r *credentialsResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { // nolint:gocritic // function signature required by Terraform var model Model diags := req.Plan.Get(ctx, &model) resp.Diagnostics.Append(diags...) @@ -233,7 +233,7 @@ func (r *postgreSQLCredentialsResource) Create(ctx context.Context, req resource } // Read refreshes the Terraform state with the latest data. -func (r *postgreSQLCredentialsResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { // nolint:gocritic // function signature required by Terraform +func (r *credentialsResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { // nolint:gocritic // function signature required by Terraform var model Model diags := req.State.Get(ctx, &model) resp.Diagnostics.Append(diags...) @@ -270,13 +270,13 @@ func (r *postgreSQLCredentialsResource) Read(ctx context.Context, req resource.R } // Update updates the resource and sets the updated Terraform state on success. -func (r *postgreSQLCredentialsResource) Update(ctx context.Context, _ resource.UpdateRequest, resp *resource.UpdateResponse) { // nolint:gocritic // function signature required by Terraform +func (r *credentialsResource) Update(ctx context.Context, _ resource.UpdateRequest, resp *resource.UpdateResponse) { // nolint:gocritic // function signature required by Terraform // Update shouldn't be called core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating credentials", "Credentials can't be updated") } // Delete deletes the resource and removes the Terraform state on success. -func (r *postgreSQLCredentialsResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { // nolint:gocritic // function signature required by Terraform +func (r *credentialsResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { // nolint:gocritic // function signature required by Terraform var model Model diags := req.State.Get(ctx, &model) resp.Diagnostics.Append(diags...) @@ -306,7 +306,7 @@ func (r *postgreSQLCredentialsResource) Delete(ctx context.Context, req resource // ImportState imports a resource into the Terraform state on success. // The expected format of the resource import identifier is: project_id,instance_id,credentials_id -func (r *postgreSQLCredentialsResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { +func (r *credentialsResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { idParts := strings.Split(req.ID, core.Separator) if len(idParts) != 3 || idParts[0] == "" || idParts[1] == "" || idParts[2] == "" { core.LogAndAddError(ctx, &resp.Diagnostics, diff --git a/stackit/services/rabbitmq/credentials/resource.go b/stackit/services/rabbitmq/credentials/resource.go index 9eaab8784..bb835ebbc 100644 --- a/stackit/services/rabbitmq/credentials/resource.go +++ b/stackit/services/rabbitmq/credentials/resource.go @@ -25,9 +25,9 @@ import ( // Ensure the implementation satisfies the expected interfaces. var ( - _ resource.Resource = &rabbitMQCredentialsResource{} - _ resource.ResourceWithConfigure = &rabbitMQCredentialsResource{} - _ resource.ResourceWithImportState = &rabbitMQCredentialsResource{} + _ resource.Resource = &credentialsResource{} + _ resource.ResourceWithConfigure = &credentialsResource{} + _ resource.ResourceWithImportState = &credentialsResource{} ) type Model struct { @@ -47,21 +47,21 @@ type Model struct { // NewCredentialsResource is a helper function to simplify the provider implementation. func NewCredentialsResource() resource.Resource { - return &rabbitMQCredentialsResource{} + return &credentialsResource{} } // credentialsResource is the resource implementation. -type rabbitMQCredentialsResource struct { +type credentialsResource struct { client *rabbitmq.APIClient } // Metadata returns the resource type name. -func (r *rabbitMQCredentialsResource) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { +func (r *credentialsResource) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { resp.TypeName = req.ProviderTypeName + "_rabbitmq_credentials" } // Configure adds the provider configured client to the resource. -func (r *rabbitMQCredentialsResource) Configure(ctx context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { +func (r *credentialsResource) Configure(ctx context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { // Prevent panic if the provider has not been configured. if req.ProviderData == nil { return @@ -97,7 +97,7 @@ func (r *rabbitMQCredentialsResource) Configure(ctx context.Context, req resourc } // Schema defines the schema for the resource. -func (r *rabbitMQCredentialsResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) { +func (r *credentialsResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) { descriptions := map[string]string{ "main": "RabbitMQ credentials resource schema.", "id": "Terraform's internal resource identifier. It is structured as \"`project_id`,`instance_id`,`credentials_id`\".", @@ -182,7 +182,7 @@ func (r *rabbitMQCredentialsResource) Schema(_ context.Context, _ resource.Schem } // Create creates the resource and sets the initial Terraform state. -func (r *rabbitMQCredentialsResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { // nolint:gocritic // function signature required by Terraform +func (r *credentialsResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { // nolint:gocritic // function signature required by Terraform var model Model diags := req.Plan.Get(ctx, &model) resp.Diagnostics.Append(diags...) @@ -233,7 +233,7 @@ func (r *rabbitMQCredentialsResource) Create(ctx context.Context, req resource.C } // Read refreshes the Terraform state with the latest data. -func (r *rabbitMQCredentialsResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { // nolint:gocritic // function signature required by Terraform +func (r *credentialsResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { // nolint:gocritic // function signature required by Terraform var model Model diags := req.State.Get(ctx, &model) resp.Diagnostics.Append(diags...) @@ -270,13 +270,13 @@ func (r *rabbitMQCredentialsResource) Read(ctx context.Context, req resource.Rea } // Update updates the resource and sets the updated Terraform state on success. -func (r *rabbitMQCredentialsResource) Update(ctx context.Context, _ resource.UpdateRequest, resp *resource.UpdateResponse) { // nolint:gocritic // function signature required by Terraform +func (r *credentialsResource) Update(ctx context.Context, _ resource.UpdateRequest, resp *resource.UpdateResponse) { // nolint:gocritic // function signature required by Terraform // Update shouldn't be called core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating credentials", "Credentials can't be updated") } // Delete deletes the resource and removes the Terraform state on success. -func (r *rabbitMQCredentialsResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { // nolint:gocritic // function signature required by Terraform +func (r *credentialsResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { // nolint:gocritic // function signature required by Terraform var model Model diags := req.State.Get(ctx, &model) resp.Diagnostics.Append(diags...) @@ -306,7 +306,7 @@ func (r *rabbitMQCredentialsResource) Delete(ctx context.Context, req resource.D // ImportState imports a resource into the Terraform state on success. // The expected format of the resource import identifier is: project_id,instance_id,credentials_id -func (r *rabbitMQCredentialsResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { +func (r *credentialsResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { idParts := strings.Split(req.ID, core.Separator) if len(idParts) != 3 || idParts[0] == "" || idParts[1] == "" || idParts[2] == "" { core.LogAndAddError(ctx, &resp.Diagnostics, From 562d0e12a58443c40d4ac4f60169cb093f6b7987 Mon Sep 17 00:00:00 2001 From: Henrique Santos Date: Thu, 21 Sep 2023 08:56:16 +0100 Subject: [PATCH 15/17] Change import log message --- stackit/services/argus/instance/resource.go | 2 +- stackit/services/argus/scrapeconfig/resource.go | 2 +- stackit/services/dns/recordset/resource.go | 2 +- stackit/services/dns/zone/resource.go | 2 +- stackit/services/logme/credentials/resource.go | 2 +- stackit/services/logme/instance/resource.go | 2 +- stackit/services/mariadb/credentials/resource.go | 2 +- stackit/services/mariadb/instance/resource.go | 2 +- stackit/services/opensearch/credentials/resource.go | 2 +- stackit/services/opensearch/instance/resource.go | 2 +- stackit/services/postgresflex/instance/resource.go | 2 +- stackit/services/postgresflex/user/resource.go | 2 +- stackit/services/postgresql/credentials/resource.go | 2 +- stackit/services/postgresql/instance/resource.go | 2 +- stackit/services/rabbitmq/credentials/resource.go | 2 +- stackit/services/rabbitmq/instance/resource.go | 2 +- stackit/services/redis/credentials/resource.go | 2 +- stackit/services/redis/instance/resource.go | 2 +- stackit/services/resourcemanager/project/resource.go | 2 +- stackit/services/ske/cluster/resource.go | 2 +- stackit/services/ske/project/resource.go | 2 +- 21 files changed, 21 insertions(+), 21 deletions(-) diff --git a/stackit/services/argus/instance/resource.go b/stackit/services/argus/instance/resource.go index a38c54547..dff94f441 100644 --- a/stackit/services/argus/instance/resource.go +++ b/stackit/services/argus/instance/resource.go @@ -435,7 +435,7 @@ func (r *instanceResource) ImportState(ctx context.Context, req resource.ImportS if len(idParts) != 2 || idParts[0] == "" || idParts[1] == "" { core.LogAndAddError(ctx, &resp.Diagnostics, - "Unexpected import identifier", + "Error importing instance", fmt.Sprintf("Expected import identifier with format: [project_id],[instance_id] Got: %q", req.ID), ) return diff --git a/stackit/services/argus/scrapeconfig/resource.go b/stackit/services/argus/scrapeconfig/resource.go index 3caa06c74..10adb7e7f 100644 --- a/stackit/services/argus/scrapeconfig/resource.go +++ b/stackit/services/argus/scrapeconfig/resource.go @@ -425,7 +425,7 @@ func (r *scrapeConfigResource) ImportState(ctx context.Context, req resource.Imp if len(idParts) != 3 || idParts[0] == "" || idParts[1] == "" || idParts[2] == "" { core.LogAndAddError(ctx, &resp.Diagnostics, - "Unexpected import identifier", + "Error importing scrape config", fmt.Sprintf("Expected import identifier with format: [project_id],[instance_id],[name] Got: %q", req.ID), ) return diff --git a/stackit/services/dns/recordset/resource.go b/stackit/services/dns/recordset/resource.go index 6e45277a2..36a4a7f3b 100644 --- a/stackit/services/dns/recordset/resource.go +++ b/stackit/services/dns/recordset/resource.go @@ -394,7 +394,7 @@ func (r *recordSetResource) ImportState(ctx context.Context, req resource.Import idParts := strings.Split(req.ID, core.Separator) if len(idParts) != 3 || idParts[0] == "" || idParts[1] == "" || idParts[2] == "" { core.LogAndAddError(ctx, &resp.Diagnostics, - "Unexpected import identifier", + "Error importing record set", fmt.Sprintf("Expected import identifier with format [project_id],[zone_id],[record_set_id], got %q", req.ID), ) return diff --git a/stackit/services/dns/zone/resource.go b/stackit/services/dns/zone/resource.go index 0458946e6..e7740bd7b 100644 --- a/stackit/services/dns/zone/resource.go +++ b/stackit/services/dns/zone/resource.go @@ -474,7 +474,7 @@ func (r *zoneResource) ImportState(ctx context.Context, req resource.ImportState if len(idParts) != 2 || idParts[0] == "" || idParts[1] == "" { core.LogAndAddError(ctx, &resp.Diagnostics, - "Unexpected import identifier", + "Error importing zone", fmt.Sprintf("Expected import identifier with format: [project_id],[zone_id] Got: %q", req.ID), ) return diff --git a/stackit/services/logme/credentials/resource.go b/stackit/services/logme/credentials/resource.go index f0a1b6f0c..f1e32f15d 100644 --- a/stackit/services/logme/credentials/resource.go +++ b/stackit/services/logme/credentials/resource.go @@ -310,7 +310,7 @@ func (r *credentialsResource) ImportState(ctx context.Context, req resource.Impo idParts := strings.Split(req.ID, core.Separator) if len(idParts) != 3 || idParts[0] == "" || idParts[1] == "" || idParts[2] == "" { core.LogAndAddError(ctx, &resp.Diagnostics, - "Unexpected import identifier", + "Error importing credentials", fmt.Sprintf("Expected import identifier with format [project_id],[instance_id],[credentials_id], got %q", req.ID), ) return diff --git a/stackit/services/logme/instance/resource.go b/stackit/services/logme/instance/resource.go index c6dc2a959..b39ef8ea4 100644 --- a/stackit/services/logme/instance/resource.go +++ b/stackit/services/logme/instance/resource.go @@ -445,7 +445,7 @@ func (r *instanceResource) ImportState(ctx context.Context, req resource.ImportS if len(idParts) != 2 || idParts[0] == "" || idParts[1] == "" { core.LogAndAddError(ctx, &resp.Diagnostics, - "Unexpected import identifier", + "Error importing instance", fmt.Sprintf("Expected import identifier with format: [project_id],[instance_id] Got: %q", req.ID), ) return diff --git a/stackit/services/mariadb/credentials/resource.go b/stackit/services/mariadb/credentials/resource.go index b539b5cc4..54557b58a 100644 --- a/stackit/services/mariadb/credentials/resource.go +++ b/stackit/services/mariadb/credentials/resource.go @@ -310,7 +310,7 @@ func (r *credentialsResource) ImportState(ctx context.Context, req resource.Impo idParts := strings.Split(req.ID, core.Separator) if len(idParts) != 3 || idParts[0] == "" || idParts[1] == "" || idParts[2] == "" { core.LogAndAddError(ctx, &resp.Diagnostics, - "Unexpected import identifier", + "Error importing credentials", fmt.Sprintf("Expected import identifier with format [project_id],[instance_id],[credentials_id], got %q", req.ID), ) return diff --git a/stackit/services/mariadb/instance/resource.go b/stackit/services/mariadb/instance/resource.go index bfe116cdb..7e0e61346 100644 --- a/stackit/services/mariadb/instance/resource.go +++ b/stackit/services/mariadb/instance/resource.go @@ -445,7 +445,7 @@ func (r *instanceResource) ImportState(ctx context.Context, req resource.ImportS if len(idParts) != 2 || idParts[0] == "" || idParts[1] == "" { core.LogAndAddError(ctx, &resp.Diagnostics, - "Unexpected import identifier", + "Error importing instance", fmt.Sprintf("Expected import identifier with format: [project_id],[instance_id] Got: %q", req.ID), ) return diff --git a/stackit/services/opensearch/credentials/resource.go b/stackit/services/opensearch/credentials/resource.go index 12bd5f05a..d12862ac5 100644 --- a/stackit/services/opensearch/credentials/resource.go +++ b/stackit/services/opensearch/credentials/resource.go @@ -310,7 +310,7 @@ func (r *credentialsResource) ImportState(ctx context.Context, req resource.Impo idParts := strings.Split(req.ID, core.Separator) if len(idParts) != 3 || idParts[0] == "" || idParts[1] == "" || idParts[2] == "" { core.LogAndAddError(ctx, &resp.Diagnostics, - "Unexpected import identifier", + "Error importing credentials", fmt.Sprintf("Expected import identifier with format [project_id],[instance_id],[credentials_id], got %q", req.ID), ) return diff --git a/stackit/services/opensearch/instance/resource.go b/stackit/services/opensearch/instance/resource.go index 188aa1d75..938efed27 100644 --- a/stackit/services/opensearch/instance/resource.go +++ b/stackit/services/opensearch/instance/resource.go @@ -445,7 +445,7 @@ func (r *instanceResource) ImportState(ctx context.Context, req resource.ImportS if len(idParts) != 2 || idParts[0] == "" || idParts[1] == "" { core.LogAndAddError(ctx, &resp.Diagnostics, - "Unexpected import identifier", + "Error importing instance", fmt.Sprintf("Expected import identifier with format: [project_id],[instance_id] Got: %q", req.ID), ) return diff --git a/stackit/services/postgresflex/instance/resource.go b/stackit/services/postgresflex/instance/resource.go index 443f8e7ff..2a9b19603 100644 --- a/stackit/services/postgresflex/instance/resource.go +++ b/stackit/services/postgresflex/instance/resource.go @@ -480,7 +480,7 @@ func (r *instanceResource) ImportState(ctx context.Context, req resource.ImportS if len(idParts) != 2 || idParts[0] == "" || idParts[1] == "" { core.LogAndAddError(ctx, &resp.Diagnostics, - "Unexpected import identifier", + "Error importing instance", fmt.Sprintf("Expected import identifier with format: [project_id],[instance_id] Got: %q", req.ID), ) return diff --git a/stackit/services/postgresflex/user/resource.go b/stackit/services/postgresflex/user/resource.go index cdc395844..a42d799c5 100644 --- a/stackit/services/postgresflex/user/resource.go +++ b/stackit/services/postgresflex/user/resource.go @@ -317,7 +317,7 @@ func (r *userResource) ImportState(ctx context.Context, req resource.ImportState idParts := strings.Split(req.ID, core.Separator) if len(idParts) != 3 || idParts[0] == "" || idParts[1] == "" || idParts[2] == "" { core.LogAndAddError(ctx, &resp.Diagnostics, - "Unexpected import identifier", + "Error importing user", fmt.Sprintf("Expected import identifier with format [project_id],[instance_id],[user_id], got %q", req.ID), ) return diff --git a/stackit/services/postgresql/credentials/resource.go b/stackit/services/postgresql/credentials/resource.go index 5551cecc4..76a55e239 100644 --- a/stackit/services/postgresql/credentials/resource.go +++ b/stackit/services/postgresql/credentials/resource.go @@ -310,7 +310,7 @@ func (r *credentialsResource) ImportState(ctx context.Context, req resource.Impo idParts := strings.Split(req.ID, core.Separator) if len(idParts) != 3 || idParts[0] == "" || idParts[1] == "" || idParts[2] == "" { core.LogAndAddError(ctx, &resp.Diagnostics, - "Unexpected import identifier", + "Error importing credentials", fmt.Sprintf("Expected import identifier with format [project_id],[instance_id],[credentials_id], got %q", req.ID), ) return diff --git a/stackit/services/postgresql/instance/resource.go b/stackit/services/postgresql/instance/resource.go index 3c6ea955a..0739c85c2 100644 --- a/stackit/services/postgresql/instance/resource.go +++ b/stackit/services/postgresql/instance/resource.go @@ -545,7 +545,7 @@ func (r *instanceResource) ImportState(ctx context.Context, req resource.ImportS if len(idParts) != 2 || idParts[0] == "" || idParts[1] == "" { core.LogAndAddError(ctx, &resp.Diagnostics, - "Unexpected import identifier", + "Error importing instance", fmt.Sprintf("Expected import identifier with format: [project_id],[instance_id] Got: %q", req.ID), ) return diff --git a/stackit/services/rabbitmq/credentials/resource.go b/stackit/services/rabbitmq/credentials/resource.go index bb835ebbc..8d45ea7de 100644 --- a/stackit/services/rabbitmq/credentials/resource.go +++ b/stackit/services/rabbitmq/credentials/resource.go @@ -310,7 +310,7 @@ func (r *credentialsResource) ImportState(ctx context.Context, req resource.Impo idParts := strings.Split(req.ID, core.Separator) if len(idParts) != 3 || idParts[0] == "" || idParts[1] == "" || idParts[2] == "" { core.LogAndAddError(ctx, &resp.Diagnostics, - "Unexpected import identifier", + "Error importing credentials", fmt.Sprintf("Expected import identifier with format [project_id],[instance_id],[credentials_id], got %q", req.ID), ) return diff --git a/stackit/services/rabbitmq/instance/resource.go b/stackit/services/rabbitmq/instance/resource.go index 579047065..f005e822d 100644 --- a/stackit/services/rabbitmq/instance/resource.go +++ b/stackit/services/rabbitmq/instance/resource.go @@ -445,7 +445,7 @@ func (r *instanceResource) ImportState(ctx context.Context, req resource.ImportS if len(idParts) != 2 || idParts[0] == "" || idParts[1] == "" { core.LogAndAddError(ctx, &resp.Diagnostics, - "Unexpected import identifier", + "Error importing instance", fmt.Sprintf("Expected import identifier with format: [project_id],[instance_id] Got: %q", req.ID), ) return diff --git a/stackit/services/redis/credentials/resource.go b/stackit/services/redis/credentials/resource.go index cf5cf91f4..c8b986948 100644 --- a/stackit/services/redis/credentials/resource.go +++ b/stackit/services/redis/credentials/resource.go @@ -310,7 +310,7 @@ func (r *redisCredentialsResource) ImportState(ctx context.Context, req resource idParts := strings.Split(req.ID, core.Separator) if len(idParts) != 3 || idParts[0] == "" || idParts[1] == "" || idParts[2] == "" { core.LogAndAddError(ctx, &resp.Diagnostics, - "Unexpected import identifier", + "Error importing credentials", fmt.Sprintf("Expected import identifier with format [project_id],[instance_id],[credentials_id], got %q", req.ID), ) return diff --git a/stackit/services/redis/instance/resource.go b/stackit/services/redis/instance/resource.go index d7292bac5..b6b996e3c 100644 --- a/stackit/services/redis/instance/resource.go +++ b/stackit/services/redis/instance/resource.go @@ -445,7 +445,7 @@ func (r *instanceResource) ImportState(ctx context.Context, req resource.ImportS if len(idParts) != 2 || idParts[0] == "" || idParts[1] == "" { core.LogAndAddError(ctx, &resp.Diagnostics, - "Unexpected import identifier", + "Error importing instance", fmt.Sprintf("Expected import identifier with format: [project_id],[instance_id] Got: %q", req.ID), ) return diff --git a/stackit/services/resourcemanager/project/resource.go b/stackit/services/resourcemanager/project/resource.go index 45d2106c9..ccd9241b7 100644 --- a/stackit/services/resourcemanager/project/resource.go +++ b/stackit/services/resourcemanager/project/resource.go @@ -343,7 +343,7 @@ func (r *projectResource) ImportState(ctx context.Context, req resource.ImportSt idParts := strings.Split(req.ID, core.Separator) if len(idParts) != 1 || idParts[0] == "" { core.LogAndAddError(ctx, &resp.Diagnostics, - "Unexpected import identifier", + "Error importing project", fmt.Sprintf("Expected import identifier with format: [container_id] Got: %q", req.ID), ) return diff --git a/stackit/services/ske/cluster/resource.go b/stackit/services/ske/cluster/resource.go index 3df3c685c..3b059d247 100644 --- a/stackit/services/ske/cluster/resource.go +++ b/stackit/services/ske/cluster/resource.go @@ -1159,7 +1159,7 @@ func (r *clusterResource) ImportState(ctx context.Context, req resource.ImportSt if len(idParts) != 2 || idParts[0] == "" || idParts[1] == "" { core.LogAndAddError(ctx, &resp.Diagnostics, - "Unexpected import identifier", + "Error importing cluster", fmt.Sprintf("Expected import identifier with format: [project_id],[name] Got: %q", req.ID), ) return diff --git a/stackit/services/ske/project/resource.go b/stackit/services/ske/project/resource.go index f410cb587..fc4400aa2 100644 --- a/stackit/services/ske/project/resource.go +++ b/stackit/services/ske/project/resource.go @@ -202,7 +202,7 @@ func (r *projectResource) ImportState(ctx context.Context, req resource.ImportSt idParts := strings.Split(req.ID, core.Separator) if len(idParts) != 1 || idParts[0] == "" { core.LogAndAddError(ctx, &resp.Diagnostics, - "Unexpected import identifier", + "Error importing project", fmt.Sprintf("Expected import identifier with format: [project_id] Got: %q", req.ID), ) return From df889d441994327358a4dbfd70ddd103d2d64c6c Mon Sep 17 00:00:00 2001 From: Henrique Santos Date: Thu, 21 Sep 2023 13:09:08 +0100 Subject: [PATCH 16/17] Remove unnecessary calls of loadPlanNameAndVersion --- stackit/services/logme/instance/resource.go | 14 -------------- stackit/services/mariadb/instance/resource.go | 14 -------------- stackit/services/opensearch/instance/resource.go | 14 -------------- stackit/services/postgresql/instance/resource.go | 14 -------------- stackit/services/rabbitmq/instance/resource.go | 14 -------------- stackit/services/redis/instance/resource.go | 14 -------------- 6 files changed, 84 deletions(-) diff --git a/stackit/services/logme/instance/resource.go b/stackit/services/logme/instance/resource.go index b39ef8ea4..01b799004 100644 --- a/stackit/services/logme/instance/resource.go +++ b/stackit/services/logme/instance/resource.go @@ -279,13 +279,6 @@ func (r *instanceResource) Create(ctx context.Context, req resource.CreateReques return } - // Compute and store values not present in the API response - err = loadPlanNameAndVersion(ctx, r.client, &model) - if err != nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading instance", fmt.Sprintf("Loading service plan details: %v", err)) - return - } - // Set state to fully populated data diags = resp.State.Set(ctx, model) resp.Diagnostics.Append(diags...) @@ -395,13 +388,6 @@ func (r *instanceResource) Update(ctx context.Context, req resource.UpdateReques return } - // Compute and store values not present in the API response - err = loadPlanNameAndVersion(ctx, r.client, &model) - if err != nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading instance", fmt.Sprintf("Loading service plan details: %v", err)) - return - } - diags = resp.State.Set(ctx, model) resp.Diagnostics.Append(diags...) if resp.Diagnostics.HasError() { diff --git a/stackit/services/mariadb/instance/resource.go b/stackit/services/mariadb/instance/resource.go index 7e0e61346..67446387f 100644 --- a/stackit/services/mariadb/instance/resource.go +++ b/stackit/services/mariadb/instance/resource.go @@ -279,13 +279,6 @@ func (r *instanceResource) Create(ctx context.Context, req resource.CreateReques return } - // Compute and store values not present in the API response - err = loadPlanNameAndVersion(ctx, r.client, &model) - if err != nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading instance", fmt.Sprintf("Loading service plan details: %v", err)) - return - } - // Set state to fully populated data diags = resp.State.Set(ctx, model) resp.Diagnostics.Append(diags...) @@ -395,13 +388,6 @@ func (r *instanceResource) Update(ctx context.Context, req resource.UpdateReques return } - // Compute and store values not present in the API response - err = loadPlanNameAndVersion(ctx, r.client, &model) - if err != nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading instance", fmt.Sprintf("Loading service plan details: %v", err)) - return - } - diags = resp.State.Set(ctx, model) resp.Diagnostics.Append(diags...) if resp.Diagnostics.HasError() { diff --git a/stackit/services/opensearch/instance/resource.go b/stackit/services/opensearch/instance/resource.go index 938efed27..791912819 100644 --- a/stackit/services/opensearch/instance/resource.go +++ b/stackit/services/opensearch/instance/resource.go @@ -279,13 +279,6 @@ func (r *instanceResource) Create(ctx context.Context, req resource.CreateReques return } - // Compute and store values not present in the API response - err = loadPlanNameAndVersion(ctx, r.client, &model) - if err != nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading instance", fmt.Sprintf("Loading service plan details: %v", err)) - return - } - // Set state to fully populated data diags = resp.State.Set(ctx, model) resp.Diagnostics.Append(diags...) @@ -395,13 +388,6 @@ func (r *instanceResource) Update(ctx context.Context, req resource.UpdateReques return } - // Compute and store values not present in the API response - err = loadPlanNameAndVersion(ctx, r.client, &model) - if err != nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading instance", fmt.Sprintf("Loading service plan details: %v", err)) - return - } - diags = resp.State.Set(ctx, model) resp.Diagnostics.Append(diags...) if resp.Diagnostics.HasError() { diff --git a/stackit/services/postgresql/instance/resource.go b/stackit/services/postgresql/instance/resource.go index 0739c85c2..a4ba7a72e 100644 --- a/stackit/services/postgresql/instance/resource.go +++ b/stackit/services/postgresql/instance/resource.go @@ -320,13 +320,6 @@ func (r *instanceResource) Create(ctx context.Context, req resource.CreateReques return } - // Compute and store values not present in the API response - err = loadPlanNameAndVersion(ctx, r.client, &model) - if err != nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading instance", fmt.Sprintf("Loading service plan details: %v", err)) - return - } - // Set state to fully populated data diags = resp.State.Set(ctx, model) resp.Diagnostics.Append(diags...) @@ -472,13 +465,6 @@ func (r *instanceResource) Update(ctx context.Context, req resource.UpdateReques return } - // Compute and store values not present in the API response - err = loadPlanNameAndVersion(ctx, r.client, &model) - if err != nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading instance", fmt.Sprintf("Loading service plan details: %v", err)) - return - } - diags = resp.State.Set(ctx, model) resp.Diagnostics.Append(diags...) if resp.Diagnostics.HasError() { diff --git a/stackit/services/rabbitmq/instance/resource.go b/stackit/services/rabbitmq/instance/resource.go index f005e822d..9ea6ef795 100644 --- a/stackit/services/rabbitmq/instance/resource.go +++ b/stackit/services/rabbitmq/instance/resource.go @@ -279,13 +279,6 @@ func (r *instanceResource) Create(ctx context.Context, req resource.CreateReques return } - // Compute and store values not present in the API response - err = loadPlanNameAndVersion(ctx, r.client, &model) - if err != nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading instance", fmt.Sprintf("Loading service plan details: %v", err)) - return - } - // Set state to fully populated data diags = resp.State.Set(ctx, model) resp.Diagnostics.Append(diags...) @@ -395,13 +388,6 @@ func (r *instanceResource) Update(ctx context.Context, req resource.UpdateReques return } - // Compute and store values not present in the API response - err = loadPlanNameAndVersion(ctx, r.client, &model) - if err != nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading instance", fmt.Sprintf("Loading service plan details: %v", err)) - return - } - diags = resp.State.Set(ctx, model) resp.Diagnostics.Append(diags...) if resp.Diagnostics.HasError() { diff --git a/stackit/services/redis/instance/resource.go b/stackit/services/redis/instance/resource.go index b6b996e3c..abb9959a3 100644 --- a/stackit/services/redis/instance/resource.go +++ b/stackit/services/redis/instance/resource.go @@ -279,13 +279,6 @@ func (r *instanceResource) Create(ctx context.Context, req resource.CreateReques return } - // Compute and store values not present in the API response - err = loadPlanNameAndVersion(ctx, r.client, &model) - if err != nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading instance", fmt.Sprintf("Loading service plan details: %v", err)) - return - } - // Set state to fully populated data diags = resp.State.Set(ctx, model) resp.Diagnostics.Append(diags...) @@ -395,13 +388,6 @@ func (r *instanceResource) Update(ctx context.Context, req resource.UpdateReques return } - // Compute and store values not present in the API response - err = loadPlanNameAndVersion(ctx, r.client, &model) - if err != nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading instance", fmt.Sprintf("Loading service plan details: %v", err)) - return - } - diags = resp.State.Set(ctx, model) resp.Diagnostics.Append(diags...) if resp.Diagnostics.HasError() { From 555163bd181c577837cc644f56cc3d859f666c60 Mon Sep 17 00:00:00 2001 From: Henrique Santos Date: Thu, 21 Sep 2023 13:12:01 +0100 Subject: [PATCH 17/17] Fix wrong description --- docs/data-sources/logme_instance.md | 2 +- stackit/services/logme/instance/datasource.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/data-sources/logme_instance.md b/docs/data-sources/logme_instance.md index 8392835d0..f232f61b4 100644 --- a/docs/data-sources/logme_instance.md +++ b/docs/data-sources/logme_instance.md @@ -33,7 +33,7 @@ data "stackit_logme_instance" "example" { - `cf_organization_guid` (String) - `cf_space_guid` (String) - `dashboard_url` (String) -- `id` (String) Terraform's internal resource identifier. It is structured as "`project_id`,`zone_id`". +- `id` (String) Terraform's internal resource identifier. It is structured as "`project_id`,`instance_id`". - `image_url` (String) - `name` (String) Instance name. - `parameters` (Attributes) (see [below for nested schema](#nestedatt--parameters)) diff --git a/stackit/services/logme/instance/datasource.go b/stackit/services/logme/instance/datasource.go index 6ddc5dbd0..8b360f071 100644 --- a/stackit/services/logme/instance/datasource.go +++ b/stackit/services/logme/instance/datasource.go @@ -75,7 +75,7 @@ func (r *instanceDataSource) Configure(ctx context.Context, req datasource.Confi func (r *instanceDataSource) Schema(_ context.Context, _ datasource.SchemaRequest, resp *datasource.SchemaResponse) { descriptions := map[string]string{ "main": "LogMe instance data source schema.", - "id": "Terraform's internal resource identifier. It is structured as \"`project_id`,`zone_id`\".", + "id": "Terraform's internal resource identifier. It is structured as \"`project_id`,`instance_id`\".", "instance_id": "ID of the LogMe instance.", "project_id": "STACKIT Project ID to which the instance is associated.", "name": "Instance name.",