From 3a1eb1707ecc2de010cdfe625e59b993453c1631 Mon Sep 17 00:00:00 2001 From: Oleksandr Zanichkovskyi Date: Thu, 2 Jul 2026 09:45:02 +0200 Subject: [PATCH 1/2] fix: check if telemetry link already exists before creating --- .../services/telemetrylink/link/resource.go | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/stackit/internal/services/telemetrylink/link/resource.go b/stackit/internal/services/telemetrylink/link/resource.go index 5227bca1b..3f6aebc3e 100644 --- a/stackit/internal/services/telemetrylink/link/resource.go +++ b/stackit/internal/services/telemetrylink/link/resource.go @@ -226,6 +226,16 @@ func (r *telemetryLinkResource) Create(ctx context.Context, req resource.CreateR var response *telemetrylink.TelemetryLinkResponse switch model.ResourceType.ValueString() { case resourceTypeOrganization: + _, err := r.client.DefaultAPI.GetOrganizationTelemetryLink(ctx, resourceID, region).Execute() + if err != nil { + var oapiErr *oapierror.GenericOpenAPIError + ok := errors.As(err, &oapiErr) + if !ok || oapiErr.StatusCode != http.StatusNotFound { + core.LogAndAddError(ctx, &resp.Diagnostics, "Error checking if TelemetryLink already exists", fmt.Sprintf("Calling API: %v", err)) + return + } + } + payload, err := toCreateOrUpdateOrganizationTelemetryLinkPayload(ctx, resp.Diagnostics, &model) if err != nil { core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating TelemetryLink", fmt.Sprintf("Creating API payload: %v", err)) @@ -262,6 +272,16 @@ func (r *telemetryLinkResource) Create(ctx context.Context, req resource.CreateR } case resourceTypeFolder: + _, err := r.client.DefaultAPI.GetFolderTelemetryLink(ctx, resourceID, region).Execute() + if err != nil { + var oapiErr *oapierror.GenericOpenAPIError + ok := errors.As(err, &oapiErr) + if !ok || oapiErr.StatusCode != http.StatusNotFound { + core.LogAndAddError(ctx, &resp.Diagnostics, "Error checking if TelemetryLink already exists", fmt.Sprintf("Calling API: %v", err)) + return + } + } + payload, err := toCreateOrUpdateFolderTelemetryLinkPayload(ctx, resp.Diagnostics, &model) if err != nil { core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating TelemetryLink", fmt.Sprintf("Creating API payload: %v", err)) @@ -297,6 +317,16 @@ func (r *telemetryLinkResource) Create(ctx context.Context, req resource.CreateR return } case resourceTypeProject: + _, err := r.client.DefaultAPI.GetProjectTelemetryLink(ctx, resourceID, region).Execute() + if err != nil { + var oapiErr *oapierror.GenericOpenAPIError + ok := errors.As(err, &oapiErr) + if !ok || oapiErr.StatusCode != http.StatusNotFound { + core.LogAndAddError(ctx, &resp.Diagnostics, "Error checking if TelemetryLink already exists", fmt.Sprintf("Calling API: %v", err)) + return + } + } + payload, err := toCreateOrUpdateProjectTelemetryLinkPayload(ctx, resp.Diagnostics, &model) if err != nil { core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating TelemetryLink", fmt.Sprintf("Creating API payload: %v", err)) From b29ab3ebb4b8add772af88e2bde163ad7602c073 Mon Sep 17 00:00:00 2001 From: Oleksandr Zanichkovskyi Date: Wed, 8 Jul 2026 16:42:44 +0200 Subject: [PATCH 2/2] feat: using If-None-Match header to conditionally create TelemetryLink # Conflicts: # go.mod # go.sum --- .../services/telemetrylink/link/datasource.go | 2 +- .../telemetrylink/link/datasource_test.go | 2 +- .../services/telemetrylink/link/resource.go | 61 ++++++------------- .../telemetrylink/link/resource_test.go | 2 +- .../telemetrylink/telemetrylink_acc_test.go | 4 +- .../services/telemetrylink/utils/utils.go | 2 +- .../telemetrylink/utils/utils_test.go | 2 +- 7 files changed, 27 insertions(+), 48 deletions(-) diff --git a/stackit/internal/services/telemetrylink/link/datasource.go b/stackit/internal/services/telemetrylink/link/datasource.go index 238e25bd1..e7fff21af 100644 --- a/stackit/internal/services/telemetrylink/link/datasource.go +++ b/stackit/internal/services/telemetrylink/link/datasource.go @@ -12,7 +12,7 @@ import ( "github.com/hashicorp/terraform-plugin-framework/schema/validator" "github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-plugin-log/tflog" - telemetrylink "github.com/stackitcloud/stackit-sdk-go/services/telemetrylink/v1betaapi" + telemetrylink "github.com/stackitcloud/stackit-sdk-go/services/telemetrylink/v1api" "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/conversion" "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/core" diff --git a/stackit/internal/services/telemetrylink/link/datasource_test.go b/stackit/internal/services/telemetrylink/link/datasource_test.go index 2b4789598..8dc2839cc 100644 --- a/stackit/internal/services/telemetrylink/link/datasource_test.go +++ b/stackit/internal/services/telemetrylink/link/datasource_test.go @@ -7,7 +7,7 @@ import ( "github.com/google/go-cmp/cmp" "github.com/hashicorp/terraform-plugin-framework/types" - telemetrylink "github.com/stackitcloud/stackit-sdk-go/services/telemetrylink/v1betaapi" + telemetrylink "github.com/stackitcloud/stackit-sdk-go/services/telemetrylink/v1api" ) func fixtureDataSourceModel(mods ...func(model *DataSourceModel)) *DataSourceModel { diff --git a/stackit/internal/services/telemetrylink/link/resource.go b/stackit/internal/services/telemetrylink/link/resource.go index 3f6aebc3e..dff183ed2 100644 --- a/stackit/internal/services/telemetrylink/link/resource.go +++ b/stackit/internal/services/telemetrylink/link/resource.go @@ -20,8 +20,8 @@ import ( "github.com/stackitcloud/stackit-sdk-go/core/oapierror" sdkUtils "github.com/stackitcloud/stackit-sdk-go/core/utils" - telemetrylink "github.com/stackitcloud/stackit-sdk-go/services/telemetrylink/v1betaapi" - "github.com/stackitcloud/stackit-sdk-go/services/telemetrylink/v1betaapi/wait" + telemetrylink "github.com/stackitcloud/stackit-sdk-go/services/telemetrylink/v1api" + "github.com/stackitcloud/stackit-sdk-go/services/telemetrylink/v1api/wait" "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/conversion" "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/core" @@ -226,23 +226,16 @@ func (r *telemetryLinkResource) Create(ctx context.Context, req resource.CreateR var response *telemetrylink.TelemetryLinkResponse switch model.ResourceType.ValueString() { case resourceTypeOrganization: - _, err := r.client.DefaultAPI.GetOrganizationTelemetryLink(ctx, resourceID, region).Execute() - if err != nil { - var oapiErr *oapierror.GenericOpenAPIError - ok := errors.As(err, &oapiErr) - if !ok || oapiErr.StatusCode != http.StatusNotFound { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error checking if TelemetryLink already exists", fmt.Sprintf("Calling API: %v", err)) - return - } - } - payload, err := toCreateOrUpdateOrganizationTelemetryLinkPayload(ctx, resp.Diagnostics, &model) if err != nil { core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating TelemetryLink", fmt.Sprintf("Creating API payload: %v", err)) return } - createResp, err := r.client.DefaultAPI.CreateOrUpdateOrganizationTelemetryLink(ctx, resourceID, region).CreateOrUpdateOrganizationTelemetryLinkPayload(*payload).Execute() + createResp, err := r.client.DefaultAPI.CreateOrUpdateOrganizationTelemetryLink(ctx, resourceID, region). + CreateOrUpdateOrganizationTelemetryLinkPayload(*payload). + IfNoneMatch("*"). + Execute() if err != nil { core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating TelemetryLink", fmt.Sprintf("Calling API: %v", err)) return @@ -265,30 +258,23 @@ func (r *telemetryLinkResource) Create(ctx context.Context, req resource.CreateR return } - response, err = wait.CreateOrUpdateOrganizationTelemetryLinkWaitHandler(ctx, r.client.DefaultAPI, resourceID, region).WaitWithContext(ctx) + response, err = wait.CreateOrganizationTelemetryLinkWaitHandler(ctx, r.client.DefaultAPI, resourceID, region).WaitWithContext(ctx) if err != nil { core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating TelemetryLink", fmt.Sprintf("Waiting for TelemetryLink to become active: %v", err)) return } case resourceTypeFolder: - _, err := r.client.DefaultAPI.GetFolderTelemetryLink(ctx, resourceID, region).Execute() - if err != nil { - var oapiErr *oapierror.GenericOpenAPIError - ok := errors.As(err, &oapiErr) - if !ok || oapiErr.StatusCode != http.StatusNotFound { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error checking if TelemetryLink already exists", fmt.Sprintf("Calling API: %v", err)) - return - } - } - payload, err := toCreateOrUpdateFolderTelemetryLinkPayload(ctx, resp.Diagnostics, &model) if err != nil { core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating TelemetryLink", fmt.Sprintf("Creating API payload: %v", err)) return } - createResp, err := r.client.DefaultAPI.CreateOrUpdateFolderTelemetryLink(ctx, resourceID, region).CreateOrUpdateFolderTelemetryLinkPayload(*payload).Execute() + createResp, err := r.client.DefaultAPI.CreateOrUpdateFolderTelemetryLink(ctx, resourceID, region). + CreateOrUpdateFolderTelemetryLinkPayload(*payload). + IfNoneMatch("*"). + Execute() if err != nil { core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating TelemetryLink", fmt.Sprintf("Calling API: %v", err)) return @@ -311,29 +297,22 @@ func (r *telemetryLinkResource) Create(ctx context.Context, req resource.CreateR return } - response, err = wait.CreateOrUpdateFolderTelemetryLinkWaitHandler(ctx, r.client.DefaultAPI, resourceID, region).WaitWithContext(ctx) + response, err = wait.CreateFolderTelemetryLinkWaitHandler(ctx, r.client.DefaultAPI, resourceID, region).WaitWithContext(ctx) if err != nil { core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating TelemetryLink", fmt.Sprintf("Waiting for TelemetryLink to become active: %v", err)) return } case resourceTypeProject: - _, err := r.client.DefaultAPI.GetProjectTelemetryLink(ctx, resourceID, region).Execute() - if err != nil { - var oapiErr *oapierror.GenericOpenAPIError - ok := errors.As(err, &oapiErr) - if !ok || oapiErr.StatusCode != http.StatusNotFound { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error checking if TelemetryLink already exists", fmt.Sprintf("Calling API: %v", err)) - return - } - } - payload, err := toCreateOrUpdateProjectTelemetryLinkPayload(ctx, resp.Diagnostics, &model) if err != nil { core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating TelemetryLink", fmt.Sprintf("Creating API payload: %v", err)) return } - createResp, err := r.client.DefaultAPI.CreateOrUpdateProjectTelemetryLink(ctx, resourceID, region).CreateOrUpdateProjectTelemetryLinkPayload(*payload).Execute() + createResp, err := r.client.DefaultAPI.CreateOrUpdateProjectTelemetryLink(ctx, resourceID, region). + CreateOrUpdateProjectTelemetryLinkPayload(*payload). + IfNoneMatch("*"). + Execute() if err != nil { core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating TelemetryLink", fmt.Sprintf("Calling API: %v", err)) return @@ -356,7 +335,7 @@ func (r *telemetryLinkResource) Create(ctx context.Context, req resource.CreateR return } - response, err = wait.CreateOrUpdateProjectTelemetryLinkWaitHandler(ctx, r.client.DefaultAPI, resourceID, region).WaitWithContext(ctx) + response, err = wait.CreateProjectTelemetryLinkWaitHandler(ctx, r.client.DefaultAPI, resourceID, region).WaitWithContext(ctx) if err != nil { core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating TelemetryLink", fmt.Sprintf("Waiting for TelemetryLink to become active: %v", err)) return @@ -473,7 +452,7 @@ func (r *telemetryLinkResource) Update(ctx context.Context, req resource.UpdateR ctx = core.LogResponse(ctx) - response, err = wait.CreateOrUpdateOrganizationTelemetryLinkWaitHandler(ctx, r.client.DefaultAPI, resourceID, region).WaitWithContext(ctx) + response, err = wait.UpdateOrganizationTelemetryLinkWaitHandler(ctx, r.client.DefaultAPI, resourceID, region).WaitWithContext(ctx) if err != nil { core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating TelemetryLink", fmt.Sprintf("Waiting for TelemetryLink to become active: %v", err)) return @@ -493,7 +472,7 @@ func (r *telemetryLinkResource) Update(ctx context.Context, req resource.UpdateR ctx = core.LogResponse(ctx) - response, err = wait.CreateOrUpdateFolderTelemetryLinkWaitHandler(ctx, r.client.DefaultAPI, resourceID, region).WaitWithContext(ctx) + response, err = wait.UpdateFolderTelemetryLinkWaitHandler(ctx, r.client.DefaultAPI, resourceID, region).WaitWithContext(ctx) if err != nil { core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating TelemetryLink", fmt.Sprintf("Waiting for TelemetryLink to become active: %v", err)) return @@ -513,7 +492,7 @@ func (r *telemetryLinkResource) Update(ctx context.Context, req resource.UpdateR ctx = core.LogResponse(ctx) - response, err = wait.CreateOrUpdateProjectTelemetryLinkWaitHandler(ctx, r.client.DefaultAPI, resourceID, region).WaitWithContext(ctx) + response, err = wait.UpdateProjectTelemetryLinkWaitHandler(ctx, r.client.DefaultAPI, resourceID, region).WaitWithContext(ctx) if err != nil { core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating TelemetryLink", fmt.Sprintf("Waiting for TelemetryLink to become active: %v", err)) return diff --git a/stackit/internal/services/telemetrylink/link/resource_test.go b/stackit/internal/services/telemetrylink/link/resource_test.go index c5c6bf7c8..6d139080a 100644 --- a/stackit/internal/services/telemetrylink/link/resource_test.go +++ b/stackit/internal/services/telemetrylink/link/resource_test.go @@ -8,7 +8,7 @@ import ( "github.com/google/go-cmp/cmp" "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/types" - telemetrylink "github.com/stackitcloud/stackit-sdk-go/services/telemetrylink/v1betaapi" + telemetrylink "github.com/stackitcloud/stackit-sdk-go/services/telemetrylink/v1api" ) var testTime = time.Now() diff --git a/stackit/internal/services/telemetrylink/telemetrylink_acc_test.go b/stackit/internal/services/telemetrylink/telemetrylink_acc_test.go index d7c0fc1d2..cd84d49b1 100644 --- a/stackit/internal/services/telemetrylink/telemetrylink_acc_test.go +++ b/stackit/internal/services/telemetrylink/telemetrylink_acc_test.go @@ -15,8 +15,8 @@ import ( "github.com/hashicorp/terraform-plugin-testing/helper/resource" "github.com/hashicorp/terraform-plugin-testing/terraform" "github.com/stackitcloud/stackit-sdk-go/core/oapierror" - telemetrylink "github.com/stackitcloud/stackit-sdk-go/services/telemetrylink/v1betaapi" - telemetrylinkWait "github.com/stackitcloud/stackit-sdk-go/services/telemetrylink/v1betaapi/wait" + telemetrylink "github.com/stackitcloud/stackit-sdk-go/services/telemetrylink/v1api" + telemetrylinkWait "github.com/stackitcloud/stackit-sdk-go/services/telemetrylink/v1api/wait" "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/core" "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/testutil" diff --git a/stackit/internal/services/telemetrylink/utils/utils.go b/stackit/internal/services/telemetrylink/utils/utils.go index dd43ab2a6..22c40fa84 100644 --- a/stackit/internal/services/telemetrylink/utils/utils.go +++ b/stackit/internal/services/telemetrylink/utils/utils.go @@ -6,7 +6,7 @@ import ( "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/stackitcloud/stackit-sdk-go/core/config" - telemetrylink "github.com/stackitcloud/stackit-sdk-go/services/telemetrylink/v1betaapi" + telemetrylink "github.com/stackitcloud/stackit-sdk-go/services/telemetrylink/v1api" "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/core" "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/utils" diff --git a/stackit/internal/services/telemetrylink/utils/utils_test.go b/stackit/internal/services/telemetrylink/utils/utils_test.go index ddefaa831..9a3205fb7 100644 --- a/stackit/internal/services/telemetrylink/utils/utils_test.go +++ b/stackit/internal/services/telemetrylink/utils/utils_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" - telemetrylink "github.com/stackitcloud/stackit-sdk-go/services/telemetrylink/v1betaapi" + telemetrylink "github.com/stackitcloud/stackit-sdk-go/services/telemetrylink/v1api" "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/core" "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/utils"