From 65f53aa5158aeabfa299e21da2b632b6c423ab30 Mon Sep 17 00:00:00 2001 From: Jonas Schlecht Date: Tue, 23 Jun 2026 11:35:01 +0200 Subject: [PATCH 1/4] feat(rabbitmq): update to rabbitmq to v2 API feat(rabbitmq): update to rabbitmq to v2 API --- docs/data-sources/rabbitmq_credential.md | 4 ++ docs/data-sources/rabbitmq_instance.md | 6 +- docs/resources/rabbitmq_credential.md | 1 + docs/resources/rabbitmq_instance.md | 3 +- .../rabbitmq/credential/datasource.go | 21 +++++-- .../services/rabbitmq/credential/resource.go | 48 +++++++++----- .../rabbitmq/credential/resource_test.go | 2 +- .../services/rabbitmq/instance/datasource.go | 25 +++++--- .../services/rabbitmq/instance/resource.go | 63 +++++++++++++------ .../rabbitmq/instance/resource_test.go | 2 +- .../services/rabbitmq/rabbitmq_acc_test.go | 10 +-- .../services/rabbitmq/rabbitmq_test.go | 14 +++-- .../internal/services/rabbitmq/utils/util.go | 24 ++++++- .../services/rabbitmq/utils/util_test.go | 3 +- 14 files changed, 162 insertions(+), 64 deletions(-) diff --git a/docs/data-sources/rabbitmq_credential.md b/docs/data-sources/rabbitmq_credential.md index a95165ad2..ac15184eb 100644 --- a/docs/data-sources/rabbitmq_credential.md +++ b/docs/data-sources/rabbitmq_credential.md @@ -29,6 +29,10 @@ data "stackit_rabbitmq_credential" "example" { - `instance_id` (String) ID of the RabbitMQ instance. - `project_id` (String) STACKIT project ID to which the instance is associated. +### Optional + +- `region` (String) The resource region. If not defined, the provider region is used. + ### Read-Only - `host` (String) diff --git a/docs/data-sources/rabbitmq_instance.md b/docs/data-sources/rabbitmq_instance.md index 9574a5971..03a9ba862 100644 --- a/docs/data-sources/rabbitmq_instance.md +++ b/docs/data-sources/rabbitmq_instance.md @@ -27,13 +27,17 @@ data "stackit_rabbitmq_instance" "example" { - `instance_id` (String) ID of the RabbitMQ instance. - `project_id` (String) STACKIT Project ID to which the instance is associated. +### Optional + +- `region` (String) The resource region. If not defined, the provider region is used. + ### Read-Only - `cf_guid` (String) - `cf_organization_guid` (String) - `cf_space_guid` (String) - `dashboard_url` (String) -- `id` (String) Terraform's internal data source. identifier. It is structured as "`project_id`,`instance_id`". +- `id` (String) Terraform's internal data source. identifier. It is structured as "`project_id`,`region`,`instance_id`". - `image_url` (String) - `name` (String) Instance name. - `parameters` (Attributes) (see [below for nested schema](#nestedatt--parameters)) diff --git a/docs/resources/rabbitmq_credential.md b/docs/resources/rabbitmq_credential.md index 1e68a51e6..fbc7ebde6 100644 --- a/docs/resources/rabbitmq_credential.md +++ b/docs/resources/rabbitmq_credential.md @@ -48,6 +48,7 @@ import { ### Optional +- `region` (String) The resource region. If not defined, the provider region is used. - `rotate_when_changed` (Map of String) A map of arbitrary key/value pairs that will force recreation of the resource when they change, enabling resource rotation based on external conditions such as a rotating timestamp. Changing this forces a new resource to be created. ### Read-Only diff --git a/docs/resources/rabbitmq_instance.md b/docs/resources/rabbitmq_instance.md index b6f03ca23..829256422 100644 --- a/docs/resources/rabbitmq_instance.md +++ b/docs/resources/rabbitmq_instance.md @@ -46,6 +46,7 @@ import { ### Optional - `parameters` (Attributes) Configuration parameters. Please note that removing a previously configured field from your Terraform configuration won't replace its value in the API. To update a previously configured field, explicitly set a new value for it. (see [below for nested schema](#nestedatt--parameters)) +- `region` (String) The resource region. If not defined, the provider region is used. ### Read-Only @@ -53,7 +54,7 @@ import { - `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 ID. It is structured as "`project_id`,`region`,`instance_id`". - `image_url` (String) - `instance_id` (String) ID of the RabbitMQ instance. - `plan_id` (String) The selected plan ID. diff --git a/stackit/internal/services/rabbitmq/credential/datasource.go b/stackit/internal/services/rabbitmq/credential/datasource.go index 0b0c63d0c..21c5492f1 100644 --- a/stackit/internal/services/rabbitmq/credential/datasource.go +++ b/stackit/internal/services/rabbitmq/credential/datasource.go @@ -18,7 +18,7 @@ import ( "github.com/hashicorp/terraform-plugin-framework/datasource/schema" "github.com/hashicorp/terraform-plugin-framework/types" - rabbitmq "github.com/stackitcloud/stackit-sdk-go/services/rabbitmq/v1api" + rabbitmq "github.com/stackitcloud/stackit-sdk-go/services/rabbitmq/v2api" ) // Ensure the implementation satisfies the expected interfaces. @@ -50,7 +50,8 @@ func NewCredentialDataSource() datasource.DataSource { // credentialDataSource is the data source implementation. type credentialDataSource struct { - client *rabbitmq.APIClient + client *rabbitmq.APIClient + providerData core.ProviderData } // Metadata returns the data source type name. @@ -60,12 +61,13 @@ func (r *credentialDataSource) Metadata(_ context.Context, req datasource.Metada // Configure adds the provider configured client to the data source. func (r *credentialDataSource) Configure(ctx context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) { - providerData, ok := conversion.ParseProviderData(ctx, req.ProviderData, &resp.Diagnostics) + var ok bool + r.providerData, ok = conversion.ParseProviderData(ctx, req.ProviderData, &resp.Diagnostics) if !ok { return } - apiClient := rabbitmqUtils.ConfigureClient(ctx, &providerData, &resp.Diagnostics) + apiClient := rabbitmqUtils.ConfigureClient(ctx, &r.providerData, &resp.Diagnostics) if resp.Diagnostics.HasError() { return } @@ -81,6 +83,7 @@ func (r *credentialDataSource) Schema(_ context.Context, _ datasource.SchemaRequ "credential_id": "The credential's ID.", "instance_id": "ID of the RabbitMQ instance.", "project_id": "STACKIT project ID to which the instance is associated.", + "region": "The resource region. If not defined, the provider region is used.", } resp.Schema = schema.Schema{ @@ -149,6 +152,12 @@ func (r *credentialDataSource) Schema(_ context.Context, _ datasource.SchemaRequ "username": schema.StringAttribute{ Computed: true, }, + "region": schema.StringAttribute{ + Optional: true, + // must be computed to allow for storing the override value from the provider + Computed: true, + Description: descriptions["region"], + }, }, } } @@ -165,13 +174,15 @@ func (r *credentialDataSource) Read(ctx context.Context, req datasource.ReadRequ ctx = core.InitProviderContext(ctx) projectId := model.ProjectId.ValueString() + region := r.providerData.GetRegionWithOverride(model.Region) instanceId := model.InstanceId.ValueString() credentialId := model.CredentialId.ValueString() ctx = tflog.SetField(ctx, "project_id", projectId) + ctx = tflog.SetField(ctx, "region", region) ctx = tflog.SetField(ctx, "instance_id", instanceId) ctx = tflog.SetField(ctx, "credential_id", credentialId) - recordSetResp, err := r.client.DefaultAPI.GetCredentials(ctx, projectId, instanceId, credentialId).Execute() + recordSetResp, err := r.client.DefaultAPI.GetCredentials(ctx, projectId, region, instanceId, credentialId).Execute() if err != nil { utils.LogError( ctx, diff --git a/stackit/internal/services/rabbitmq/credential/resource.go b/stackit/internal/services/rabbitmq/credential/resource.go index 9f21f001f..279a4c122 100644 --- a/stackit/internal/services/rabbitmq/credential/resource.go +++ b/stackit/internal/services/rabbitmq/credential/resource.go @@ -25,8 +25,8 @@ import ( "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier" "github.com/hashicorp/terraform-plugin-framework/types" "github.com/stackitcloud/stackit-sdk-go/core/oapierror" - rabbitmq "github.com/stackitcloud/stackit-sdk-go/services/rabbitmq/v1api" - "github.com/stackitcloud/stackit-sdk-go/services/rabbitmq/v1api/wait" + rabbitmq "github.com/stackitcloud/stackit-sdk-go/services/rabbitmq/v2api" + "github.com/stackitcloud/stackit-sdk-go/services/rabbitmq/v2api/wait" ) // Ensure the implementation satisfies the expected interfaces. @@ -41,6 +41,7 @@ type Model struct { CredentialId types.String `tfsdk:"credential_id"` InstanceId types.String `tfsdk:"instance_id"` ProjectId types.String `tfsdk:"project_id"` + Region types.String `tfsdk:"region"` Host types.String `tfsdk:"host"` Hosts types.List `tfsdk:"hosts"` HttpAPIURI types.String `tfsdk:"http_api_uri"` @@ -65,7 +66,8 @@ func NewCredentialResource() resource.Resource { // credentialResource is the resource implementation. type credentialResource struct { - client *rabbitmq.APIClient + client *rabbitmq.APIClient + providerData core.ProviderData } // Metadata returns the resource type name. @@ -75,12 +77,13 @@ func (r *credentialResource) Metadata(_ context.Context, req resource.MetadataRe // Configure adds the provider configured client to the resource. func (r *credentialResource) Configure(ctx context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { - providerData, ok := conversion.ParseProviderData(ctx, req.ProviderData, &resp.Diagnostics) + var ok bool + r.providerData, ok = conversion.ParseProviderData(ctx, req.ProviderData, &resp.Diagnostics) if !ok { return } - apiClient := rabbitmqUtils.ConfigureClient(ctx, &providerData, &resp.Diagnostics) + apiClient := rabbitmqUtils.ConfigureClient(ctx, &r.providerData, &resp.Diagnostics) if resp.Diagnostics.HasError() { return } @@ -96,6 +99,7 @@ func (r *credentialResource) Schema(_ context.Context, _ resource.SchemaRequest, "credential_id": "The credential's ID.", "instance_id": "ID of the RabbitMQ instance.", "project_id": "STACKIT Project ID to which the instance is associated.", + "region": "The resource region. If not defined, the provider region is used.", } resp.Schema = schema.Schema{ @@ -190,6 +194,15 @@ func (r *credentialResource) Schema(_ context.Context, _ resource.SchemaRequest, mapplanmodifier.RequiresReplace(), }, }, + "region": schema.StringAttribute{ + Optional: true, + // must be computed to allow for storing the override value from the provider + Computed: true, + Description: descriptions["region"], + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), + }, + }, }, } } @@ -207,11 +220,13 @@ func (r *credentialResource) Create(ctx context.Context, req resource.CreateRequ projectId := model.ProjectId.ValueString() instanceId := model.InstanceId.ValueString() + region := r.providerData.GetRegionWithOverride(model.Region) ctx = tflog.SetField(ctx, "project_id", projectId) ctx = tflog.SetField(ctx, "instance_id", instanceId) + ctx = tflog.SetField(ctx, "region", region) // Create new recordset - credentialsResp, err := r.client.DefaultAPI.CreateCredentials(ctx, projectId, instanceId).Execute() + credentialsResp, err := r.client.DefaultAPI.CreateCredentials(ctx, projectId, instanceId, region).Execute() if err != nil { core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating credential", fmt.Sprintf("Calling API: %v", err)) return @@ -226,6 +241,7 @@ func (r *credentialResource) Create(ctx context.Context, req resource.CreateRequ credentialId := credentialsResp.Id ctx = utils.SetAndLogStateFields(ctx, &resp.Diagnostics, &resp.State, map[string]any{ "project_id": projectId, + "region": region, "instance_id": instanceId, "credential_id": credentialId, }) @@ -233,7 +249,7 @@ func (r *credentialResource) Create(ctx context.Context, req resource.CreateRequ return } - waitResp, err := wait.CreateCredentialsWaitHandler(ctx, r.client.DefaultAPI, projectId, instanceId, credentialId).WaitWithContext(ctx) + waitResp, err := wait.CreateCredentialsWaitHandler(ctx, r.client.DefaultAPI, projectId, region, instanceId, credentialId).WaitWithContext(ctx) if err != nil { core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating credential", fmt.Sprintf("Instance creation waiting: %v", err)) return @@ -265,6 +281,7 @@ func (r *credentialResource) Read(ctx context.Context, req resource.ReadRequest, ctx = core.InitProviderContext(ctx) projectId := model.ProjectId.ValueString() + region := r.providerData.GetRegionWithOverride(model.Region) instanceId := model.InstanceId.ValueString() credentialId := model.CredentialId.ValueString() if credentialId == "" { @@ -273,10 +290,11 @@ func (r *credentialResource) Read(ctx context.Context, req resource.ReadRequest, return } ctx = tflog.SetField(ctx, "project_id", projectId) + ctx = tflog.SetField(ctx, "region", region) ctx = tflog.SetField(ctx, "instance_id", instanceId) ctx = tflog.SetField(ctx, "credential_id", credentialId) - recordSetResp, err := r.client.DefaultAPI.GetCredentials(ctx, projectId, instanceId, credentialId).Execute() + recordSetResp, err := r.client.DefaultAPI.GetCredentials(ctx, projectId, region, instanceId, credentialId).Execute() if err != nil { var oapiErr *oapierror.GenericOpenAPIError if errors.As(err, &oapiErr) && oapiErr.StatusCode == http.StatusNotFound { @@ -323,14 +341,16 @@ func (r *credentialResource) Delete(ctx context.Context, req resource.DeleteRequ ctx = core.InitProviderContext(ctx) projectId := model.ProjectId.ValueString() + region := r.providerData.GetRegionWithOverride(model.Region) instanceId := model.InstanceId.ValueString() credentialId := model.CredentialId.ValueString() ctx = tflog.SetField(ctx, "project_id", projectId) + ctx = tflog.SetField(ctx, "region", region) ctx = tflog.SetField(ctx, "instance_id", instanceId) ctx = tflog.SetField(ctx, "credential_id", credentialId) // Delete existing record set - err := r.client.DefaultAPI.DeleteCredentials(ctx, projectId, instanceId, credentialId).Execute() + err := r.client.DefaultAPI.DeleteCredentials(ctx, projectId, region, instanceId, credentialId).Execute() if err != nil { var oapiErr *oapierror.GenericOpenAPIError if errors.As(err, &oapiErr) && oapiErr.StatusCode == http.StatusNotFound { @@ -342,7 +362,7 @@ func (r *credentialResource) Delete(ctx context.Context, req resource.DeleteRequ ctx = core.LogResponse(ctx) - _, err = wait.DeleteCredentialsWaitHandler(ctx, r.client.DefaultAPI, projectId, instanceId, credentialId).WaitWithContext(ctx) + _, err = wait.DeleteCredentialsWaitHandler(ctx, r.client.DefaultAPI, projectId, region, instanceId, credentialId).WaitWithContext(ctx) if err != nil { core.LogAndAddError(ctx, &resp.Diagnostics, "Error deleting credential", fmt.Sprintf("Instance deletion waiting: %v", err)) return @@ -351,7 +371,7 @@ func (r *credentialResource) Delete(ctx context.Context, req resource.DeleteRequ } // ImportState imports a resource into the Terraform state on success. -// The expected format of the resource import identifier is: project_id,instance_id,credential_id +// The expected format of the resource import identifier is: project_id,region,instance_id,credential_id func (r *credentialResource) 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] == "" { @@ -361,11 +381,11 @@ func (r *credentialResource) ImportState(ctx context.Context, req resource.Impor ) return } - ctx = utils.SetAndLogStateFields(ctx, &resp.Diagnostics, &resp.State, map[string]any{ "project_id": idParts[0], - "instance_id": idParts[1], - "credential_id": idParts[2], + "region": idParts[1], + "instance_id": idParts[2], + "credential_id": idParts[3], }) if resp.Diagnostics.HasError() { return diff --git a/stackit/internal/services/rabbitmq/credential/resource_test.go b/stackit/internal/services/rabbitmq/credential/resource_test.go index c0b891759..6027062b2 100644 --- a/stackit/internal/services/rabbitmq/credential/resource_test.go +++ b/stackit/internal/services/rabbitmq/credential/resource_test.go @@ -7,7 +7,7 @@ import ( "github.com/google/go-cmp/cmp" "github.com/hashicorp/terraform-plugin-framework/attr" "github.com/hashicorp/terraform-plugin-framework/types" - rabbitmq "github.com/stackitcloud/stackit-sdk-go/services/rabbitmq/v1api" + rabbitmq "github.com/stackitcloud/stackit-sdk-go/services/rabbitmq/v2api" ) func TestMapFields(t *testing.T) { diff --git a/stackit/internal/services/rabbitmq/instance/datasource.go b/stackit/internal/services/rabbitmq/instance/datasource.go index 7f74707f3..7fc1f041c 100644 --- a/stackit/internal/services/rabbitmq/instance/datasource.go +++ b/stackit/internal/services/rabbitmq/instance/datasource.go @@ -18,7 +18,7 @@ import ( "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/validate" "github.com/hashicorp/terraform-plugin-framework/datasource/schema" - rabbitmq "github.com/stackitcloud/stackit-sdk-go/services/rabbitmq/v1api" + rabbitmq "github.com/stackitcloud/stackit-sdk-go/services/rabbitmq/v2api" ) // Ensure the implementation satisfies the expected interfaces. @@ -33,7 +33,8 @@ func NewInstanceDataSource() datasource.DataSource { // instanceDataSource is the data source implementation. type instanceDataSource struct { - client *rabbitmq.APIClient + client *rabbitmq.APIClient + providerData core.ProviderData } // Metadata returns the data source type name. @@ -43,12 +44,13 @@ func (r *instanceDataSource) Metadata(_ context.Context, req datasource.Metadata // Configure adds the provider configured client to the data source. func (r *instanceDataSource) Configure(ctx context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) { - providerData, ok := conversion.ParseProviderData(ctx, req.ProviderData, &resp.Diagnostics) + var ok bool + r.providerData, ok = conversion.ParseProviderData(ctx, req.ProviderData, &resp.Diagnostics) if !ok { return } - apiClient := rabbitmqUtils.ConfigureClient(ctx, &providerData, &resp.Diagnostics) + apiClient := rabbitmqUtils.ConfigureClient(ctx, &r.providerData, &resp.Diagnostics) if resp.Diagnostics.HasError() { return } @@ -60,13 +62,14 @@ 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. Must have a `region` specified in the provider configuration.", - "id": "Terraform's internal data source. identifier. It is structured as \"`project_id`,`instance_id`\".", + "id": "Terraform's internal data source. identifier. It is structured as \"`project_id`,`region`,`instance_id`\".", "instance_id": "ID of the RabbitMQ instance.", "project_id": "STACKIT Project ID to which the instance is associated.", "name": "Instance name.", "version": "The service version.", "plan_name": "The selected plan name.", "plan_id": "The selected plan ID.", + "region": "The resource region. If not defined, the provider region is used.", } parametersDescriptions := map[string]string{ @@ -201,6 +204,12 @@ func (r *instanceDataSource) Schema(_ context.Context, _ datasource.SchemaReques "cf_organization_guid": schema.StringAttribute{ Computed: true, }, + "region": schema.StringAttribute{ + Optional: true, + // must be computed to allow for storing the override value from the provider + Computed: true, + Description: descriptions["region"], + }, }, } } @@ -218,10 +227,12 @@ func (r *instanceDataSource) Read(ctx context.Context, req datasource.ReadReques projectId := model.ProjectId.ValueString() instanceId := model.InstanceId.ValueString() + region := r.providerData.GetRegionWithOverride(model.Region) ctx = tflog.SetField(ctx, "project_id", projectId) ctx = tflog.SetField(ctx, "instance_id", instanceId) + ctx = tflog.SetField(ctx, "region", region) - instanceResp, err := r.client.DefaultAPI.GetInstance(ctx, projectId, instanceId).Execute() + instanceResp, err := r.client.DefaultAPI.GetInstance(ctx, projectId, instanceId, region).Execute() if err != nil { utils.LogError( ctx, @@ -246,7 +257,7 @@ func (r *instanceDataSource) Read(ctx context.Context, req datasource.ReadReques } // Compute and store values not present in the API response - err = loadPlanNameAndVersion(ctx, r.client, &model) + err = loadPlanNameAndVersion(ctx, r.client, &model, region) if err != nil { core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading instance", fmt.Sprintf("Loading service plan details: %v", err)) return diff --git a/stackit/internal/services/rabbitmq/instance/resource.go b/stackit/internal/services/rabbitmq/instance/resource.go index 2654423ab..813aa5189 100644 --- a/stackit/internal/services/rabbitmq/instance/resource.go +++ b/stackit/internal/services/rabbitmq/instance/resource.go @@ -27,8 +27,8 @@ import ( "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier" "github.com/hashicorp/terraform-plugin-framework/types" "github.com/stackitcloud/stackit-sdk-go/core/oapierror" - rabbitmq "github.com/stackitcloud/stackit-sdk-go/services/rabbitmq/v1api" - "github.com/stackitcloud/stackit-sdk-go/services/rabbitmq/v1api/wait" + rabbitmq "github.com/stackitcloud/stackit-sdk-go/services/rabbitmq/v2api" + "github.com/stackitcloud/stackit-sdk-go/services/rabbitmq/v2api/wait" ) // Ensure the implementation satisfies the expected interfaces. @@ -42,6 +42,7 @@ type Model struct { Id types.String `tfsdk:"id"` // needed by TF InstanceId types.String `tfsdk:"instance_id"` ProjectId types.String `tfsdk:"project_id"` + Region types.String `tfsdk:"region"` CfGuid types.String `tfsdk:"cf_guid"` CfSpaceGuid types.String `tfsdk:"cf_space_guid"` DashboardUrl types.String `tfsdk:"dashboard_url"` @@ -95,7 +96,8 @@ func NewInstanceResource() resource.Resource { // instanceResource is the resource implementation. type instanceResource struct { - client *rabbitmq.APIClient + client *rabbitmq.APIClient + providerData core.ProviderData } // Metadata returns the resource type name. @@ -105,12 +107,13 @@ func (r *instanceResource) Metadata(_ context.Context, req resource.MetadataRequ // Configure adds the provider configured client to the resource. func (r *instanceResource) Configure(ctx context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { - providerData, ok := conversion.ParseProviderData(ctx, req.ProviderData, &resp.Diagnostics) + var ok bool + r.providerData, ok = conversion.ParseProviderData(ctx, req.ProviderData, &resp.Diagnostics) if !ok { return } - apiClient := rabbitmqUtils.ConfigureClient(ctx, &providerData, &resp.Diagnostics) + apiClient := rabbitmqUtils.ConfigureClient(ctx, &r.providerData, &resp.Diagnostics) if resp.Diagnostics.HasError() { return } @@ -122,7 +125,7 @@ func (r *instanceResource) Configure(ctx context.Context, req resource.Configure func (r *instanceResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) { descriptions := map[string]string{ "main": "RabbitMQ instance resource schema. Must have a `region` specified in the provider configuration.", - "id": "Terraform's internal resource ID. It is structured as \"`project_id`,`instance_id`\".", + "id": "Terraform's internal resource ID. It is structured as \"`project_id`,`region`,`instance_id`\".", "instance_id": "ID of the RabbitMQ instance.", "project_id": "STACKIT project ID to which the instance is associated.", "name": "Instance name.", @@ -130,6 +133,7 @@ func (r *instanceResource) Schema(_ context.Context, _ resource.SchemaRequest, r "plan_name": "The selected plan name.", "plan_id": "The selected plan ID.", "parameters": "Configuration parameters. Please note that removing a previously configured field from your Terraform configuration won't replace its value in the API. To update a previously configured field, explicitly set a new value for it.", + "region": "The resource region. If not defined, the provider region is used.", } parametersDescriptions := map[string]string{ @@ -315,6 +319,15 @@ func (r *instanceResource) Schema(_ context.Context, _ resource.SchemaRequest, r stringplanmodifier.UseStateForUnknown(), }, }, + "region": schema.StringAttribute{ + Optional: true, + // must be computed to allow for storing the override value from the provider + Computed: true, + Description: descriptions["region"], + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), + }, + }, }, } } @@ -331,7 +344,9 @@ func (r *instanceResource) Create(ctx context.Context, req resource.CreateReques ctx = core.InitProviderContext(ctx) projectId := model.ProjectId.ValueString() + region := r.providerData.GetRegionWithOverride(model.Region) ctx = tflog.SetField(ctx, "project_id", projectId) + ctx = tflog.SetField(ctx, "region", region) var parameters *parametersModel if !(model.Parameters.IsNull() || model.Parameters.IsUnknown()) { @@ -356,7 +371,7 @@ func (r *instanceResource) Create(ctx context.Context, req resource.CreateReques return } // Create new instance - createResp, err := r.client.DefaultAPI.CreateInstance(ctx, projectId).CreateInstancePayload(*payload).Execute() + createResp, err := r.client.DefaultAPI.CreateInstance(ctx, projectId, region).CreateInstancePayload(*payload).Execute() if err != nil { core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating instance", fmt.Sprintf("Calling API: %v", err)) return @@ -373,12 +388,13 @@ func (r *instanceResource) Create(ctx context.Context, req resource.CreateReques ctx = utils.SetAndLogStateFields(ctx, &resp.Diagnostics, &resp.State, map[string]any{ "project_id": projectId, "instance_id": instanceId, + "region": region, }) if resp.Diagnostics.HasError() { return } - waitResp, err := wait.CreateInstanceWaitHandler(ctx, r.client.DefaultAPI, projectId, instanceId).WaitWithContext(ctx) + waitResp, err := wait.CreateInstanceWaitHandler(ctx, r.client.DefaultAPI, projectId, instanceId, region).WaitWithContext(ctx) if err != nil { core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating instance", fmt.Sprintf("Instance creation waiting: %v", err)) return @@ -418,10 +434,13 @@ func (r *instanceResource) Read(ctx context.Context, req resource.ReadRequest, r resp.State.RemoveResource(ctx) return } + region := r.providerData.GetRegionWithOverride(model.Region) + ctx = tflog.SetField(ctx, "project_id", projectId) ctx = tflog.SetField(ctx, "instance_id", instanceId) + ctx = tflog.SetField(ctx, "region", region) - instanceResp, err := r.client.DefaultAPI.GetInstance(ctx, projectId, instanceId).Execute() + instanceResp, err := r.client.DefaultAPI.GetInstance(ctx, projectId, region, instanceId).Execute() if err != nil { var oapiErr *oapierror.GenericOpenAPIError if errors.As(err, &oapiErr) && (oapiErr.StatusCode == http.StatusNotFound || oapiErr.StatusCode == http.StatusGone) { @@ -442,7 +461,7 @@ func (r *instanceResource) Read(ctx context.Context, req resource.ReadRequest, r } // Compute and store values not present in the API response - err = loadPlanNameAndVersion(ctx, r.client, &model) + err = loadPlanNameAndVersion(ctx, r.client, &model, region) if err != nil { core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading instance", fmt.Sprintf("Loading service plan details: %v", err)) return @@ -470,8 +489,10 @@ func (r *instanceResource) Update(ctx context.Context, req resource.UpdateReques projectId := model.ProjectId.ValueString() instanceId := model.InstanceId.ValueString() + region := r.providerData.GetRegionWithOverride(model.Region) ctx = tflog.SetField(ctx, "project_id", projectId) ctx = tflog.SetField(ctx, "instance_id", instanceId) + ctx = tflog.SetField(ctx, "region", region) var parameters *parametersModel if !(model.Parameters.IsNull() || model.Parameters.IsUnknown()) { @@ -496,7 +517,7 @@ func (r *instanceResource) Update(ctx context.Context, req resource.UpdateReques return } // Update existing instance - err = r.client.DefaultAPI.PartialUpdateInstance(ctx, projectId, instanceId).PartialUpdateInstancePayload(*payload).Execute() + err = r.client.DefaultAPI.PartialUpdateInstance(ctx, projectId, instanceId, region).PartialUpdateInstancePayload(*payload).Execute() if err != nil { core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating instance", fmt.Sprintf("Calling API: %v", err)) return @@ -504,7 +525,7 @@ func (r *instanceResource) Update(ctx context.Context, req resource.UpdateReques ctx = core.LogResponse(ctx) - waitResp, err := wait.PartialUpdateInstanceWaitHandler(ctx, r.client.DefaultAPI, projectId, instanceId).WaitWithContext(ctx) + waitResp, err := wait.PartialUpdateInstanceWaitHandler(ctx, r.client.DefaultAPI, projectId, instanceId, region).WaitWithContext(ctx) if err != nil { core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating instance", fmt.Sprintf("Instance update waiting: %v", err)) return @@ -539,11 +560,13 @@ func (r *instanceResource) Delete(ctx context.Context, req resource.DeleteReques projectId := model.ProjectId.ValueString() instanceId := model.InstanceId.ValueString() + region := r.providerData.GetRegionWithOverride(model.Region) ctx = tflog.SetField(ctx, "project_id", projectId) ctx = tflog.SetField(ctx, "instance_id", instanceId) + ctx = tflog.SetField(ctx, "region", region) // Delete existing instance - err := r.client.DefaultAPI.DeleteInstance(ctx, projectId, instanceId).Execute() + err := r.client.DefaultAPI.DeleteInstance(ctx, projectId, instanceId, region).Execute() if err != nil { var oapiErr *oapierror.GenericOpenAPIError if errors.As(err, &oapiErr) && oapiErr.StatusCode == http.StatusNotFound { @@ -556,7 +579,7 @@ func (r *instanceResource) Delete(ctx context.Context, req resource.DeleteReques ctx = core.LogResponse(ctx) - _, err = wait.DeleteInstanceWaitHandler(ctx, r.client.DefaultAPI, projectId, instanceId).WaitWithContext(ctx) + _, err = wait.DeleteInstanceWaitHandler(ctx, r.client.DefaultAPI, projectId, instanceId, region).WaitWithContext(ctx) if err != nil { core.LogAndAddError(ctx, &resp.Diagnostics, "Error deleting instance", fmt.Sprintf("Instance deletion waiting: %v", err)) return @@ -565,7 +588,7 @@ func (r *instanceResource) Delete(ctx context.Context, req resource.DeleteReques } // ImportState imports a resource into the Terraform state on success. -// The expected format of the resource import identifier is: project_id,instance_id +// The expected format of the resource import identifier is: project_id,region,instance_id func (r *instanceResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { idParts := strings.Split(req.ID, core.Separator) @@ -579,7 +602,8 @@ func (r *instanceResource) ImportState(ctx context.Context, req resource.ImportS ctx = utils.SetAndLogStateFields(ctx, &resp.Diagnostics, &resp.State, map[string]any{ "project_id": idParts[0], - "instance_id": idParts[1], + "region": idParts[1], + "instance_id": idParts[2], }) if resp.Diagnostics.HasError() { return @@ -806,7 +830,8 @@ func toInstanceParams(parameters *parametersModel) (*rabbitmq.InstanceParameters func (r *instanceResource) loadPlanId(ctx context.Context, model *Model) error { projectId := model.ProjectId.ValueString() - res, err := r.client.DefaultAPI.ListOfferings(ctx, projectId).Execute() + region := r.providerData.GetRegionWithOverride(model.Region) + res, err := r.client.DefaultAPI.ListOfferings(ctx, projectId, region).Execute() if err != nil { return fmt.Errorf("getting RabbitMQ offerings: %w", err) } @@ -841,10 +866,10 @@ func (r *instanceResource) loadPlanId(ctx context.Context, model *Model) error { 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, model *Model) error { +func loadPlanNameAndVersion(ctx context.Context, client *rabbitmq.APIClient, model *Model, region string) error { projectId := model.ProjectId.ValueString() planId := model.PlanId.ValueString() - res, err := client.DefaultAPI.ListOfferings(ctx, projectId).Execute() + res, err := client.DefaultAPI.ListOfferings(ctx, projectId, region).Execute() if err != nil { return fmt.Errorf("getting RabbitMQ offerings: %w", err) } diff --git a/stackit/internal/services/rabbitmq/instance/resource_test.go b/stackit/internal/services/rabbitmq/instance/resource_test.go index 6242ad249..b609b04da 100644 --- a/stackit/internal/services/rabbitmq/instance/resource_test.go +++ b/stackit/internal/services/rabbitmq/instance/resource_test.go @@ -8,7 +8,7 @@ import ( "github.com/hashicorp/terraform-plugin-framework/attr" "github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-plugin-framework/types/basetypes" - rabbitmq "github.com/stackitcloud/stackit-sdk-go/services/rabbitmq/v1api" + rabbitmq "github.com/stackitcloud/stackit-sdk-go/services/rabbitmq/v2api" ) var fixtureModelParameters = types.ObjectValueMust(parametersTypes, map[string]attr.Value{ diff --git a/stackit/internal/services/rabbitmq/rabbitmq_acc_test.go b/stackit/internal/services/rabbitmq/rabbitmq_acc_test.go index 089736beb..241c87fb9 100644 --- a/stackit/internal/services/rabbitmq/rabbitmq_acc_test.go +++ b/stackit/internal/services/rabbitmq/rabbitmq_acc_test.go @@ -10,8 +10,8 @@ import ( "github.com/hashicorp/terraform-plugin-testing/helper/resource" "github.com/hashicorp/terraform-plugin-testing/terraform" "github.com/stackitcloud/stackit-sdk-go/core/utils" - rabbitmq "github.com/stackitcloud/stackit-sdk-go/services/rabbitmq/v1api" - "github.com/stackitcloud/stackit-sdk-go/services/rabbitmq/v1api/wait" + rabbitmq "github.com/stackitcloud/stackit-sdk-go/services/rabbitmq/v2api" + "github.com/stackitcloud/stackit-sdk-go/services/rabbitmq/v2api/wait" "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/core" "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/testutil" @@ -261,7 +261,7 @@ func testAccCheckRabbitMQDestroy(s *terraform.State) error { instancesToDestroy = append(instancesToDestroy, instanceId) } - instancesResp, err := client.DefaultAPI.ListInstances(ctx, testutil.ProjectId).Execute() + instancesResp, err := client.DefaultAPI.ListInstances(ctx, testutil.ProjectId, testutil.Region).Execute() if err != nil { return fmt.Errorf("getting instancesResp: %w", err) } @@ -273,11 +273,11 @@ func testAccCheckRabbitMQDestroy(s *terraform.State) error { } if utils.Contains(instancesToDestroy, *instances[i].InstanceId) { if !checkInstanceDeleteSuccess(&instances[i]) { - err := client.DefaultAPI.DeleteInstance(ctx, testutil.ProjectId, *instances[i].InstanceId).Execute() + err := client.DefaultAPI.DeleteInstance(ctx, testutil.ProjectId, testutil.Region, *instances[i].InstanceId).Execute() if err != nil { return fmt.Errorf("destroying instance %s during CheckDestroy: %w", *instances[i].InstanceId, err) } - _, err = wait.DeleteInstanceWaitHandler(ctx, client.DefaultAPI, testutil.ProjectId, *instances[i].InstanceId).WaitWithContext(ctx) + _, err = wait.DeleteInstanceWaitHandler(ctx, client.DefaultAPI, testutil.ProjectId, testutil.Region, *instances[i].InstanceId).WaitWithContext(ctx) if err != nil { return fmt.Errorf("destroying instance %s during CheckDestroy: waiting for deletion %w", *instances[i].InstanceId, err) } diff --git a/stackit/internal/services/rabbitmq/rabbitmq_test.go b/stackit/internal/services/rabbitmq/rabbitmq_test.go index 4851c2aef..e2b5a087a 100644 --- a/stackit/internal/services/rabbitmq/rabbitmq_test.go +++ b/stackit/internal/services/rabbitmq/rabbitmq_test.go @@ -8,7 +8,7 @@ import ( "github.com/google/uuid" "github.com/hashicorp/terraform-plugin-testing/helper/resource" - rabbitmq "github.com/stackitcloud/stackit-sdk-go/services/rabbitmq/v1api" + rabbitmq "github.com/stackitcloud/stackit-sdk-go/services/rabbitmq/v2api" "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/testutil" ) @@ -21,6 +21,7 @@ func TestRabbitMQInstanceSavesIDsOnError(t *testing.T) { planName = "plan-name" planId = "plan-id" version = "version" + region = "eu01" ) s := testutil.NewMockServer(t) defer s.Server.Close() @@ -35,8 +36,9 @@ resource "stackit_rabbitmq_instance" "instance" { name = "%s" plan_name = "%s" version = "%s" + region = "%s" } -`, s.Server.URL, projectId, name, planName, version) +`, s.Server.URL, projectId, name, planName, version, region) offerings := testutil.MockResponse{ ToJsonBody: &rabbitmq.ListOfferingsResponse{ Offerings: []rabbitmq.Offering{ @@ -77,7 +79,7 @@ resource "stackit_rabbitmq_instance" "instance" { testutil.MockResponse{ Description: "refresh", Handler: func(w http.ResponseWriter, req *http.Request) { - expected := fmt.Sprintf("/v1/projects/%s/instances/%s", projectId, instanceId) + expected := fmt.Sprintf("/v2/projects/%s/regions/%s/instances/%s", projectId, region, instanceId) if req.URL.Path != expected { t.Errorf("expected request to %s, got %s", expected, req.URL.Path) } @@ -100,6 +102,7 @@ func TestRabbitMQCredentialsSavesIDsOnError(t *testing.T) { projectId = uuid.NewString() instanceId = uuid.NewString() credentialId = uuid.NewString() + region = "eu01" ) s := testutil.NewMockServer(t) t.Cleanup(s.Server.Close) @@ -111,9 +114,10 @@ provider "stackit" { resource "stackit_rabbitmq_credential" "credential" { project_id = "%s" + region = "%s" instance_id = "%s" } -`, s.Server.URL, projectId, instanceId) +`, s.Server.URL, projectId, region, instanceId) resource.UnitTest(t, resource.TestCase{ ProtoV6ProviderFactories: testutil.TestAccProtoV6ProviderFactories, Steps: []resource.TestStep{ @@ -139,7 +143,7 @@ resource "stackit_rabbitmq_credential" "credential" { testutil.MockResponse{ Description: "refresh", Handler: func(w http.ResponseWriter, req *http.Request) { - expected := fmt.Sprintf("/v1/projects/%s/instances/%s/credentials/%s", projectId, instanceId, credentialId) + expected := fmt.Sprintf("/v2/projects/%s/regions/%s/instances/%s/credentials/%s", projectId, region, instanceId, credentialId) if req.URL.Path != expected { t.Errorf("expected request to %s, got %s", expected, req.URL.Path) } diff --git a/stackit/internal/services/rabbitmq/utils/util.go b/stackit/internal/services/rabbitmq/utils/util.go index 07c1b7ee6..72d40dc2a 100644 --- a/stackit/internal/services/rabbitmq/utils/util.go +++ b/stackit/internal/services/rabbitmq/utils/util.go @@ -6,7 +6,7 @@ import ( "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/stackitcloud/stackit-sdk-go/core/config" - rabbitmq "github.com/stackitcloud/stackit-sdk-go/services/rabbitmq/v1api" + rabbitmq "github.com/stackitcloud/stackit-sdk-go/services/rabbitmq/v2api" "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/core" "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/utils" @@ -19,8 +19,6 @@ func ConfigureClient(ctx context.Context, providerData *core.ProviderData, diags } if providerData.RabbitMQCustomEndpoint != "" { apiClientConfigOptions = append(apiClientConfigOptions, config.WithEndpoint(providerData.RabbitMQCustomEndpoint)) - } else { - apiClientConfigOptions = append(apiClientConfigOptions, config.WithRegion(providerData.GetRegion())) } apiClient, err := rabbitmq.NewAPIClient(apiClientConfigOptions...) if err != nil { @@ -30,3 +28,23 @@ func ConfigureClient(ctx context.Context, providerData *core.ProviderData, diags return apiClient } + +// StringSliceToInstanceParametersPluginsInner takes a string slice and converts it to rabbitmq.InstanceParamtersPluginsInner. +func StringSliceToInstanceParametersPluginsInner(s []string) []rabbitmq.InstanceParametersPluginsInner { + result := make([]rabbitmq.InstanceParametersPluginsInner, len(s)) + for i, element := range s { + result[i] = rabbitmq.InstanceParametersPluginsInner(element) + } + + return result +} + +// StringSliceToInstanceParametersTlsProtocolsInner takes a string slice and converts it to rabbitmq.InstanceParametersTlsProtocolsInner. +func StringSliceToInstanceParametersTlsProtocolsInner(s []string) []rabbitmq.InstanceParametersTlsProtocolsInner { + result := make([]rabbitmq.InstanceParametersTlsProtocolsInner, len(s)) + for i, element := range s { + result[i] = rabbitmq.InstanceParametersTlsProtocolsInner(element) + } + + return result +} diff --git a/stackit/internal/services/rabbitmq/utils/util_test.go b/stackit/internal/services/rabbitmq/utils/util_test.go index ee2227199..401f4db87 100644 --- a/stackit/internal/services/rabbitmq/utils/util_test.go +++ b/stackit/internal/services/rabbitmq/utils/util_test.go @@ -9,7 +9,7 @@ import ( "github.com/hashicorp/terraform-plugin-framework/diag" sdkClients "github.com/stackitcloud/stackit-sdk-go/core/clients" "github.com/stackitcloud/stackit-sdk-go/core/config" - rabbitmq "github.com/stackitcloud/stackit-sdk-go/services/rabbitmq/v1api" + rabbitmq "github.com/stackitcloud/stackit-sdk-go/services/rabbitmq/v2api" "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/core" "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/utils" @@ -46,7 +46,6 @@ func TestConfigureClient(t *testing.T) { }, expected: func() *rabbitmq.APIClient { apiClient, err := rabbitmq.NewAPIClient( - config.WithRegion("eu01"), utils.UserAgentConfigOption(testVersion), ) if err != nil { From 9efb71bc1e4d5371235edfb519457a41d5c19238 Mon Sep 17 00:00:00 2001 From: Jonas Schlecht Date: Mon, 29 Jun 2026 14:13:11 +0200 Subject: [PATCH 2/4] feat(rabbitmq): fix terraform id for rabbitmq ressource --- go.mod | 2 +- go.sum | 4 ++-- .../services/rabbitmq/credential/datasource.go | 10 ++++++---- .../rabbitmq/credential/datasource_test.go | 18 ++++++++++++------ .../services/rabbitmq/credential/resource.go | 11 ++++++----- .../rabbitmq/credential/resource_test.go | 16 +++++++++++----- .../services/rabbitmq/instance/datasource.go | 2 +- .../services/rabbitmq/instance/resource.go | 11 ++++++----- .../rabbitmq/instance/resource_test.go | 10 +++++++--- 9 files changed, 52 insertions(+), 32 deletions(-) diff --git a/go.mod b/go.mod index 2339c9453..41de5ba70 100644 --- a/go.mod +++ b/go.mod @@ -33,7 +33,7 @@ require ( github.com/stackitcloud/stackit-sdk-go/services/observability v0.24.0 github.com/stackitcloud/stackit-sdk-go/services/opensearch v1.0.0 github.com/stackitcloud/stackit-sdk-go/services/postgresflex v1.10.0 - github.com/stackitcloud/stackit-sdk-go/services/rabbitmq v1.0.0 + github.com/stackitcloud/stackit-sdk-go/services/rabbitmq v1.1.0 github.com/stackitcloud/stackit-sdk-go/services/redis v1.0.0 github.com/stackitcloud/stackit-sdk-go/services/resourcemanager v0.24.0 github.com/stackitcloud/stackit-sdk-go/services/scf v0.9.0 diff --git a/go.sum b/go.sum index 99763d1c5..cffb46575 100644 --- a/go.sum +++ b/go.sum @@ -712,8 +712,8 @@ github.com/stackitcloud/stackit-sdk-go/services/opensearch v1.0.0 h1:xJ/rhcMTV2p github.com/stackitcloud/stackit-sdk-go/services/opensearch v1.0.0/go.mod h1:L+NlfC1hilLOqlLLukCj/UDnxlnNrc/oMikcw3Ansyw= github.com/stackitcloud/stackit-sdk-go/services/postgresflex v1.10.0 h1:Ia8FWqG14hkl7rWAUDjSKwd+8NPvrPGOpUC0jLB1sR0= github.com/stackitcloud/stackit-sdk-go/services/postgresflex v1.10.0/go.mod h1:yzlakB+f8ur4yAHR6lyCABO+HcEtZG3G2Faj6m5/uW8= -github.com/stackitcloud/stackit-sdk-go/services/rabbitmq v1.0.0 h1:kHdXzMcYPLRwidoQuNu1U12PmqCBNqpTS+U82rB9HtY= -github.com/stackitcloud/stackit-sdk-go/services/rabbitmq v1.0.0/go.mod h1:TwfVVynB/+AKbccSOLk2qZpPL1tdK43BBAiACP6EtSg= +github.com/stackitcloud/stackit-sdk-go/services/rabbitmq v1.1.0 h1:HRJwodJX4aOn/487zaqJIKw13yIj4T6dn7/kEHLxeTg= +github.com/stackitcloud/stackit-sdk-go/services/rabbitmq v1.1.0/go.mod h1:TwfVVynB/+AKbccSOLk2qZpPL1tdK43BBAiACP6EtSg= github.com/stackitcloud/stackit-sdk-go/services/redis v1.0.0 h1:JsHchCTVpCVUB0KQyjzlFEwJEdorql6pBpXtqQDjtqU= github.com/stackitcloud/stackit-sdk-go/services/redis v1.0.0/go.mod h1:yjej6QfYoYdRIyKXlmbVz8fZYxbuUdl+QBkvLDPgA4k= github.com/stackitcloud/stackit-sdk-go/services/resourcemanager v0.24.0 h1:JPP6a0ME1tZXr4iB69d/LtJsCAr58ENBadFaK9f48/c= diff --git a/stackit/internal/services/rabbitmq/credential/datasource.go b/stackit/internal/services/rabbitmq/credential/datasource.go index 21c5492f1..477a093ee 100644 --- a/stackit/internal/services/rabbitmq/credential/datasource.go +++ b/stackit/internal/services/rabbitmq/credential/datasource.go @@ -31,6 +31,7 @@ type DataSourceModel struct { CredentialId types.String `tfsdk:"credential_id"` InstanceId types.String `tfsdk:"instance_id"` ProjectId types.String `tfsdk:"project_id"` + Region types.String `tfsdk:"region"` Host types.String `tfsdk:"host"` Hosts types.List `tfsdk:"hosts"` HttpAPIURI types.String `tfsdk:"http_api_uri"` @@ -79,7 +80,7 @@ func (r *credentialDataSource) Configure(ctx context.Context, req datasource.Con func (r *credentialDataSource) Schema(_ context.Context, _ datasource.SchemaRequest, resp *datasource.SchemaResponse) { descriptions := map[string]string{ //nolint:gosec // description for credential id "main": "RabbitMQ credential data source schema. Must have a `region` specified in the provider configuration.", - "id": "Terraform's internal data source. identifier. It is structured as \"`project_id`,`instance_id`,`credential_id`\".", + "id": "Terraform's internal data source. identifier. It is structured as \"`project_id`,`region`,`instance_id`,`credential_id`\".", "credential_id": "The credential's ID.", "instance_id": "ID of the RabbitMQ instance.", "project_id": "STACKIT project ID to which the instance is associated.", @@ -201,7 +202,7 @@ func (r *credentialDataSource) Read(ctx context.Context, req datasource.ReadRequ ctx = core.LogResponse(ctx) // Map response body to schema - err = mapDataSourceFields(ctx, recordSetResp, &model) + err = mapDataSourceFields(ctx, recordSetResp, &model, region) if err != nil { core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading credential", fmt.Sprintf("Processing API payload: %v", err)) return @@ -216,7 +217,7 @@ func (r *credentialDataSource) Read(ctx context.Context, req datasource.ReadRequ tflog.Info(ctx, "RabbitMQ credential read") } -func mapDataSourceFields(ctx context.Context, credentialsResp *rabbitmq.CredentialsResponse, model *DataSourceModel) error { +func mapDataSourceFields(ctx context.Context, credentialsResp *rabbitmq.CredentialsResponse, model *DataSourceModel, region string) error { if credentialsResp == nil { return fmt.Errorf("response input is nil") } @@ -237,8 +238,9 @@ func mapDataSourceFields(ctx context.Context, credentialsResp *rabbitmq.Credenti return fmt.Errorf("credentials id not present") } + model.Region = types.StringValue(region) model.Id = utils.BuildInternalTerraformId( - model.ProjectId.ValueString(), model.InstanceId.ValueString(), credentialId, + model.ProjectId.ValueString(), model.Region.ValueString(), model.InstanceId.ValueString(), credentialId, ) model.CredentialId = types.StringValue(credentialId) diff --git a/stackit/internal/services/rabbitmq/credential/datasource_test.go b/stackit/internal/services/rabbitmq/credential/datasource_test.go index 367617408..20e12ab61 100644 --- a/stackit/internal/services/rabbitmq/credential/datasource_test.go +++ b/stackit/internal/services/rabbitmq/credential/datasource_test.go @@ -2,15 +2,17 @@ package rabbitmq import ( "context" + "fmt" "testing" "github.com/google/go-cmp/cmp" "github.com/hashicorp/terraform-plugin-framework/attr" "github.com/hashicorp/terraform-plugin-framework/types" - rabbitmq "github.com/stackitcloud/stackit-sdk-go/services/rabbitmq/v1api" + rabbitmq "github.com/stackitcloud/stackit-sdk-go/services/rabbitmq/v2api" ) func TestMapDataSourceFields(t *testing.T) { + const testRegion = "eu01" tests := []struct { description string state DataSourceModel @@ -29,10 +31,11 @@ func TestMapDataSourceFields(t *testing.T) { Raw: &rabbitmq.RawCredentials{}, }, DataSourceModel{ - Id: types.StringValue("pid,iid,cid"), + Id: types.StringValue(fmt.Sprintf("pid,%s,iid,cid", testRegion)), CredentialId: types.StringValue("cid"), InstanceId: types.StringValue("iid"), ProjectId: types.StringValue("pid"), + Region: types.StringValue(testRegion), Host: types.StringValue(""), Hosts: types.ListNull(types.StringType), HttpAPIURI: types.StringNull(), @@ -79,10 +82,11 @@ func TestMapDataSourceFields(t *testing.T) { }, }, DataSourceModel{ - Id: types.StringValue("pid,iid,cid"), + Id: types.StringValue(fmt.Sprintf("pid,%s,iid,cid", testRegion)), CredentialId: types.StringValue("cid"), InstanceId: types.StringValue("iid"), ProjectId: types.StringValue("pid"), + Region: types.StringValue(testRegion), Host: types.StringValue("host"), Hosts: types.ListValueMust(types.StringType, []attr.Value{ types.StringValue("host_1"), @@ -156,10 +160,11 @@ func TestMapDataSourceFields(t *testing.T) { }, }, DataSourceModel{ - Id: types.StringValue("pid,iid,cid"), + Id: types.StringValue(fmt.Sprintf("pid,%s,iid,cid", testRegion)), CredentialId: types.StringValue("cid"), InstanceId: types.StringValue("iid"), ProjectId: types.StringValue("pid"), + Region: types.StringValue(testRegion), Host: types.StringValue("host"), Hosts: types.ListValueMust(types.StringType, []attr.Value{ types.StringValue("host_2"), @@ -209,10 +214,11 @@ func TestMapDataSourceFields(t *testing.T) { }, }, DataSourceModel{ - Id: types.StringValue("pid,iid,cid"), + Id: types.StringValue(fmt.Sprintf("pid,%s,iid,cid", testRegion)), CredentialId: types.StringValue("cid"), InstanceId: types.StringValue("iid"), ProjectId: types.StringValue("pid"), + Region: types.StringValue(testRegion), Host: types.StringValue(""), Hosts: types.ListValueMust(types.StringType, []attr.Value{}), HttpAPIURI: types.StringNull(), @@ -261,7 +267,7 @@ func TestMapDataSourceFields(t *testing.T) { } for _, tt := range tests { t.Run(tt.description, func(t *testing.T) { - err := mapDataSourceFields(context.Background(), tt.input, &tt.state) + err := mapDataSourceFields(context.Background(), tt.input, &tt.state, testRegion) if !tt.isValid && err == nil { t.Fatalf("Should have failed") } diff --git a/stackit/internal/services/rabbitmq/credential/resource.go b/stackit/internal/services/rabbitmq/credential/resource.go index 279a4c122..929edb09d 100644 --- a/stackit/internal/services/rabbitmq/credential/resource.go +++ b/stackit/internal/services/rabbitmq/credential/resource.go @@ -95,7 +95,7 @@ func (r *credentialResource) Configure(ctx context.Context, req resource.Configu func (r *credentialResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) { descriptions := map[string]string{ //nolint:gosec // description for credential id "main": "RabbitMQ credential resource schema. Must have a `region` specified in the provider configuration.", - "id": "Terraform's internal resource identifier. It is structured as \"`project_id`,`instance_id`,`credential_id`\".", + "id": "Terraform's internal resource identifier. It is structured as \"`project_id`,`region`,`instance_id`,`credential_id`\".", "credential_id": "The credential's ID.", "instance_id": "ID of the RabbitMQ instance.", "project_id": "STACKIT Project ID to which the instance is associated.", @@ -256,7 +256,7 @@ func (r *credentialResource) Create(ctx context.Context, req resource.CreateRequ } // Map response body to schema - err = mapFields(ctx, waitResp, &model) + err = mapFields(ctx, waitResp, &model, region) if err != nil { core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating credential", fmt.Sprintf("Processing API payload: %v", err)) return @@ -308,7 +308,7 @@ func (r *credentialResource) Read(ctx context.Context, req resource.ReadRequest, ctx = core.LogResponse(ctx) // Map response body to schema - err = mapFields(ctx, recordSetResp, &model) + err = mapFields(ctx, recordSetResp, &model, region) if err != nil { core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading credential", fmt.Sprintf("Processing API payload: %v", err)) return @@ -393,7 +393,7 @@ func (r *credentialResource) ImportState(ctx context.Context, req resource.Impor tflog.Info(ctx, "RabbitMQ credential state imported") } -func mapFields(ctx context.Context, credentialsResp *rabbitmq.CredentialsResponse, model *Model) error { +func mapFields(ctx context.Context, credentialsResp *rabbitmq.CredentialsResponse, model *Model, region string) error { if credentialsResp == nil { return fmt.Errorf("response input is nil") } @@ -414,8 +414,9 @@ func mapFields(ctx context.Context, credentialsResp *rabbitmq.CredentialsRespons return fmt.Errorf("credentials id not present") } + model.Region = types.StringValue(region) model.Id = utils.BuildInternalTerraformId( - model.ProjectId.ValueString(), model.InstanceId.ValueString(), credentialId, + model.ProjectId.ValueString(), model.Region.ValueString(), model.InstanceId.ValueString(), credentialId, ) model.CredentialId = types.StringValue(credentialId) diff --git a/stackit/internal/services/rabbitmq/credential/resource_test.go b/stackit/internal/services/rabbitmq/credential/resource_test.go index 6027062b2..6e955ecce 100644 --- a/stackit/internal/services/rabbitmq/credential/resource_test.go +++ b/stackit/internal/services/rabbitmq/credential/resource_test.go @@ -2,6 +2,7 @@ package rabbitmq import ( "context" + "fmt" "testing" "github.com/google/go-cmp/cmp" @@ -11,6 +12,7 @@ import ( ) func TestMapFields(t *testing.T) { + const testRegion = "eu01" tests := []struct { description string state Model @@ -30,10 +32,11 @@ func TestMapFields(t *testing.T) { Raw: &rabbitmq.RawCredentials{}, }, Model{ - Id: types.StringValue("pid,iid,cid"), + Id: types.StringValue(fmt.Sprintf("pid,%s,iid,cid", testRegion)), CredentialId: types.StringValue("cid"), InstanceId: types.StringValue("iid"), ProjectId: types.StringValue("pid"), + Region: types.StringValue(testRegion), Host: types.StringValue(""), Hosts: types.ListNull(types.StringType), HttpAPIURI: types.StringNull(), @@ -82,10 +85,11 @@ func TestMapFields(t *testing.T) { }, }, Model{ - Id: types.StringValue("pid,iid,cid"), + Id: types.StringValue(fmt.Sprintf("pid,%s,iid,cid", testRegion)), CredentialId: types.StringValue("cid"), InstanceId: types.StringValue("iid"), ProjectId: types.StringValue("pid"), + Region: types.StringValue(testRegion), Host: types.StringValue("host"), Hosts: types.ListValueMust(types.StringType, []attr.Value{ types.StringValue("host_1"), @@ -161,10 +165,11 @@ func TestMapFields(t *testing.T) { }, }, Model{ - Id: types.StringValue("pid,iid,cid"), + Id: types.StringValue(fmt.Sprintf("pid,%s,iid,cid", testRegion)), CredentialId: types.StringValue("cid"), InstanceId: types.StringValue("iid"), ProjectId: types.StringValue("pid"), + Region: types.StringValue(testRegion), Host: types.StringValue("host"), Hosts: types.ListValueMust(types.StringType, []attr.Value{ types.StringValue("host_2"), @@ -216,10 +221,11 @@ func TestMapFields(t *testing.T) { }, }, Model{ - Id: types.StringValue("pid,iid,cid"), + Id: types.StringValue(fmt.Sprintf("pid,%s,iid,cid", testRegion)), CredentialId: types.StringValue("cid"), InstanceId: types.StringValue("iid"), ProjectId: types.StringValue("pid"), + Region: types.StringValue(testRegion), Host: types.StringValue(""), Hosts: types.ListValueMust(types.StringType, []attr.Value{}), HttpAPIURI: types.StringNull(), @@ -272,7 +278,7 @@ func TestMapFields(t *testing.T) { } for _, tt := range tests { t.Run(tt.description, func(t *testing.T) { - err := mapFields(context.Background(), tt.input, &tt.state) + err := mapFields(context.Background(), tt.input, &tt.state, testRegion) if !tt.isValid && err == nil { t.Fatalf("Should have failed") } diff --git a/stackit/internal/services/rabbitmq/instance/datasource.go b/stackit/internal/services/rabbitmq/instance/datasource.go index 7fc1f041c..d0fb518bf 100644 --- a/stackit/internal/services/rabbitmq/instance/datasource.go +++ b/stackit/internal/services/rabbitmq/instance/datasource.go @@ -250,7 +250,7 @@ func (r *instanceDataSource) Read(ctx context.Context, req datasource.ReadReques ctx = core.LogResponse(ctx) - err = mapFields(instanceResp, &model) + err = mapFields(instanceResp, &model, region) if err != nil { core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading instance", fmt.Sprintf("Processing API payload: %v", err)) return diff --git a/stackit/internal/services/rabbitmq/instance/resource.go b/stackit/internal/services/rabbitmq/instance/resource.go index 813aa5189..170c9a972 100644 --- a/stackit/internal/services/rabbitmq/instance/resource.go +++ b/stackit/internal/services/rabbitmq/instance/resource.go @@ -401,7 +401,7 @@ func (r *instanceResource) Create(ctx context.Context, req resource.CreateReques } // Map response body to schema - err = mapFields(waitResp, &model) + err = mapFields(waitResp, &model, region) if err != nil { core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating instance", fmt.Sprintf("Processing API payload: %v", err)) return @@ -454,7 +454,7 @@ func (r *instanceResource) Read(ctx context.Context, req resource.ReadRequest, r ctx = core.LogResponse(ctx) // Map response body to schema - err = mapFields(instanceResp, &model) + err = mapFields(instanceResp, &model, region) if err != nil { core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading instance", fmt.Sprintf("Processing API payload: %v", err)) return @@ -532,7 +532,7 @@ func (r *instanceResource) Update(ctx context.Context, req resource.UpdateReques } // Map response body to schema - err = mapFields(waitResp, &model) + err = mapFields(waitResp, &model, region) if err != nil { core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating instance", fmt.Sprintf("Processing API payload: %v", err)) return @@ -611,7 +611,7 @@ func (r *instanceResource) ImportState(ctx context.Context, req resource.ImportS tflog.Info(ctx, "RabbitMQ instance state imported") } -func mapFields(instance *rabbitmq.Instance, model *Model) error { +func mapFields(instance *rabbitmq.Instance, model *Model, region string) error { if instance == nil { return fmt.Errorf("response input is nil") } @@ -628,7 +628,8 @@ func mapFields(instance *rabbitmq.Instance, model *Model) error { return fmt.Errorf("instance id not present") } - model.Id = utils.BuildInternalTerraformId(model.ProjectId.ValueString(), instanceId) + model.Region = types.StringValue(region) + model.Id = utils.BuildInternalTerraformId(model.ProjectId.ValueString(), model.Region.ValueString(), instanceId) model.InstanceId = types.StringValue(instanceId) model.PlanId = types.StringValue(instance.PlanId) model.CfGuid = types.StringValue(instance.CfGuid) diff --git a/stackit/internal/services/rabbitmq/instance/resource_test.go b/stackit/internal/services/rabbitmq/instance/resource_test.go index b609b04da..f24f57e85 100644 --- a/stackit/internal/services/rabbitmq/instance/resource_test.go +++ b/stackit/internal/services/rabbitmq/instance/resource_test.go @@ -2,6 +2,7 @@ package rabbitmq import ( "context" + "fmt" "testing" "github.com/google/go-cmp/cmp" @@ -59,6 +60,7 @@ var fixtureInstanceParameters = rabbitmq.InstanceParameters{ } func TestMapFields(t *testing.T) { + const testRegion = "eu01" tests := []struct { description string input *rabbitmq.Instance @@ -69,9 +71,10 @@ func TestMapFields(t *testing.T) { "default_values", &rabbitmq.Instance{}, Model{ - Id: types.StringValue("pid,iid"), + Id: types.StringValue(fmt.Sprintf("pid,%s,iid", testRegion)), InstanceId: types.StringValue("iid"), ProjectId: types.StringValue("pid"), + Region: types.StringValue(testRegion), PlanId: types.StringValue(""), Name: types.StringValue(""), CfGuid: types.StringValue(""), @@ -111,9 +114,10 @@ func TestMapFields(t *testing.T) { }, }, Model{ - Id: types.StringValue("pid,iid"), + Id: types.StringValue(fmt.Sprintf("pid,%s,iid", testRegion)), InstanceId: types.StringValue("iid"), ProjectId: types.StringValue("pid"), + Region: types.StringValue(testRegion), PlanId: types.StringValue("plan"), Name: types.StringValue("name"), CfGuid: types.StringValue("cf"), @@ -165,7 +169,7 @@ func TestMapFields(t *testing.T) { ProjectId: tt.expected.ProjectId, InstanceId: tt.expected.InstanceId, } - err := mapFields(tt.input, state) + err := mapFields(tt.input, state, testRegion) if !tt.isValid && err == nil { t.Fatalf("Should have failed") } From 1b16a1e97ba2f5fdc0263e4d1cacf64b30f50467 Mon Sep 17 00:00:00 2001 From: Jonas Schlecht Date: Wed, 1 Jul 2026 13:53:02 +0200 Subject: [PATCH 3/4] feat(rabbitmq): fix acc tests --- docs/data-sources/rabbitmq_credential.md | 2 +- docs/resources/rabbitmq_credential.md | 2 +- .../services/rabbitmq/credential/resource.go | 6 +++--- .../services/rabbitmq/instance/datasource.go | 2 +- .../services/rabbitmq/instance/resource.go | 14 ++++++------- .../services/rabbitmq/rabbitmq_acc_test.go | 20 +++++++++++++------ 6 files changed, 27 insertions(+), 19 deletions(-) diff --git a/docs/data-sources/rabbitmq_credential.md b/docs/data-sources/rabbitmq_credential.md index ac15184eb..b03c982b1 100644 --- a/docs/data-sources/rabbitmq_credential.md +++ b/docs/data-sources/rabbitmq_credential.md @@ -39,7 +39,7 @@ data "stackit_rabbitmq_credential" "example" { - `hosts` (List of String) - `http_api_uri` (String) - `http_api_uris` (List of String) -- `id` (String) Terraform's internal data source. identifier. It is structured as "`project_id`,`instance_id`,`credential_id`". +- `id` (String) Terraform's internal data source. identifier. It is structured as "`project_id`,`region`,`instance_id`,`credential_id`". - `management` (String) - `password` (String, Sensitive) - `port` (Number) diff --git a/docs/resources/rabbitmq_credential.md b/docs/resources/rabbitmq_credential.md index fbc7ebde6..e2aeda9bb 100644 --- a/docs/resources/rabbitmq_credential.md +++ b/docs/resources/rabbitmq_credential.md @@ -58,7 +58,7 @@ import { - `hosts` (List of String) - `http_api_uri` (String) - `http_api_uris` (List of String) -- `id` (String) Terraform's internal resource identifier. It is structured as "`project_id`,`instance_id`,`credential_id`". +- `id` (String) Terraform's internal resource identifier. It is structured as "`project_id`,`region`,`instance_id`,`credential_id`". - `management` (String) - `password` (String, Sensitive) - `port` (Number) diff --git a/stackit/internal/services/rabbitmq/credential/resource.go b/stackit/internal/services/rabbitmq/credential/resource.go index 929edb09d..8247d8a0c 100644 --- a/stackit/internal/services/rabbitmq/credential/resource.go +++ b/stackit/internal/services/rabbitmq/credential/resource.go @@ -226,7 +226,7 @@ func (r *credentialResource) Create(ctx context.Context, req resource.CreateRequ ctx = tflog.SetField(ctx, "region", region) // Create new recordset - credentialsResp, err := r.client.DefaultAPI.CreateCredentials(ctx, projectId, instanceId, region).Execute() + credentialsResp, err := r.client.DefaultAPI.CreateCredentials(ctx, projectId, region, instanceId).Execute() if err != nil { core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating credential", fmt.Sprintf("Calling API: %v", err)) return @@ -374,10 +374,10 @@ func (r *credentialResource) Delete(ctx context.Context, req resource.DeleteRequ // The expected format of the resource import identifier is: project_id,region,instance_id,credential_id func (r *credentialResource) 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] == "" { + if len(idParts) != 4 || idParts[0] == "" || idParts[1] == "" || idParts[2] == "" || idParts[3] == "" { core.LogAndAddError(ctx, &resp.Diagnostics, "Error importing credential", - fmt.Sprintf("Expected import identifier with format [project_id],[instance_id],[credential_id], got %q", req.ID), + fmt.Sprintf("Expected import identifier with format [project_id],[region],[instance_id],[credential_id], got %q", req.ID), ) return } diff --git a/stackit/internal/services/rabbitmq/instance/datasource.go b/stackit/internal/services/rabbitmq/instance/datasource.go index d0fb518bf..21e17b3cb 100644 --- a/stackit/internal/services/rabbitmq/instance/datasource.go +++ b/stackit/internal/services/rabbitmq/instance/datasource.go @@ -232,7 +232,7 @@ func (r *instanceDataSource) Read(ctx context.Context, req datasource.ReadReques ctx = tflog.SetField(ctx, "instance_id", instanceId) ctx = tflog.SetField(ctx, "region", region) - instanceResp, err := r.client.DefaultAPI.GetInstance(ctx, projectId, instanceId, region).Execute() + instanceResp, err := r.client.DefaultAPI.GetInstance(ctx, projectId, region, instanceId).Execute() if err != nil { utils.LogError( ctx, diff --git a/stackit/internal/services/rabbitmq/instance/resource.go b/stackit/internal/services/rabbitmq/instance/resource.go index 170c9a972..bf98d609d 100644 --- a/stackit/internal/services/rabbitmq/instance/resource.go +++ b/stackit/internal/services/rabbitmq/instance/resource.go @@ -394,7 +394,7 @@ func (r *instanceResource) Create(ctx context.Context, req resource.CreateReques return } - waitResp, err := wait.CreateInstanceWaitHandler(ctx, r.client.DefaultAPI, projectId, instanceId, region).WaitWithContext(ctx) + waitResp, err := wait.CreateInstanceWaitHandler(ctx, r.client.DefaultAPI, projectId, region, instanceId).WaitWithContext(ctx) if err != nil { core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating instance", fmt.Sprintf("Instance creation waiting: %v", err)) return @@ -525,7 +525,7 @@ func (r *instanceResource) Update(ctx context.Context, req resource.UpdateReques ctx = core.LogResponse(ctx) - waitResp, err := wait.PartialUpdateInstanceWaitHandler(ctx, r.client.DefaultAPI, projectId, instanceId, region).WaitWithContext(ctx) + waitResp, err := wait.PartialUpdateInstanceWaitHandler(ctx, r.client.DefaultAPI, projectId, region, instanceId).WaitWithContext(ctx) if err != nil { core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating instance", fmt.Sprintf("Instance update waiting: %v", err)) return @@ -566,7 +566,7 @@ func (r *instanceResource) Delete(ctx context.Context, req resource.DeleteReques ctx = tflog.SetField(ctx, "region", region) // Delete existing instance - err := r.client.DefaultAPI.DeleteInstance(ctx, projectId, instanceId, region).Execute() + err := r.client.DefaultAPI.DeleteInstance(ctx, projectId, region, instanceId).Execute() if err != nil { var oapiErr *oapierror.GenericOpenAPIError if errors.As(err, &oapiErr) && oapiErr.StatusCode == http.StatusNotFound { @@ -579,7 +579,7 @@ func (r *instanceResource) Delete(ctx context.Context, req resource.DeleteReques ctx = core.LogResponse(ctx) - _, err = wait.DeleteInstanceWaitHandler(ctx, r.client.DefaultAPI, projectId, instanceId, region).WaitWithContext(ctx) + _, err = wait.DeleteInstanceWaitHandler(ctx, r.client.DefaultAPI, projectId, region, instanceId).WaitWithContext(ctx) if err != nil { core.LogAndAddError(ctx, &resp.Diagnostics, "Error deleting instance", fmt.Sprintf("Instance deletion waiting: %v", err)) return @@ -592,10 +592,10 @@ func (r *instanceResource) Delete(ctx context.Context, req resource.DeleteReques func (r *instanceResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { idParts := strings.Split(req.ID, core.Separator) - if len(idParts) != 2 || idParts[0] == "" || idParts[1] == "" { + if len(idParts) != 3 || idParts[0] == "" || idParts[1] == "" || idParts[2] == "" { core.LogAndAddError(ctx, &resp.Diagnostics, "Error importing instance", - fmt.Sprintf("Expected import identifier with format: [project_id],[instance_id] Got: %q", req.ID), + fmt.Sprintf("Expected import identifier with format: [project_id],[region],[instance_id] Got: %q", req.ID), ) return } @@ -629,7 +629,7 @@ func mapFields(instance *rabbitmq.Instance, model *Model, region string) error { } model.Region = types.StringValue(region) - model.Id = utils.BuildInternalTerraformId(model.ProjectId.ValueString(), model.Region.ValueString(), instanceId) + model.Id = utils.BuildInternalTerraformId(model.ProjectId.ValueString(), region, instanceId) model.InstanceId = types.StringValue(instanceId) model.PlanId = types.StringValue(instance.PlanId) model.CfGuid = types.StringValue(instance.CfGuid) diff --git a/stackit/internal/services/rabbitmq/rabbitmq_acc_test.go b/stackit/internal/services/rabbitmq/rabbitmq_acc_test.go index 241c87fb9..7ed52592d 100644 --- a/stackit/internal/services/rabbitmq/rabbitmq_acc_test.go +++ b/stackit/internal/services/rabbitmq/rabbitmq_acc_test.go @@ -196,11 +196,15 @@ func TestAccRabbitMQResource(t *testing.T) { if !ok { return "", fmt.Errorf("couldn't find resource stackit_rabbitmq_instance.instance") } + region, ok := r.Primary.Attributes["region"] + if !ok { + return "", fmt.Errorf("couldn't find attribute region") + } instanceId, ok := r.Primary.Attributes["instance_id"] if !ok { return "", fmt.Errorf("couldn't find attribute instance_id") } - return fmt.Sprintf("%s,%s", testutil.ProjectId, instanceId), nil + return fmt.Sprintf("%s,%s,%s", testutil.ProjectId, region, instanceId), nil }, ImportState: true, ImportStateVerify: true, @@ -212,6 +216,10 @@ func TestAccRabbitMQResource(t *testing.T) { if !ok { return "", fmt.Errorf("couldn't find resource stackit_rabbitmq_credential.credential") } + region, ok := r.Primary.Attributes["region"] + if !ok { + return "", fmt.Errorf("couldn't find attribute region") + } instanceId, ok := r.Primary.Attributes["instance_id"] if !ok { return "", fmt.Errorf("couldn't find attribute instance_id") @@ -220,7 +228,7 @@ func TestAccRabbitMQResource(t *testing.T) { if !ok { return "", fmt.Errorf("couldn't find attribute credential_id") } - return fmt.Sprintf("%s,%s,%s", testutil.ProjectId, instanceId, credentialId), nil + return fmt.Sprintf("%s,%s,%s,%s", testutil.ProjectId, region, instanceId, credentialId), nil }, ImportState: true, ImportStateVerify: true, @@ -246,7 +254,7 @@ func TestAccRabbitMQResource(t *testing.T) { func testAccCheckRabbitMQDestroy(s *terraform.State) error { ctx := context.Background() - client, err := rabbitmq.NewAPIClient(testutil.NewConfigBuilder().BuildClientOptions(testutil.RabbitMQCustomEndpoint, true)...) + client, err := rabbitmq.NewAPIClient(testutil.NewConfigBuilder().BuildClientOptions(testutil.RabbitMQCustomEndpoint, false)...) if err != nil { return fmt.Errorf("creating client: %w", err) } @@ -261,7 +269,7 @@ func testAccCheckRabbitMQDestroy(s *terraform.State) error { instancesToDestroy = append(instancesToDestroy, instanceId) } - instancesResp, err := client.DefaultAPI.ListInstances(ctx, testutil.ProjectId, testutil.Region).Execute() + instancesResp, err := client.DefaultAPI.ListInstances(ctx, testutil.ProjectId, "eu01").Execute() if err != nil { return fmt.Errorf("getting instancesResp: %w", err) } @@ -273,11 +281,11 @@ func testAccCheckRabbitMQDestroy(s *terraform.State) error { } if utils.Contains(instancesToDestroy, *instances[i].InstanceId) { if !checkInstanceDeleteSuccess(&instances[i]) { - err := client.DefaultAPI.DeleteInstance(ctx, testutil.ProjectId, testutil.Region, *instances[i].InstanceId).Execute() + err := client.DefaultAPI.DeleteInstance(ctx, testutil.ProjectId, "eu01", *instances[i].InstanceId).Execute() if err != nil { return fmt.Errorf("destroying instance %s during CheckDestroy: %w", *instances[i].InstanceId, err) } - _, err = wait.DeleteInstanceWaitHandler(ctx, client.DefaultAPI, testutil.ProjectId, testutil.Region, *instances[i].InstanceId).WaitWithContext(ctx) + _, err = wait.DeleteInstanceWaitHandler(ctx, client.DefaultAPI, testutil.ProjectId, "eu01", *instances[i].InstanceId).WaitWithContext(ctx) if err != nil { return fmt.Errorf("destroying instance %s during CheckDestroy: waiting for deletion %w", *instances[i].InstanceId, err) } From 2cc81d83d19117d31a9e65adcf4369637a098c78 Mon Sep 17 00:00:00 2001 From: Jonas Schlecht Date: Thu, 2 Jul 2026 09:14:39 +0200 Subject: [PATCH 4/4] chore(rabbitmq): remove unused function in utils --- .../internal/services/rabbitmq/utils/util.go | 20 ------------------- 1 file changed, 20 deletions(-) diff --git a/stackit/internal/services/rabbitmq/utils/util.go b/stackit/internal/services/rabbitmq/utils/util.go index 72d40dc2a..94c618c3d 100644 --- a/stackit/internal/services/rabbitmq/utils/util.go +++ b/stackit/internal/services/rabbitmq/utils/util.go @@ -28,23 +28,3 @@ func ConfigureClient(ctx context.Context, providerData *core.ProviderData, diags return apiClient } - -// StringSliceToInstanceParametersPluginsInner takes a string slice and converts it to rabbitmq.InstanceParamtersPluginsInner. -func StringSliceToInstanceParametersPluginsInner(s []string) []rabbitmq.InstanceParametersPluginsInner { - result := make([]rabbitmq.InstanceParametersPluginsInner, len(s)) - for i, element := range s { - result[i] = rabbitmq.InstanceParametersPluginsInner(element) - } - - return result -} - -// StringSliceToInstanceParametersTlsProtocolsInner takes a string slice and converts it to rabbitmq.InstanceParametersTlsProtocolsInner. -func StringSliceToInstanceParametersTlsProtocolsInner(s []string) []rabbitmq.InstanceParametersTlsProtocolsInner { - result := make([]rabbitmq.InstanceParametersTlsProtocolsInner, len(s)) - for i, element := range s { - result[i] = rabbitmq.InstanceParametersTlsProtocolsInner(element) - } - - return result -}