diff --git a/.github/actions/acc_test/action.yaml b/.github/actions/acc_test/action.yaml index ccd08969..ff8b1602 100644 --- a/.github/actions/acc_test/action.yaml +++ b/.github/actions/acc_test/action.yaml @@ -2,9 +2,14 @@ name: Acceptance Testing description: "Acceptance Testing pipeline" inputs: + tf_debug: + description: "enable terraform debug logs" + default: 'false' + required: true + test_timeout_string: description: "string that determines the timeout (default: 45m)" - default: '45m' + default: '90m' required: true go-version: @@ -141,6 +146,12 @@ runs: ${{ steps.goenv.outputs.gomodcache }} key: ${{ runner.os }}-gopkg + - name: Define service account file path variable + id: service_account + shell: bash + run: | + echo "safilepath=${PWD}/stackit/${{ inputs.service_account_json_file_path }}" >> "$GITHUB_OUTPUT" + - name: Creating service_account file from json input if: inputs.service_account_json_content != '' shell: bash @@ -192,6 +203,11 @@ runs: echo "::group::go test file" set -e set -o pipefail + + if [[ "${{ inputs.tf_debug }}" == "true" ]]; then + TF_LOG=INFO + export TF_LOG + fi echo "Running acceptance tests for the terraform provider" cd stackit || exit 1 @@ -204,7 +220,7 @@ runs: TF_ACC_KEK_KEY_RING_ID=${TF_ACC_KEK_KEY_RING_ID} \ TF_ACC_KEK_KEY_VERSION=${TF_ACC_KEK_KEY_VERSION} \ TF_ACC_KEK_SERVICE_ACCOUNT=${TF_ACC_KEK_SERVICE_ACCOUNT} \ - go test ${{ inputs.test_file }} -count=1 -timeout=${{ inputs.test_timeout_string }} + go test -v ${{ inputs.test_file }} -timeout=${{ inputs.test_timeout_string }} echo "::endgroup::" env: TF_ACC_PROJECT_ID: ${{ inputs.project_id }} @@ -215,6 +231,7 @@ runs: TF_ACC_KEK_KEY_VERSION: ${{ inputs.tf_acc_kek_key_version }} TF_ACC_KEK_SERVICE_ACCOUNT: ${{ inputs.tf_acc_kek_service_account }} +# does not work correctly # - name: Run test action # if: ${{ inputs.test_file == '' }} # env: @@ -226,19 +243,25 @@ runs: # TF_ACC_KEK_KEY_RING_ID: ${{ inputs.tf_acc_kek_key_ring_id }} # TF_ACC_KEK_KEY_VERSION: ${{ inputs.tf_acc_kek_key_version }} # TF_ACC_KEK_SERVICE_ACCOUNT: ${{ inputs.tf_acc_kek_service_account }} -# TF_ACC_SERVICE_ACCOUNT_FILE: "${PWD}/${{ inputs.service_account_json_file_path }}" -# uses: robherley/go-test-action@v0.1.0 +# TF_ACC_SERVICE_ACCOUNT_FILE: ${{ steps.service_account.outputs.safile }} +# uses: robherley/go-test-action@v0 # with: -# testArguments: "./... -timeout 45m" +# testArguments: "./... -timeout ${{ inputs.test_timeout_string }}" +# moduleDirectory: "stackit" - name: Run acceptance tests if: ${{ inputs.test_file == '' }} shell: bash run: | echo "::group::go test all" - set -e + set -e set -o pipefail + if [[ "${{ inputs.tf_debug }}" == "true" ]]; then + TF_LOG=INFO + export TF_LOG + fi + echo "Running acceptance tests for the terraform provider" cd stackit || exit 1 TF_ACC=1 \ @@ -250,7 +273,7 @@ runs: TF_ACC_KEK_KEY_RING_ID=${TF_ACC_KEK_KEY_RING_ID} \ TF_ACC_KEK_KEY_VERSION=${TF_ACC_KEK_KEY_VERSION} \ TF_ACC_KEK_SERVICE_ACCOUNT=${TF_ACC_KEK_SERVICE_ACCOUNT} \ - go test ./... -count=1 -timeout=${{ inputs.test_timeout_string }} + go test -v ./... -timeout=${{ inputs.test_timeout_string }} echo "::endgroup::" env: TF_ACC_PROJECT_ID: ${{ inputs.project_id }} diff --git a/.github/workflows/ci_new.yaml b/.github/workflows/ci_new.yaml index 35deb76c..9ff6a379 100644 --- a/.github/workflows/ci_new.yaml +++ b/.github/workflows/ci_new.yaml @@ -2,6 +2,7 @@ name: CI Workflow on: pull_request: + types: [ opened, synchronize, reopened ] branches: - alpha - main @@ -218,11 +219,21 @@ jobs: run: go mod tidy - name: Testing + if: ${{ github.event_name != 'pull_request' }} run: | + unset TF_ACC TF_ACC_SERVICE_ACCOUNT_FILE=~/.service_account.json export TF_ACC_SERVICE_ACCOUNT_FILE make test + - name: Testing with coverage + if: ${{ github.event_name == 'pull_request' }} + run: | + unset TF_ACC + TF_ACC_SERVICE_ACCOUNT_FILE=~/.service_account.json + export TF_ACC_SERVICE_ACCOUNT_FILE + make coverage + # - name: Acceptance Testing # env: # TF_ACC: "1" @@ -232,20 +243,20 @@ jobs: # export TF_ACC_SERVICE_ACCOUNT_FILE # make test-acceptance-tf - - name: Run Test - if: ${{ github.event_name == 'pull_request' }} - uses: ./.github/actions/acc_test - with: - go-version: ${{ env.GO_VERSION }} - project_id: ${{ vars.TF_ACC_PROJECT_ID }} - region: ${{ vars.TF_ACC_REGION }} - service_account_json_content_b64: "${{ secrets.TF_ACC_SERVICE_ACCOUNT_JSON_B64 }}" - project_user_email: ${{ vars.TEST_PROJECT_USER_EMAIL }} - tf_acc_kek_key_id: ${{ vars.TF_ACC_KEK_KEY_ID }} - tf_acc_kek_key_ring_id: ${{ vars.TF_ACC_KEK_KEY_RING_ID }} - tf_acc_kek_key_version: ${{ vars.TF_ACC_KEK_KEY_VERSION }} - tf_acc_kek_service_account: ${{ vars.TF_ACC_KEK_SERVICE_ACCOUNT }} - # service_account_json_file_path: "~/service_account.json" +# - name: Run Acceptance Test +# if: ${{ github.event_name == 'pull_request' }} +# uses: ./.github/actions/acc_test +# with: +# go-version: ${{ env.GO_VERSION }} +# project_id: ${{ vars.TF_ACC_PROJECT_ID }} +# region: ${{ vars.TF_ACC_REGION }} +# service_account_json_content_b64: "${{ secrets.TF_ACC_SERVICE_ACCOUNT_JSON_B64 }}" +# project_user_email: ${{ vars.TEST_PROJECT_USER_EMAIL }} +# tf_acc_kek_key_id: ${{ vars.TF_ACC_KEK_KEY_ID }} +# tf_acc_kek_key_ring_id: ${{ vars.TF_ACC_KEK_KEY_RING_ID }} +# tf_acc_kek_key_version: ${{ vars.TF_ACC_KEK_KEY_VERSION }} +# tf_acc_kek_service_account: ${{ vars.TF_ACC_KEK_SERVICE_ACCOUNT }} +# # service_account_json_file_path: "~/service_account.json" - name: Check coverage threshold shell: bash diff --git a/.github/workflows/renovate.yaml b/.github/workflows/renovate.yaml index 90adebe6..c629eab0 100644 --- a/.github/workflows/renovate.yaml +++ b/.github/workflows/renovate.yaml @@ -12,8 +12,10 @@ jobs: steps: - name: Checkout uses: actions/checkout@v6 + - name: Self-hosted Renovate - uses: renovatebot/github-action@v41.0.0 + uses: renovatebot/github-action@v46.1.4 with: configurationFile: .github/renovate.json - token: ${{ secrets.RENOVATE_TOKEN }} + # token: ${{ secrets.RENOVATE_TOKEN }} + token: ${{ env.FORGEJO_TOKEN }} diff --git a/.github/workflows/tf-acc-test.yaml b/.github/workflows/tf-acc-test.yaml index b409df26..75a35382 100644 --- a/.github/workflows/tf-acc-test.yaml +++ b/.github/workflows/tf-acc-test.yaml @@ -1,10 +1,24 @@ name: TF Acceptance Tests Workflow on: + pull_request: + types: [opened, synchronize, reopened] + branches: + - alpha + - main push: branches: - master workflow_dispatch: + inputs: + enable_debug: + description: "enable terraform debug logs" + default: 'false' + required: true + test_timeout_string: + description: "string that determines the timeout (default: 45m)" + default: '90m' + required: true jobs: acc_test: @@ -14,7 +28,8 @@ jobs: - name: Checkout uses: actions/checkout@v6 - - name: Run Test + - name: Run Test (workflow dispatch) + if: ${{ github.event_name == 'workflow_dispatch' }} uses: ./.github/actions/acc_test with: go-version: ${{ env.GO_VERSION }} @@ -26,4 +41,20 @@ jobs: tf_acc_kek_key_ring_id: ${{ vars.TF_ACC_KEK_KEY_RING_ID }} tf_acc_kek_key_version: ${{ vars.TF_ACC_KEK_KEY_VERSION }} tf_acc_kek_service_account: ${{ vars.TF_ACC_KEK_SERVICE_ACCOUNT }} - # service_account_json_file_path: "~/service_account.json" + tf_debug: ${{ inputs.enable_debug }} + test_timeout_string: ${{ inputs.test_timeout_string }} + + - name: Run Test (automatic) + if: ${{ github.event_name != 'workflow_dispatch' }} + uses: ./.github/actions/acc_test + with: + go-version: ${{ env.GO_VERSION }} + project_id: ${{ vars.TF_ACC_PROJECT_ID }} + region: 'eu01' + service_account_json_content_b64: "${{ secrets.TF_ACC_SERVICE_ACCOUNT_JSON_B64 }}" + project_user_email: ${{ vars.TEST_PROJECT_USER_EMAIL }} + tf_acc_kek_key_id: ${{ vars.TF_ACC_KEK_KEY_ID }} + tf_acc_kek_key_ring_id: ${{ vars.TF_ACC_KEK_KEY_RING_ID }} + tf_acc_kek_key_version: ${{ vars.TF_ACC_KEK_KEY_VERSION }} + tf_acc_kek_service_account: ${{ vars.TF_ACC_KEK_SERVICE_ACCOUNT }} + tf_debug: ${{ inputs.enable_debug }} diff --git a/.golang-ci.yaml b/.golang-ci.yaml index a9fa6be5..8f4c571b 100644 --- a/.golang-ci.yaml +++ b/.golang-ci.yaml @@ -29,12 +29,8 @@ linters: depguard: rules: main: - list-mode: lax - allow: - - tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview - - github.com/hashicorp/terraform-plugin-framework - - github.com/hashicorp/terraform-plugin-log - - github.com/stackitcloud/stackit-sdk-go + list-mode: original + allow: [] deny: - pkg: github.com/stretchr/testify desc: Do not use a testing framework @@ -76,6 +72,7 @@ linters: exclusions: paths: - generator/ + - internal/testutils generated: lax warn-unused: true # Excluding configuration per-path, per-linter, per-text and per-source. @@ -86,7 +83,7 @@ linters: - gochecknoinits formatters: enable: - #- gofmt + - gofmt - goimports settings: goimports: diff --git a/docs/data-sources/postgresflexalpha_database.md b/docs/data-sources/postgresflexalpha_database.md index 95c115e3..7e4c7183 100644 --- a/docs/data-sources/postgresflexalpha_database.md +++ b/docs/data-sources/postgresflexalpha_database.md @@ -28,6 +28,9 @@ data "stackitprivatepreview_postgresflexalpha_database" "example" { - `database_id` (Number) The ID of the database. - `instance_id` (String) The ID of the instance. - `project_id` (String) The STACKIT project ID. + +### Optional + - `region` (String) The region which should be addressed ### Read-Only diff --git a/docs/data-sources/postgresflexalpha_instance.md b/docs/data-sources/postgresflexalpha_instance.md index d21a5f10..cb1d183a 100644 --- a/docs/data-sources/postgresflexalpha_instance.md +++ b/docs/data-sources/postgresflexalpha_instance.md @@ -26,6 +26,9 @@ data "stackitprivatepreview_postgresflexalpha_instance" "example" { - `instance_id` (String) The ID of the instance. - `project_id` (String) The STACKIT project ID. + +### Optional + - `region` (String) The region which should be addressed ### Read-Only @@ -37,6 +40,7 @@ data "stackitprivatepreview_postgresflexalpha_instance" "example" { ⚠︝ **Note:** This feature is in private preview. Supplying this object is only permitted for enabled accounts. If your account does not have access, the request will be rejected. (see [below for nested schema](#nestedatt--encryption)) - `flavor_id` (String) The id of the instance flavor. +- `id` (String) internal ID - `is_deletable` (Boolean) Whether the instance can be deleted or not. - `name` (String) The name of the instance. - `network` (Attributes) The access configuration of the instance (see [below for nested schema](#nestedatt--network)) diff --git a/docs/data-sources/postgresflexalpha_user.md b/docs/data-sources/postgresflexalpha_user.md index c3553c7b..b5a8af2d 100644 --- a/docs/data-sources/postgresflexalpha_user.md +++ b/docs/data-sources/postgresflexalpha_user.md @@ -27,12 +27,12 @@ data "stackitprivatepreview_postgresflexalpha_user" "example" { - `instance_id` (String) The ID of the instance. - `project_id` (String) The STACKIT project ID. -- `region` (String) The region which should be addressed - `user_id` (Number) The ID of the user. ### Optional - `id` (String) Terraform's internal resource ID. It is structured as \"`project_id`,`region`,`instance_id`,`user_id`\".", +- `region` (String) The region which should be addressed ### Read-Only diff --git a/docs/resources/postgresflexalpha_database.md b/docs/resources/postgresflexalpha_database.md index 6c94fd62..29f43024 100644 --- a/docs/resources/postgresflexalpha_database.md +++ b/docs/resources/postgresflexalpha_database.md @@ -54,4 +54,4 @@ import { ### Read-Only -- `id` (Number) The id of the database. +- `id` (String) The id of the database. diff --git a/docs/resources/postgresflexalpha_user.md b/docs/resources/postgresflexalpha_user.md index b83de15d..eebab22d 100644 --- a/docs/resources/postgresflexalpha_user.md +++ b/docs/resources/postgresflexalpha_user.md @@ -54,6 +54,6 @@ import { ### Read-Only -- `id` (Number) The ID of the user. +- `id` (String) The ID of the user. - `password` (String) The password for the user. - `status` (String) The current status of the user. diff --git a/internal/testutils/functions.go b/internal/testutils/functions.go index 5b8f2970..f797259a 100644 --- a/internal/testutils/functions.go +++ b/internal/testutils/functions.go @@ -53,7 +53,7 @@ func CreateTemporaryHome(createValidCredentialsFile bool, t *testing.T) string { // Define content, default = invalid token token := "foo_token" - //if createValidCredentialsFile { + // if createValidCredentialsFile { // token = GetTestProjectServiceAccountJson("") //} if _, err = file.WriteString(token); err != nil { diff --git a/internal/testutils/testutils.go b/internal/testutils/testutils.go index 142efe13..cfe400cd 100644 --- a/internal/testutils/testutils.go +++ b/internal/testutils/testutils.go @@ -99,7 +99,7 @@ func ResourceNameWithDateTime(name string) string { return fmt.Sprintf("tf-acc-%s-%s", name, dateTimeTrimmed) } -//func GetTestProjectServiceAccountJson(path string) string { +// func GetTestProjectServiceAccountJson(path string) string { // var err error // json, ok := os.LookupEnv("TF_ACC_SERVICE_ACCOUNT_JSON_CONTENT") // if !ok || json == "" { @@ -153,7 +153,7 @@ func ResourceNameWithDateTime(name string) string { // return credentials.TF_ACC_TEST_PROJECT_SERVICE_ACCOUNT_TOKEN, nil //} -//func readTestServiceAccountJsonFromFile(path string) (string, error) { +// func readTestServiceAccountJsonFromFile(path string) (string, error) { // if path == "" { // customPath, ok := os.LookupEnv("TF_ACC_SERVICE_ACCOUNT_FILE") // if !ok || customPath == "" { diff --git a/stackit/internal/services/postgresflexalpha/database/datasources_gen/database_data_source_gen.go b/stackit/internal/services/postgresflexalpha/database/datasources_gen/database_data_source_gen.go index d5683a6c..f4a08793 100644 --- a/stackit/internal/services/postgresflexalpha/database/datasources_gen/database_data_source_gen.go +++ b/stackit/internal/services/postgresflexalpha/database/datasources_gen/database_data_source_gen.go @@ -45,7 +45,7 @@ func DatabaseDataSourceSchema(ctx context.Context) schema.Schema { MarkdownDescription: "The STACKIT project ID.", }, "region": schema.StringAttribute{ - Required: true, + Optional: true, Description: "The region which should be addressed", MarkdownDescription: "The region which should be addressed", Validators: []validator.String{ diff --git a/stackit/internal/services/postgresflexalpha/database/mapper.go b/stackit/internal/services/postgresflexalpha/database/mapper.go index 6ce2200c..213c262f 100644 --- a/stackit/internal/services/postgresflexalpha/database/mapper.go +++ b/stackit/internal/services/postgresflexalpha/database/mapper.go @@ -64,17 +64,21 @@ func mapResourceFields(source *v3alpha1api.GetDatabaseResponse, model *resourceM return fmt.Errorf("model input is nil") } - var databaseId int64 - if model.Id.ValueInt64() != 0 { - databaseId = model.Id.ValueInt64() + var databaseID int64 + if model.DatabaseId.ValueInt64() != 0 { + if source.Id != 0 { + if model.DatabaseId.ValueInt64() != int64(source.Id) { + return fmt.Errorf("retrieved ID does not match known ID") + } + } + databaseID = model.DatabaseId.ValueInt64() } else if source.Id != 0 { - databaseId = int64(source.Id) + databaseID = int64(source.Id) } else { return fmt.Errorf("database id not present") } - model.Id = types.Int64Value(databaseId) - model.DatabaseId = types.Int64Value(databaseId) + model.DatabaseId = types.Int64Value(databaseID) model.Name = types.StringValue(source.GetName()) model.Owner = types.StringValue(cleanString(source.Owner)) return nil diff --git a/stackit/internal/services/postgresflexalpha/database/mapper_test.go b/stackit/internal/services/postgresflexalpha/database/mapper_test.go index 684af672..30c62be1 100644 --- a/stackit/internal/services/postgresflexalpha/database/mapper_test.go +++ b/stackit/internal/services/postgresflexalpha/database/mapper_test.go @@ -160,7 +160,7 @@ func TestMapResourceFields(t *testing.T) { }, expected: expected{ model: &resourceModel{ - Id: types.Int64Value(1), + Id: types.StringNull(), Name: types.StringValue("my-db"), Owner: types.StringValue("my-owner"), DatabaseId: types.Int64Value(1), diff --git a/stackit/internal/services/postgresflexalpha/database/resource.go b/stackit/internal/services/postgresflexalpha/database/resource.go index 6db70746..fc9390e3 100644 --- a/stackit/internal/services/postgresflexalpha/database/resource.go +++ b/stackit/internal/services/postgresflexalpha/database/resource.go @@ -11,9 +11,9 @@ import ( "github.com/hashicorp/terraform-plugin-framework/path" "github.com/hashicorp/terraform-plugin-framework/resource" - "github.com/hashicorp/terraform-plugin-framework/resource/identityschema" "github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-plugin-log/tflog" + "github.com/stackitcloud/stackit-sdk-go/core/oapierror" "github.com/stackitcloud/stackit-sdk-go/services/postgresflex/v3alpha1api" "tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit/internal/conversion" @@ -30,11 +30,6 @@ var ( _ resource.ResourceWithConfigure = &databaseResource{} _ resource.ResourceWithImportState = &databaseResource{} _ resource.ResourceWithModifyPlan = &databaseResource{} - _ resource.ResourceWithIdentity = &databaseResource{} - - // Error message constants - extractErrorSummary = "extracting failed" - extractErrorMessage = "Extracting identity data: %v" ) // NewDatabaseResource is a helper function to simplify the provider implementation. @@ -45,14 +40,6 @@ func NewDatabaseResource() resource.Resource { // resourceModel describes the resource data model. type resourceModel = postgresflexalphaResGen.DatabaseModel -// DatabaseResourceIdentityModel describes the resource's identity attributes. -type DatabaseResourceIdentityModel struct { - ProjectID types.String `tfsdk:"project_id"` - Region types.String `tfsdk:"region"` - InstanceID types.String `tfsdk:"instance_id"` - DatabaseID types.Int64 `tfsdk:"database_id"` -} - // databaseResource is the resource implementation. type databaseResource struct { client *v3alpha1api.APIClient @@ -138,30 +125,6 @@ func (r *databaseResource) Schema(ctx context.Context, _ resource.SchemaRequest, resp.Schema = s } -// IdentitySchema defines the schema for the resource's identity attributes. -func (r *databaseResource) IdentitySchema( - _ context.Context, - _ resource.IdentitySchemaRequest, - response *resource.IdentitySchemaResponse, -) { - response.IdentitySchema = identityschema.Schema{ - Attributes: map[string]identityschema.Attribute{ - "project_id": identityschema.StringAttribute{ - RequiredForImport: true, - }, - "region": identityschema.StringAttribute{ - RequiredForImport: true, - }, - "instance_id": identityschema.StringAttribute{ - RequiredForImport: true, - }, - "database_id": identityschema.Int64Attribute{ - RequiredForImport: true, - }, - }, - } -} - // Create creates the resource and sets the initial Terraform state. func (r *databaseResource) Create( ctx context.Context, @@ -178,12 +141,12 @@ func (r *databaseResource) Create( ctx = core.InitProviderContext(ctx) - projectId := model.ProjectId.ValueString() + projectID := model.ProjectId.ValueString() region := model.Region.ValueString() - instanceId := model.InstanceId.ValueString() + instanceID := model.InstanceId.ValueString() - ctx = tflog.SetField(ctx, "project_id", projectId) - ctx = tflog.SetField(ctx, "instance_id", instanceId) + ctx = tflog.SetField(ctx, "project_id", projectID) + ctx = tflog.SetField(ctx, "instance_id", instanceID) ctx = tflog.SetField(ctx, "region", region) // Generate API request body from model @@ -200,9 +163,9 @@ func (r *databaseResource) Create( // Create new database databaseResp, err := r.client.DefaultAPI.CreateDatabaseRequest( ctx, - projectId, + projectID, region, - instanceId, + instanceID, ).CreateDatabaseRequestPayload(*payload).Execute() if err != nil { core.LogAndAddError(ctx, &resp.Diagnostics, funcErrorSummary, fmt.Sprintf("Calling API: %v", err)) @@ -219,23 +182,33 @@ func (r *databaseResource) Create( ) return } - databaseId := int64(*dbID) - ctx = tflog.SetField(ctx, "database_id", databaseId) + databaseID := int64(*dbID) + databaseIDString := strconv.Itoa(int(*dbID)) + + ctx = tflog.SetField(ctx, "database_id", databaseID) ctx = core.LogResponse(ctx) - // Save identity into Terraform state - identity := DatabaseResourceIdentityModel{ - ProjectID: types.StringValue(projectId), - Region: types.StringValue(region), - InstanceID: types.StringValue(instanceId), - DatabaseID: types.Int64Value(databaseId), - } - resp.Diagnostics.Append(resp.Identity.Set(ctx, identity)...) - if resp.Diagnostics.HasError() { - return - } + model.DatabaseId = types.Int64Value(databaseID) + model.Id = utils.BuildInternalTerraformId(projectID, region, instanceID, databaseIDString) - database, err := postgresflexalphaWait.GetDatabaseByIdWaitHandler(ctx, r.client.DefaultAPI, projectId, instanceId, region, databaseId). + // Set data returned by API in id + resp.Diagnostics.Append( + resp.State.SetAttribute( + ctx, + path.Root("database_id"), + databaseID, + )..., + ) + // Set data returned by API in id + resp.Diagnostics.Append( + resp.State.SetAttribute( + ctx, + path.Root("id"), + model.Id, + )..., + ) + + database, err := postgresflexalphaWait.GetDatabaseByIdWaitHandler(ctx, r.client.DefaultAPI, projectID, instanceID, region, databaseID). SetTimeout(15 * time.Minute). SetSleepBeforeWait(15 * time.Second). WaitWithContext(ctx) @@ -284,17 +257,28 @@ func (r *databaseResource) Read( ctx = core.InitProviderContext(ctx) - projectId := model.ProjectId.ValueString() - instanceId := model.InstanceId.ValueString() + projectID := model.ProjectId.ValueString() + instanceID := model.InstanceId.ValueString() region := model.Region.ValueString() - databaseId := model.DatabaseId.ValueInt64() + databaseID := model.DatabaseId.ValueInt64() - ctx = tflog.SetField(ctx, "project_id", projectId) - ctx = tflog.SetField(ctx, "instance_id", instanceId) + databaseIDString := strconv.Itoa(int(databaseID)) + + ctx = tflog.SetField(ctx, "project_id", projectID) + ctx = tflog.SetField(ctx, "instance_id", instanceID) ctx = tflog.SetField(ctx, "region", region) - ctx = tflog.SetField(ctx, "database_id", databaseId) + ctx = tflog.SetField(ctx, "database_id", databaseID) - databaseResp, err := postgresflexalphaWait.GetDatabaseByIdWaitHandler(ctx, r.client.DefaultAPI, projectId, instanceId, region, databaseId). + // Set data returned by API in id + resp.Diagnostics.Append( + resp.State.SetAttribute( + ctx, + path.Root("id"), + utils.BuildInternalTerraformId(projectID, region, instanceID, databaseIDString), + )..., + ) + + databaseResp, err := postgresflexalphaWait.GetDatabaseByIdWaitHandler(ctx, r.client.DefaultAPI, projectID, instanceID, region, databaseID). SetTimeout(15 * time.Minute). SetSleepBeforeWait(15 * time.Second). WaitWithContext(ctx) @@ -322,18 +306,6 @@ func (r *databaseResource) Read( return } - // Save identity into Terraform state - identity := DatabaseResourceIdentityModel{ - ProjectID: types.StringValue(projectId), - Region: types.StringValue(region), - InstanceID: types.StringValue(instanceId), - DatabaseID: types.Int64Value(int64(databaseResp.GetId())), - } - resp.Diagnostics.Append(resp.Identity.Set(ctx, identity)...) - if resp.Diagnostics.HasError() { - return - } - // Set refreshed state diags = resp.State.Set(ctx, model) resp.Diagnostics.Append(diags...) @@ -436,18 +408,6 @@ func (r *databaseResource) Update( return } - // Save identity into Terraform state - identity := DatabaseResourceIdentityModel{ - ProjectID: types.StringValue(projectId), - Region: types.StringValue(region), - InstanceID: types.StringValue(instanceId), - DatabaseID: types.Int64Value(databaseId), - } - resp.Diagnostics.Append(resp.Identity.Set(ctx, identity)...) - if resp.Diagnostics.HasError() { - return - } - // Set state to fully populated data resp.Diagnostics.Append(resp.State.Set(ctx, &model)...) if resp.Diagnostics.HasError() { @@ -469,38 +429,33 @@ func (r *databaseResource) Delete( return } - // Read identity data - var identityData DatabaseResourceIdentityModel - resp.Diagnostics.Append(req.Identity.Get(ctx, &identityData)...) - if resp.Diagnostics.HasError() { - return - } - ctx = core.InitProviderContext(ctx) - projectId, region, instanceId, databaseId64, errExt := r.extractIdentityData(model, identityData) - if errExt != nil { - core.LogAndAddError( - ctx, - &resp.Diagnostics, - extractErrorSummary, - fmt.Sprintf(extractErrorMessage, errExt), - ) - } + projectID := model.ProjectId.ValueString() + instanceID := model.InstanceId.ValueString() + region := model.Region.ValueString() + databaseID64 := model.DatabaseId.ValueInt64() - if databaseId64 > math.MaxInt32 { + if databaseID64 > math.MaxInt32 { core.LogAndAddError(ctx, &resp.Diagnostics, "Error in type conversion", "int value too large (databaseId)") return } - databaseId := int32(databaseId64) // nolint:gosec // check is performed above - ctx = tflog.SetField(ctx, "project_id", projectId) - ctx = tflog.SetField(ctx, "instance_id", instanceId) + databaseID := int32(databaseID64) // nolint:gosec // check is performed above + ctx = tflog.SetField(ctx, "project_id", projectID) + ctx = tflog.SetField(ctx, "instance_id", instanceID) ctx = tflog.SetField(ctx, "region", region) - ctx = tflog.SetField(ctx, "database_id", databaseId) + ctx = tflog.SetField(ctx, "database_id", databaseID) // Delete existing record set - err := r.client.DefaultAPI.DeleteDatabaseRequest(ctx, projectId, region, instanceId, databaseId).Execute() + err := r.client.DefaultAPI.DeleteDatabaseRequest(ctx, projectID, region, instanceID, databaseID).Execute() if err != nil { + oapiErr, ok := err.(*oapierror.GenericOpenAPIError) // nolint:errorlint //complaining that error.As should be used to catch wrapped errors, but this error should not be wrapped + if ok { + if oapiErr.StatusCode == 404 { + resp.State.RemoveResource(ctx) + return + } + } core.LogAndAddError(ctx, &resp.Diagnostics, "Error deleting database", fmt.Sprintf("Calling API: %v", err)) } @@ -517,109 +472,44 @@ func (r *databaseResource) ImportState( resp *resource.ImportStateResponse, ) { ctx = core.InitProviderContext(ctx) + idParts := strings.Split(req.ID, core.Separator) - if req.ID != "" { - idParts := strings.Split(req.ID, core.Separator) + if len(idParts) != 4 || idParts[0] == "" || idParts[1] == "" || idParts[2] == "" || idParts[3] == "" { + core.LogAndAddError( + ctx, &resp.Diagnostics, + "Error importing database", + fmt.Sprintf( + "Expected import identifier with format [project_id],[region],[instance_id],[database_id], got %q", + req.ID, + ), + ) + return + } - if len(idParts) != 4 || idParts[0] == "" || idParts[1] == "" || idParts[2] == "" || idParts[3] == "" { - core.LogAndAddError( - ctx, &resp.Diagnostics, - "Error importing database", - fmt.Sprintf( - "Expected import identifier with format [project_id],[region],[instance_id],[database_id], got %q", - req.ID, - ), - ) - return - } - - databaseId, err := strconv.ParseInt(idParts[3], 10, 64) - if err != nil { - core.LogAndAddError( - ctx, - &resp.Diagnostics, - "Error importing database", - fmt.Sprintf("Invalid database_id format: %q. It must be a valid integer.", idParts[3]), - ) - return - } - - resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("project_id"), idParts[0])...) - resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("region"), idParts[1])...) - resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("instance_id"), idParts[2])...) - resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("database_id"), databaseId)...) - - core.LogAndAddWarning( + databaseID, err := strconv.ParseInt(idParts[3], 10, 64) + if err != nil { + core.LogAndAddError( ctx, &resp.Diagnostics, - "Postgresflex database imported with empty password", - "The database password is not imported as it is only available upon creation of a new database. The password field will be empty.", + "Error importing database", + fmt.Sprintf("Invalid database_id format: %q. It must be a valid integer.", idParts[3]), ) - - tflog.Info(ctx, "Postgres Flex database state imported") - return } - // If no ID is provided, attempt to read identity attributes from the import configuration - var identityData DatabaseResourceIdentityModel - resp.Diagnostics.Append(req.Identity.Get(ctx, &identityData)...) - if resp.Diagnostics.HasError() { - return - } + tfIDString := utils.BuildInternalTerraformId(idParts...).ValueString() + resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("id"), tfIDString)...) + resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("project_id"), idParts[0])...) + resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("region"), idParts[1])...) + resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("instance_id"), idParts[2])...) + resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("database_id"), databaseID)...) - projectId := identityData.ProjectID.ValueString() - region := identityData.Region.ValueString() - instanceId := identityData.InstanceID.ValueString() - databaseId := identityData.DatabaseID.ValueInt64() - - resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("project_id"), projectId)...) - resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("region"), region)...) - resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("instance_id"), instanceId)...) - resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("database_id"), databaseId)...) + core.LogAndAddWarning( + ctx, + &resp.Diagnostics, + "Postgresflex database imported with empty password", + "The database password is not imported as it is only available upon creation of a new database. The password field will be empty.", + ) tflog.Info(ctx, "Postgres Flex database state imported") } - -// extractIdentityData extracts essential identifiers from the resource model, falling back to the identity model. -func (r *databaseResource) extractIdentityData( - model resourceModel, - identity DatabaseResourceIdentityModel, -) (projectId, region, instanceId string, databaseId int64, err error) { - if !model.DatabaseId.IsNull() && !model.DatabaseId.IsUnknown() { - databaseId = model.DatabaseId.ValueInt64() - } else { - if identity.DatabaseID.IsNull() || identity.DatabaseID.IsUnknown() { - return "", "", "", 0, fmt.Errorf("database_id not found in config") - } - databaseId = identity.DatabaseID.ValueInt64() - } - - if !model.ProjectId.IsNull() && !model.ProjectId.IsUnknown() { - projectId = model.ProjectId.ValueString() - } else { - if identity.ProjectID.IsNull() || identity.ProjectID.IsUnknown() { - return "", "", "", 0, fmt.Errorf("project_id not found in config") - } - projectId = identity.ProjectID.ValueString() - } - - if !model.Region.IsNull() && !model.Region.IsUnknown() { - region = r.providerData.GetRegionWithOverride(model.Region) - } else { - if identity.Region.IsNull() || identity.Region.IsUnknown() { - return "", "", "", 0, fmt.Errorf("region not found in config") - } - region = r.providerData.GetRegionWithOverride(identity.Region) - } - - if !model.InstanceId.IsNull() && !model.InstanceId.IsUnknown() { - instanceId = model.InstanceId.ValueString() - } else { - if identity.InstanceID.IsNull() || identity.InstanceID.IsUnknown() { - return "", "", "", 0, fmt.Errorf("instance_id not found in config") - } - instanceId = identity.InstanceID.ValueString() - } - return projectId, region, instanceId, databaseId, nil -} diff --git a/stackit/internal/services/postgresflexalpha/database/resources_gen/database_resource_gen.go b/stackit/internal/services/postgresflexalpha/database/resources_gen/database_resource_gen.go index 6affc956..fe8871a2 100644 --- a/stackit/internal/services/postgresflexalpha/database/resources_gen/database_resource_gen.go +++ b/stackit/internal/services/postgresflexalpha/database/resources_gen/database_resource_gen.go @@ -20,7 +20,7 @@ func DatabaseResourceSchema(ctx context.Context) schema.Schema { Description: "The ID of the database.", MarkdownDescription: "The ID of the database.", }, - "id": schema.Int64Attribute{ + "id": schema.StringAttribute{ Computed: true, Description: "The id of the database.", MarkdownDescription: "The id of the database.", @@ -65,7 +65,7 @@ func DatabaseResourceSchema(ctx context.Context) schema.Schema { type DatabaseModel struct { DatabaseId types.Int64 `tfsdk:"database_id"` - Id types.Int64 `tfsdk:"id"` + Id types.String `tfsdk:"id"` InstanceId types.String `tfsdk:"instance_id"` Name types.String `tfsdk:"name"` Owner types.String `tfsdk:"owner"` diff --git a/stackit/internal/services/postgresflexalpha/instance/datasource.go b/stackit/internal/services/postgresflexalpha/instance/datasource.go index cd7048e3..edb1a9a9 100644 --- a/stackit/internal/services/postgresflexalpha/instance/datasource.go +++ b/stackit/internal/services/postgresflexalpha/instance/datasource.go @@ -5,6 +5,7 @@ import ( "fmt" "net/http" + "github.com/hashicorp/terraform-plugin-framework/datasource/schema" "github.com/hashicorp/terraform-plugin-framework/types" "github.com/stackitcloud/stackit-sdk-go/services/postgresflex/v3alpha1api" @@ -72,7 +73,13 @@ func (r *instanceDataSource) Configure( // Schema defines the schema for the data source. func (r *instanceDataSource) Schema(ctx context.Context, _ datasource.SchemaRequest, resp *datasource.SchemaResponse) { - resp.Schema = postgresflexalpha2.InstanceDataSourceSchema(ctx) + sch := postgresflexalpha2.InstanceDataSourceSchema(ctx) + sch.Attributes["id"] = schema.StringAttribute{ + Computed: true, + Description: "internal ID", + MarkdownDescription: "internal ID", + } + resp.Schema = sch } // Read refreshes the Terraform state with the latest data. @@ -90,22 +97,22 @@ func (r *instanceDataSource) Read( ctx = core.InitProviderContext(ctx) - projectId := model.ProjectId.ValueString() - instanceId := model.InstanceId.ValueString() + 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, "project_id", projectID) + ctx = tflog.SetField(ctx, "instance_id", instanceID) ctx = tflog.SetField(ctx, "region", region) - instanceResp, err := r.client.DefaultAPI.GetInstanceRequest(ctx, projectId, region, instanceId).Execute() + instanceResp, err := r.client.DefaultAPI.GetInstanceRequest(ctx, projectID, region, instanceID).Execute() if err != nil { utils.LogError( ctx, &resp.Diagnostics, err, "Reading instance", - fmt.Sprintf("Instance with ID %q does not exist in project %q.", instanceId, projectId), + fmt.Sprintf("Instance with ID %q does not exist in project %q.", instanceID, projectID), map[int]string{ - http.StatusForbidden: fmt.Sprintf("Project with ID %q not found or forbidden access", projectId), + http.StatusForbidden: fmt.Sprintf("Project with ID %q not found or forbidden access", projectID), }, ) resp.State.RemoveResource(ctx) diff --git a/stackit/internal/services/postgresflexalpha/instance/datasources_gen/instance_data_source_gen.go b/stackit/internal/services/postgresflexalpha/instance/datasources_gen/instance_data_source_gen.go index 58f88e01..9b3e28ce 100644 --- a/stackit/internal/services/postgresflexalpha/instance/datasources_gen/instance_data_source_gen.go +++ b/stackit/internal/services/postgresflexalpha/instance/datasources_gen/instance_data_source_gen.go @@ -155,7 +155,7 @@ func InstanceDataSourceSchema(ctx context.Context) schema.Schema { MarkdownDescription: "The STACKIT project ID.", }, "region": schema.StringAttribute{ - Required: true, + Optional: true, Description: "The region which should be addressed", MarkdownDescription: "The region which should be addressed", Validators: []validator.String{ diff --git a/stackit/internal/services/postgresflexalpha/instance/functions.go b/stackit/internal/services/postgresflexalpha/instance/functions.go index 6e7164b9..1eb10d32 100644 --- a/stackit/internal/services/postgresflexalpha/instance/functions.go +++ b/stackit/internal/services/postgresflexalpha/instance/functions.go @@ -55,23 +55,21 @@ func mapGetInstanceResponseToModel( } m.FlavorId = types.StringValue(resp.GetFlavorId()) - if m.Id.IsNull() || m.Id.IsUnknown() { - m.Id = utils.BuildInternalTerraformId( - m.ProjectId.ValueString(), - m.Region.ValueString(), - m.InstanceId.ValueString(), - ) - } + m.Id = utils.BuildInternalTerraformId( + m.ProjectId.ValueString(), + m.Region.ValueString(), + resp.Id, + ) m.InstanceId = types.StringValue(resp.Id) m.IsDeletable = types.BoolValue(resp.GetIsDeletable()) - netAcl, diags := types.ListValueFrom(ctx, types.StringType, resp.Network.GetAcl()) + netACL, diags := types.ListValueFrom(ctx, types.StringType, resp.Network.GetAcl()) if diags.HasError() { return fmt.Errorf("failed converting network acl from response") } - m.Acl = netAcl + m.Acl = netACL netInstAdd := types.StringValue("") if instAdd, ok := resp.Network.GetInstanceAddressOk(); ok { @@ -87,7 +85,7 @@ func mapGetInstanceResponseToModel( postgresflexalpharesource.NetworkValue{}.AttributeTypes(ctx), map[string]attr.Value{ "access_scope": basetypes.NewStringValue(string(resp.Network.GetAccessScope())), - "acl": netAcl, + "acl": netACL, "instance_address": netInstAdd, "router_address": netRtrAdd, }, @@ -130,7 +128,8 @@ func mapGetDataInstanceResponseToModel( handleConnectionInfo(ctx, m, resp) m.FlavorId = types.StringValue(resp.GetFlavorId()) - m.Id = utils.BuildInternalTerraformId(m.ProjectId.ValueString(), m.Region.ValueString(), m.InstanceId.ValueString()) + m.Id = types.StringValue(resp.Id) + m.TerraformID = utils.BuildInternalTerraformId(m.ProjectId.ValueString(), m.Region.ValueString(), m.InstanceId.ValueString()) m.InstanceId = types.StringValue(resp.Id) m.IsDeletable = types.BoolValue(resp.GetIsDeletable()) m.Name = types.StringValue(resp.GetName()) @@ -212,14 +211,14 @@ func handleNetwork(ctx context.Context, m *dataSourceModel, resp *postgresflex.G } func handleEncryption(m *dataSourceModel, resp *postgresflex.GetInstanceResponse) { - keyId := "" - if keyIdVal, ok := resp.Encryption.GetKekKeyIdOk(); ok { - keyId = *keyIdVal + keyID := "" + if keyIDVal, ok := resp.Encryption.GetKekKeyIdOk(); ok { + keyID = *keyIDVal } - keyRingId := "" - if keyRingIdVal, ok := resp.Encryption.GetKekKeyRingIdOk(); ok { - keyRingId = *keyRingIdVal + keyRingID := "" + if keyRingIDVal, ok := resp.Encryption.GetKekKeyRingIdOk(); ok { + keyRingID = *keyRingIDVal } keyVersion := "" @@ -233,8 +232,8 @@ func handleEncryption(m *dataSourceModel, resp *postgresflex.GetInstanceResponse } m.Encryption = postgresflexalphadatasource.EncryptionValue{ - KekKeyId: types.StringValue(keyId), - KekKeyRingId: types.StringValue(keyRingId), + KekKeyId: types.StringValue(keyID), + KekKeyRingId: types.StringValue(keyRingID), KekKeyVersion: types.StringValue(keyVersion), ServiceAccount: types.StringValue(svcAcc), } diff --git a/stackit/internal/services/postgresflexalpha/instance/resource.go b/stackit/internal/services/postgresflexalpha/instance/resource.go index d07bf546..b6a6bfa7 100644 --- a/stackit/internal/services/postgresflexalpha/instance/resource.go +++ b/stackit/internal/services/postgresflexalpha/instance/resource.go @@ -7,11 +7,10 @@ import ( "math" "net/http" "strings" + "time" "github.com/hashicorp/terraform-plugin-framework/path" "github.com/hashicorp/terraform-plugin-framework/resource" - "github.com/hashicorp/terraform-plugin-framework/resource/identityschema" - "github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-plugin-log/tflog" "github.com/stackitcloud/stackit-sdk-go/core/oapierror" coreUtils "github.com/stackitcloud/stackit-sdk-go/core/utils" @@ -32,7 +31,6 @@ var ( _ resource.ResourceWithImportState = &instanceResource{} _ resource.ResourceWithModifyPlan = &instanceResource{} _ resource.ResourceWithValidateConfig = &instanceResource{} - _ resource.ResourceWithIdentity = &instanceResource{} ) // NewInstanceResource is a helper function to simplify the provider implementation. @@ -40,15 +38,6 @@ func NewInstanceResource() resource.Resource { return &instanceResource{} } -// resourceModel describes the resource data model. -type resourceModel = postgresflexalpha.InstanceModel - -type InstanceResourceIdentityModel struct { - ProjectID types.String `tfsdk:"project_id"` - Region types.String `tfsdk:"region"` - InstanceID types.String `tfsdk:"instance_id"` -} - // instanceResource is the resource implementation. type instanceResource struct { client *v3alpha1api.APIClient @@ -60,7 +49,7 @@ func (r *instanceResource) ValidateConfig( req resource.ValidateConfigRequest, resp *resource.ValidateConfigResponse, ) { - var data resourceModel + var data postgresflexalpha.InstanceModel resp.Diagnostics.Append(req.Config.Get(ctx, &data)...) if resp.Diagnostics.HasError() { @@ -84,7 +73,7 @@ func (r *instanceResource) ModifyPlan( req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse, ) { // nolint:gocritic // function signature required by Terraform - var configModel resourceModel + var configModel postgresflexalpha.InstanceModel // skip initial empty configuration to avoid follow-up errors if req.Config.Raw.IsNull() { return @@ -94,7 +83,7 @@ func (r *instanceResource) ModifyPlan( return } - var planModel resourceModel + var planModel postgresflexalpha.InstanceModel resp.Diagnostics.Append(req.Plan.Get(ctx, &planModel)...) if resp.Diagnostics.HasError() { return @@ -160,33 +149,13 @@ func (r *instanceResource) Schema(ctx context.Context, _ resource.SchemaRequest, resp.Schema = schema } -func (r *instanceResource) IdentitySchema( - _ context.Context, - _ resource.IdentitySchemaRequest, - resp *resource.IdentitySchemaResponse, -) { - resp.IdentitySchema = identityschema.Schema{ - Attributes: map[string]identityschema.Attribute{ - "project_id": identityschema.StringAttribute{ - RequiredForImport: true, // must be set during import by the practitioner - }, - "region": identityschema.StringAttribute{ - RequiredForImport: true, // can be defaulted by the provider configuration - }, - "instance_id": identityschema.StringAttribute{ - RequiredForImport: true, // can be defaulted by the provider configuration - }, - }, - } -} - // 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 - var model resourceModel + var model postgresflexalpha.InstanceModel diags := req.Plan.Get(ctx, &model) resp.Diagnostics.Append(diags...) @@ -201,15 +170,15 @@ func (r *instanceResource) Create( ctx = tflog.SetField(ctx, "project_id", projectID) ctx = tflog.SetField(ctx, "region", region) - var netAcl []string - diag := model.Network.Acl.ElementsAs(ctx, &netAcl, false) + var netACL []string + diag := model.Network.Acl.ElementsAs(ctx, &netACL, false) resp.Diagnostics.Append(diags...) if diag.HasError() { return } replVal := model.Replicas.ValueInt64() // nolint:gosec // check is performed above - payload := modelToCreateInstancePayload(netAcl, model, replVal) + payload := modelToCreateInstancePayload(netACL, model, replVal) // Create new instance createResp, err := r.client.DefaultAPI.CreateInstanceRequest( @@ -229,18 +198,18 @@ func (r *instanceResource) Create( return } - // Set data returned by API in identity - identity := InstanceResourceIdentityModel{ - ProjectID: types.StringValue(projectID), - Region: types.StringValue(region), - InstanceID: types.StringPointerValue(instanceID), - } - resp.Diagnostics.Append(resp.Identity.Set(ctx, identity)...) - if resp.Diagnostics.HasError() { - return - } + // Set data returned by API in id + resp.Diagnostics.Append( + resp.State.SetAttribute( + ctx, + path.Root("id"), + utils.BuildInternalTerraformId(projectID, region, *instanceID), + )..., + ) waitResp, err := wait.CreateInstanceWaitHandler(ctx, r.client.DefaultAPI, projectID, region, *instanceID). + SetTimeout(30 * time.Minute). + SetSleepBeforeWait(10 * time.Second). WaitWithContext(ctx) if err != nil { core.LogAndAddError( @@ -314,7 +283,7 @@ func (r *instanceResource) Read( ) { // nolint:gocritic // function signature required by Terraform functionErrorSummary := "read instance failed" - var model resourceModel + var model postgresflexalpha.InstanceModel diags := req.State.Get(ctx, &model) resp.Diagnostics.Append(diags...) if resp.Diagnostics.HasError() { @@ -323,9 +292,9 @@ func (r *instanceResource) Read( ctx = core.InitProviderContext(ctx) - var projectId string + var projectID string if !model.ProjectId.IsNull() && !model.ProjectId.IsUnknown() { - projectId = model.ProjectId.ValueString() + projectID = model.ProjectId.ValueString() } var region string @@ -333,16 +302,16 @@ func (r *instanceResource) Read( region = r.providerData.GetRegionWithOverride(model.Region) } - var instanceId string + var instanceID string if !model.InstanceId.IsNull() && !model.InstanceId.IsUnknown() { - instanceId = model.InstanceId.ValueString() + instanceID = model.InstanceId.ValueString() } - ctx = tflog.SetField(ctx, "project_id", projectId) - ctx = tflog.SetField(ctx, "instance_id", instanceId) + 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.GetInstanceRequest(ctx, projectId, region, instanceId).Execute() + instanceResp, err := r.client.DefaultAPI.GetInstanceRequest(ctx, projectID, region, instanceID).Execute() if err != nil { oapiErr, ok := err.(*oapierror.GenericOpenAPIError) //nolint:errorlint //complaining that error.As should be used to catch wrapped errors, but this error should not be wrapped if ok && oapiErr.StatusCode == http.StatusNotFound { @@ -361,7 +330,7 @@ func (r *instanceResource) Read( return } if !model.InstanceId.IsUnknown() && !model.InstanceId.IsNull() { - if *respInstanceID != instanceId { + if *respInstanceID != instanceID { core.LogAndAddError( ctx, &resp.Diagnostics, @@ -372,6 +341,10 @@ func (r *instanceResource) Read( } } + if model.Id.IsUnknown() || model.Id.IsNull() { + model.Id = utils.BuildInternalTerraformId(projectID, region, instanceID) + } + err = mapGetInstanceResponseToModel(ctx, &model, instanceResp) if err != nil { core.LogAndAddError( @@ -389,17 +362,6 @@ func (r *instanceResource) Read( return } - // Set data returned by API in identity - identity := InstanceResourceIdentityModel{ - ProjectID: types.StringValue(projectId), - Region: types.StringValue(region), - InstanceID: types.StringValue(instanceId), - } - resp.Diagnostics.Append(resp.Identity.Set(ctx, identity)...) - if resp.Diagnostics.HasError() { - return - } - tflog.Info(ctx, "Postgres Flex instance read") } @@ -409,7 +371,7 @@ func (r *instanceResource) Update( req resource.UpdateRequest, resp *resource.UpdateResponse, ) { // nolint:gocritic // function signature required by Terraform - var model resourceModel + var model postgresflexalpha.InstanceModel diags := req.Plan.Get(ctx, &model) resp.Diagnostics.Append(diags...) @@ -419,15 +381,8 @@ func (r *instanceResource) Update( ctx = core.InitProviderContext(ctx) - // Read identity data - var identityData InstanceResourceIdentityModel - resp.Diagnostics.Append(req.Identity.Get(ctx, &identityData)...) - if resp.Diagnostics.HasError() { - return - } - - projectID := identityData.ProjectID.ValueString() - instanceID := identityData.InstanceID.ValueString() + projectID := model.ProjectId.ValueString() + instanceID := model.InstanceId.ValueString() region := model.Region.ValueString() ctx = tflog.SetField(ctx, "project_id", projectID) ctx = tflog.SetField(ctx, "instance_id", instanceID) @@ -490,7 +445,10 @@ func (r *instanceResource) Update( projectID, region, instanceID, - ).WaitWithContext(ctx) + ). + SetTimeout(30 * time.Minute). + SetSleepBeforeWait(10 * time.Second). + WaitWithContext(ctx) if err != nil { core.LogAndAddError( ctx, @@ -526,7 +484,7 @@ func (r *instanceResource) Delete( req resource.DeleteRequest, resp *resource.DeleteResponse, ) { // nolint:gocritic // function signature required by Terraform - var model resourceModel + var model postgresflexalpha.InstanceModel diags := req.State.Get(ctx, &model) resp.Diagnostics.Append(diags...) @@ -536,15 +494,15 @@ func (r *instanceResource) Delete( ctx = core.InitProviderContext(ctx) - projectId := model.ProjectId.ValueString() - instanceId := model.InstanceId.ValueString() + projectID := model.ProjectId.ValueString() + instanceID := model.InstanceId.ValueString() region := model.Region.ValueString() - ctx = tflog.SetField(ctx, "project_id", projectId) - ctx = tflog.SetField(ctx, "instance_id", instanceId) + 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.DeleteInstanceRequest(ctx, projectId, region, instanceId).Execute() + err := r.client.DefaultAPI.DeleteInstanceRequest(ctx, projectID, region, instanceID).Execute() if err != nil { core.LogAndAddError(ctx, &resp.Diagnostics, "Error deleting instance", fmt.Sprintf("Calling API: %v", err)) return @@ -552,7 +510,7 @@ func (r *instanceResource) Delete( ctx = core.LogResponse(ctx) - _, err = r.client.DefaultAPI.GetInstanceRequest(ctx, projectId, region, instanceId).Execute() + _, err = r.client.DefaultAPI.GetInstanceRequest(ctx, projectID, region, instanceID).Execute() if err != nil { oapiErr, ok := err.(*oapierror.GenericOpenAPIError) //nolint:errorlint //complaining that error.As should be used to catch wrapped errors, but this error should not be wrapped if ok && oapiErr.StatusCode != http.StatusNotFound { @@ -574,41 +532,30 @@ func (r *instanceResource) ImportState( ) { ctx = core.InitProviderContext(ctx) - if req.ID != "" { - idParts := strings.Split(req.ID, core.Separator) + idParts := strings.Split(req.ID, core.Separator) - if len(idParts) != 3 || idParts[0] == "" || idParts[1] == "" || idParts[2] == "" { - core.LogAndAddError( - ctx, &resp.Diagnostics, - "Error importing instance", - fmt.Sprintf( - "Expected import identifier with format [project_id],[region],[instance_id] Got: %q", - req.ID, - ), - ) - return - } - - resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("project_id"), idParts[0])...) - resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("region"), idParts[1])...) - resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("instance_id"), idParts[2])...) + if len(idParts) != 3 || idParts[0] == "" || idParts[1] == "" || idParts[2] == "" { + core.LogAndAddError( + ctx, &resp.Diagnostics, + "Error importing instance", + fmt.Sprintf( + "Expected import identifier with format [project_id],[region],[instance_id] Got: %q", + req.ID, + ), + ) return } - // If no ID is provided, attempt to read identity attributes from the import configuration - var identityData InstanceResourceIdentityModel - resp.Diagnostics.Append(req.Identity.Get(ctx, &identityData)...) - if resp.Diagnostics.HasError() { - return - } - - projectId := identityData.ProjectID.ValueString() - region := identityData.Region.ValueString() - instanceId := identityData.InstanceID.ValueString() - - resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("project_id"), projectId)...) - resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("region"), region)...) - resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("instance_id"), instanceId)...) + resp.Diagnostics.Append( + resp.State.SetAttribute( + ctx, + path.Root("id"), + utils.BuildInternalTerraformId(idParts...), + )..., + ) + resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("project_id"), idParts[0])...) + resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("region"), idParts[1])...) + resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("instance_id"), idParts[2])...) tflog.Info(ctx, "Postgres Flex instance state imported") } diff --git a/stackit/internal/services/postgresflexalpha/postgresflex_acc_test.go b/stackit/internal/services/postgresflexalpha/postgresflex_acc_test.go index b5707376..874556e2 100644 --- a/stackit/internal/services/postgresflexalpha/postgresflex_acc_test.go +++ b/stackit/internal/services/postgresflexalpha/postgresflex_acc_test.go @@ -7,14 +7,20 @@ import ( "log" "math" "os" + "regexp" "strconv" "strings" "testing" "time" + "github.com/hashicorp/terraform-plugin-testing/compare" "github.com/hashicorp/terraform-plugin-testing/helper/acctest" "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/hashicorp/terraform-plugin-testing/knownvalue" + "github.com/hashicorp/terraform-plugin-testing/plancheck" + "github.com/hashicorp/terraform-plugin-testing/statecheck" "github.com/hashicorp/terraform-plugin-testing/terraform" + "github.com/hashicorp/terraform-plugin-testing/tfjsonpath" "github.com/stackitcloud/stackit-sdk-go/core/config" "github.com/stackitcloud/stackit-sdk-go/core/utils" "github.com/stackitcloud/stackit-sdk-go/services/postgresflex/v3alpha1api" @@ -30,7 +36,13 @@ import ( fwresource "github.com/hashicorp/terraform-plugin-framework/resource" ) -const pfx = "stackitprivatepreview_postgresflexalpha" +const ( + pfx = "stackitprivatepreview_postgresflexalpha" + dataPfx = "data.stackitprivatepreview_postgresflexalpha" + + singleFlavorID = "2.4" + replicasFlavorID = "2.4-replica" +) func TestInstanceResourceSchema(t *testing.T) { // t.Parallel() @@ -83,12 +95,13 @@ type resData struct { PerformanceClass string Replicas uint32 Size uint32 - ACLString string + ACLStrings []string AccessScope string RetentionDays uint32 Version string Users []User Databases []Database + DataSourceTest bool } type User struct { @@ -111,14 +124,14 @@ func getExample() resData { ProjectID: os.Getenv("TF_ACC_PROJECT_ID"), Name: name, TfName: name, - FlavorID: "2.4", + FlavorID: singleFlavorID, BackupSchedule: "0 0 * * *", UseEncryption: false, RetentionDays: 33, Replicas: 1, PerformanceClass: "premium-perf2-stackit", Size: 10, - ACLString: "0.0.0.0/0", + ACLStrings: []string{"0.0.0.0/0"}, AccessScope: "PUBLIC", Version: "17", } @@ -126,6 +139,7 @@ func getExample() resData { func TestAccInstance(t *testing.T) { exData := getExample() + exData.Version = "16" updNameData := exData updNameData.Name = "name-updated" @@ -137,149 +151,238 @@ func TestAccInstance(t *testing.T) { // api should complain about more than one daily backup updBackupSched.BackupSchedule = "30 3 * * *" - /* - { - "backupSchedule": "6 6 * * *", - "flavorId": "1.2", - "name": "postgres-instance", - "network": { - "acl": [ - "198.51.100.0/24" - ] - }, - "replicas": 1, - "retentionDays": 35, - "storage": { - "size": 10 - }, - "version": "string" - } - */ + updNetACL := updBackupSched + updNetACL.ACLStrings = append(updNetACL.ACLStrings, "192.168.0.0/24") + + updVersion := updNetACL + updVersion.Version = "17" testItemID := testutils.ResStr(pfx, "instance", exData.TfName) - + compareValuesSame := statecheck.CompareValue(compare.ValuesSame()) resource.ParallelTest( t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) - t.Logf(" ... working on instance %s", exData.TfName) + t.Logf(" ... %s - %s", t.Name(), exData.TfName) }, CheckDestroy: testAccCheckPostgresFlexDestroy, ProtoV6ProviderFactories: testutils.TestAccProtoV6ProviderFactories, Steps: []resource.TestStep{ // Create and verify { - //PreConfig: func() { - // // - // }, + PreConfig: func() { + t.Logf("testing: %s - %s", t.Name(), "create and verify") + }, Config: testutils.StringFromTemplateMust( "testdata/instance_template.gompl", exData, ), - Check: resource.ComposeAggregateTestCheckFunc( - // check params acl count - resource.TestCheckResourceAttr(testItemID, "acl.#", "1"), - - // check params are set - resource.TestCheckResourceAttrSet(testItemID, "backup_schedule"), - - //// connection_info should contain 1 sub entry - // resource.TestCheckResourceAttr(testItemID, "connection_info.%", "1"), - // - //// connection_info.write should contain 2 sub entries - // resource.TestCheckResourceAttr(testItemID, "connection_info.write", "2"), - // - // resource.TestCheckResourceAttrSet(testItemID, "connection_info.write.host"), - // resource.TestCheckResourceAttrSet(testItemID, "connection_info.write.port"), - - resource.TestCheckResourceAttrSet(testItemID, "flavor_id"), - resource.TestCheckResourceAttrSet(testItemID, "id"), - resource.TestCheckResourceAttrSet(testItemID, "instance_id"), - resource.TestCheckResourceAttrSet(testItemID, "is_deletable"), - resource.TestCheckResourceAttrSet(testItemID, "name"), - - // network should contain 4 sub entries - resource.TestCheckResourceAttr(testItemID, "network.%", "4"), - - resource.TestCheckResourceAttrSet(testItemID, "network.access_scope"), - - // on unencrypted instances we expect this to be empty - resource.TestCheckResourceAttr(testItemID, "network.instance_address", ""), - resource.TestCheckResourceAttr(testItemID, "network.router_address", ""), - - // only one acl entry should be set - resource.TestCheckResourceAttr(testItemID, "network.acl.#", "1"), - - resource.TestCheckResourceAttrSet(testItemID, "replicas"), - resource.TestCheckResourceAttrSet(testItemID, "retention_days"), - resource.TestCheckResourceAttrSet(testItemID, "status"), - - // storage should contain 2 sub entries - resource.TestCheckResourceAttr(testItemID, "storage.%", "2"), - - resource.TestCheckResourceAttrSet(testItemID, "storage.performance_class"), - resource.TestCheckResourceAttrSet(testItemID, "storage.size"), - resource.TestCheckResourceAttrSet(testItemID, "version"), - - // check absent attr - resource.TestCheckNoResourceAttr(testItemID, "encryption"), - resource.TestCheckNoResourceAttr(testItemID, "encryption.kek_key_id"), - resource.TestCheckNoResourceAttr(testItemID, "encryption.kek_key_ring_id"), - resource.TestCheckNoResourceAttr(testItemID, "encryption.kek_key_version"), - resource.TestCheckNoResourceAttr(testItemID, "encryption.service_account"), - - // check param values - resource.TestCheckResourceAttr(testItemID, "name", exData.Name), + ConfigStateChecks: []statecheck.StateCheck{ + compareValuesSame.AddStateValue( + testItemID, + tfjsonpath.New("id"), + ), + statecheck.ExpectKnownValue( + testItemID, + tfjsonpath.New("is_deletable"), + knownvalue.Bool(true), + ), + statecheck.ExpectKnownValue( + testItemID, + tfjsonpath.New("connection_info"), + knownvalue.MapExact(map[string]knownvalue.Check{ + "write": knownvalue.MapExact(map[string]knownvalue.Check{ + "host": knownvalue.StringRegexp(regexp.MustCompile("[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}.postgresql.[a-z0-9]+.onstackit.cloud")), + "port": knownvalue.Int32Func(func(v int32) error { + if v < 0 { + return fmt.Errorf("value is negative") + } + if v <= 1024 { + return fmt.Errorf("value uses protected port range") + } + return nil + }), + }), + }), + ), + }, + Check: defaultNoEncInstanceTestChecks(testItemID, exData), + }, + // Second apply should not have changes + { + PreConfig: func() { + t.Logf(" ... %s - %s", t.Name(), "second apply") + }, + Config: testutils.StringFromTemplateMust( + "testdata/instance_template.gompl", + exData, ), + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectEmptyPlan(), + }, + }, + ConfigStateChecks: []statecheck.StateCheck{ + compareValuesSame.AddStateValue( + testItemID, + tfjsonpath.New("id"), + ), + statecheck.ExpectKnownValue( + testItemID, + tfjsonpath.New("is_deletable"), + knownvalue.Bool(true), + ), + }, + }, + // Refresh state test + { + PreConfig: func() { + t.Logf(" ... %s - %s", t.Name(), "refresh state") + }, + RefreshState: true, }, // Update name and verify { + PreConfig: func() { + t.Logf(" ... %s - %s", t.Name(), "update name") + }, Config: testutils.StringFromTemplateMust( "testdata/instance_template.gompl", updNameData, ), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr( - testutils.ResStr(pfx, "instance", exData.TfName), + testItemID, "name", updNameData.Name, ), ), + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectNonEmptyPlan(), + }, + }, }, // Update size and verify { + PreConfig: func() { + t.Logf(" ... %s - %s", t.Name(), "update storage.size") + }, Config: testutils.StringFromTemplateMust( "testdata/instance_template.gompl", updSizeData, ), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr( - testutils.ResStr(pfx, "instance", exData.TfName), + testItemID, "storage.size", strconv.Itoa(int(updSizeData.Size)), ), + // network should contain 4 sub entries + resource.TestCheckResourceAttr(testItemID, "network.acl.#", "1"), ), }, // Update backup schedule { + PreConfig: func() { + t.Logf(" ... %s - %s", t.Name(), "update backup schedule") + }, Config: testutils.StringFromTemplateMust( "testdata/instance_template.gompl", updBackupSched, ), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr( - testutils.ResStr(pfx, "instance", exData.TfName), + testItemID, "backup_schedule", updBackupSched.BackupSchedule, ), + // network should contain 4 sub entries + resource.TestCheckResourceAttr(testItemID, "network.acl.#", "1"), ), }, - //// Import test - //{ - // ResourceName: "example_resource.test", - // ImportState: true, - // ImportStateVerify: true, - // }, + // Update network ACL + { + PreConfig: func() { + t.Logf(" ... %s - %s", t.Name(), "update network.acl") + }, + Config: testutils.StringFromTemplateMust( + "testdata/instance_template.gompl", + updNetACL, + ), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr( + testItemID, + "backup_schedule", + updBackupSched.BackupSchedule, + ), + // network should contain 4 sub entries + resource.TestCheckResourceAttr(testItemID, "network.acl.#", "2"), + ), + }, + // Update version + { + PreConfig: func() { + t.Logf(" ... %s - %s", t.Name(), "update version") + }, + Config: testutils.StringFromTemplateMust( + "testdata/instance_template.gompl", + updVersion, + ), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr( + testItemID, + "version", + updVersion.Version, + ), + ), + }, + // Import test + // test instance imports + { + PreConfig: func() { + t.Logf(" ... %s - %s", t.Name(), "import instance") + }, + ResourceName: testItemID, + // ImportStateIdPrefix: "", + // ImportStateVerifyIdentifierAttribute: "id", + ImportStateIdFunc: getInstanceTestID(exData.TfName), + ImportStateKind: resource.ImportCommandWithID, + ImportState: true, + ImportStateVerify: true, + }, + }, + }, + ) +} + +func TestAccInstanceHA(t *testing.T) { + data := getExample() + data.FlavorID = replicasFlavorID + data.Replicas = 3 + + testItemID := testutils.ResStr(pfx, "instance", data.TfName) + + resource.ParallelTest( + t, resource.TestCase{ + PreCheck: func() { + testAccPreCheck(t) + t.Logf(" ... %s - %s", t.Name(), data.TfName) + }, + CheckDestroy: testAccCheckPostgresFlexDestroy, + ProtoV6ProviderFactories: testutils.TestAccProtoV6ProviderFactories, + Steps: []resource.TestStep{ + // Create and verify + { + PreConfig: func() { + t.Logf(" ... %s - %s", t.Name(), "create and verify") + }, + Config: testutils.StringFromTemplateMust( + "testdata/instance_template.gompl", + data, + ), + Check: defaultNoEncInstanceTestChecks(testItemID, data), + }, }, }, ) @@ -297,30 +400,34 @@ func TestAccInstanceWithUsers(t *testing.T) { }, } + testItemID := testutils.ResStr(pfx, "instance", data.TfName) + // TODO : implement check multiple users + testUserItemID := testutils.ResStr(pfx, "user", userName) + resource.ParallelTest( t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) - t.Logf(" ... working on instance %s", data.TfName) + t.Logf(" ... %s - %s", t.Name(), data.TfName) }, CheckDestroy: testAccCheckPostgresFlexDestroy, ProtoV6ProviderFactories: testutils.TestAccProtoV6ProviderFactories, Steps: []resource.TestStep{ // Create and verify { + PreConfig: func() { + t.Logf(" ... %s - %s", t.Name(), "create and verify") + }, Config: testutils.StringFromTemplateMust( "testdata/instance_template.gompl", data, ), Check: resource.ComposeAggregateTestCheckFunc( - resource.TestCheckResourceAttr( - testutils.ResStr(pfx, "instance", data.TfName), - "name", - data.Name, - ), - resource.TestCheckResourceAttrSet(testutils.ResStr(pfx, "instance", data.TfName), "id"), - resource.TestCheckResourceAttr(testutils.ResStr(pfx, "user", userName), "name", userName), - resource.TestCheckResourceAttrSet(testutils.ResStr(pfx, "user", userName), "id"), + defaultNoEncInstanceTestChecks(testItemID, data), + + resource.TestCheckResourceAttr(testUserItemID, "name", userName), + resource.TestCheckResourceAttrSet(testUserItemID, "id"), + resource.TestCheckResourceAttr(testUserItemID, "roles.#", "1"), ), }, }, @@ -348,36 +455,185 @@ func TestAccInstanceWithDatabases(t *testing.T) { Owner: userName, }, } + data.DataSourceTest = true + testItemID := testutils.ResStr(pfx, "instance", data.TfName) resource.ParallelTest( t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) - t.Logf(" ... working on instance %s", data.TfName) + t.Logf(" ... %s - %s", t.Name(), data.TfName) }, CheckDestroy: testAccCheckPostgresFlexDestroy, ProtoV6ProviderFactories: testutils.TestAccProtoV6ProviderFactories, Steps: []resource.TestStep{ // Create and verify { + PreConfig: func() { + t.Logf(" ... %s - %s", t.Name(), "create and verify") + }, Config: testutils.StringFromTemplateMust( "testdata/instance_template.gompl", data, ), Check: resource.ComposeAggregateTestCheckFunc( - resource.TestCheckResourceAttr( - testutils.ResStr(pfx, "instance", data.TfName), - "name", - data.Name, - ), - resource.TestCheckResourceAttrSet(testutils.ResStr(pfx, "instance", data.TfName), "id"), + defaultNoEncInstanceTestChecks(testItemID, data), + + // TODO - extract also to functions resource.TestCheckResourceAttr(testutils.ResStr(pfx, "user", userName), "name", userName), resource.TestCheckResourceAttrSet(testutils.ResStr(pfx, "user", userName), "id"), + resource.TestCheckResourceAttrPair( + testItemID, "project_id", + testutils.ResStr(pfx, "user", userName), "project_id", + ), + resource.TestCheckResourceAttrPair( + testItemID, "instance_id", + testutils.ResStr(pfx, "user", userName), "instance_id", + ), + + // TODO - extract also to functions resource.TestCheckResourceAttr(testutils.ResStr(pfx, "database", dbName), "name", dbName), resource.TestCheckResourceAttr(testutils.ResStr(pfx, "database", dbName), "owner", userName), resource.TestCheckResourceAttrSet(testutils.ResStr(pfx, "database", dbName), "id"), + resource.TestCheckResourceAttrPair( + testItemID, "project_id", + testutils.ResStr(pfx, "database", dbName), "project_id", + ), + resource.TestCheckResourceAttrPair( + testItemID, "instance_id", + testutils.ResStr(pfx, "database", dbName), "instance_id", + ), ), }, + // data source + { + PreConfig: func() { + t.Logf(" ... %s - %s", t.Name(), "datasource") + }, + Config: testutils.StringFromTemplateMust( + "testdata/instance_template.gompl", + data, + ), + Check: resource.ComposeAggregateTestCheckFunc( + // Instance data + resource.TestCheckResourceAttr( + testutils.ResStr(dataPfx, "instance", data.TfName), + "project_id", + data.ProjectID, + ), + resource.TestCheckResourceAttr( + testutils.ResStr(dataPfx, "instance", data.TfName), + "name", + data.Name, + ), + resource.TestCheckResourceAttrPair( + testutils.ResStr(dataPfx, "instance", data.TfName), "project_id", + testutils.ResStr(pfx, "instance", data.TfName), "project_id", + ), + resource.TestCheckResourceAttrPair( + testutils.ResStr(dataPfx, "database", dbName), "instance_id", + testutils.ResStr(pfx, "instance", data.TfName), "instance_id", + ), + resource.TestCheckResourceAttrPair( + testutils.ResStr(dataPfx, "user", userName), "instance_id", + testutils.ResStr(pfx, "instance", data.TfName), "instance_id", + ), + resource.TestCheckResourceAttrPair( + testutils.ResStr(dataPfx, "user", userName), "instance_id", + testutils.ResStr(pfx, "user", userName), "instance_id", + ), + + // User data + resource.TestCheckResourceAttr( + testutils.ResStr(dataPfx, "user", userName), + "project_id", + data.ProjectID, + ), + resource.TestCheckResourceAttrSet( + testutils.ResStr(dataPfx, "user", userName), + "user_id", + ), + resource.TestCheckResourceAttr( + testutils.ResStr(dataPfx, "user", userName), + "name", + data.Users[0].Name, + ), + resource.TestCheckResourceAttr( + testutils.ResStr(dataPfx, "user", userName), + "roles.#", + "1", + ), + resource.TestCheckResourceAttr( + testutils.ResStr(dataPfx, "user", userName), + "roles.0", + data.Users[0].Roles[0], + ), + + // Database data + resource.TestCheckResourceAttr( + testutils.ResStr(dataPfx, "database", dbName), + "project_id", + data.ProjectID, + ), + resource.TestCheckResourceAttr( + testutils.ResStr(dataPfx, "database", dbName), + "name", + dbName, + ), + resource.TestCheckResourceAttrPair( + testutils.ResStr(dataPfx, "database", dbName), + "instance_id", + testutils.ResStr(pfx, "database", dbName), + "instance_id", + ), + resource.TestCheckResourceAttrPair( + testutils.ResStr(dataPfx, "database", dbName), + "owner", + testutils.ResStr(dataPfx, "user", userName), + "name", + ), + ), + }, + // test instance imports + { + PreConfig: func() { + t.Logf(" ... %s - %s", t.Name(), "import instance") + }, + ResourceName: testItemID, + // ImportStateIdPrefix: "", + ImportStateVerifyIdentifierAttribute: "id", + ImportStateIdFunc: getInstanceTestID(data.TfName), + ImportStateKind: resource.ImportCommandWithID, + ImportState: true, + ImportStateVerify: true, + }, + // test database imports + { + PreConfig: func() { + t.Logf(" ... %s - %s", t.Name(), "import database") + }, + ResourceName: testutils.ResStr(pfx, "database", dbName), + // ImportStateIdPrefix: "", + // ImportStateVerifyIdentifierAttribute: "id", + ImportStateIdFunc: getDatabaseTestID(dbName), + ImportStateKind: resource.ImportCommandWithID, + ImportState: true, + ImportStateVerify: true, + }, + // test user imports + { + PreConfig: func() { + t.Logf(" ... %s - %s", t.Name(), "import user") + }, + ResourceName: testutils.ResStr(pfx, "user", userName), + // ImportStateIdPrefix: "", + // ImportStateVerifyIdentifierAttribute: "id", + ImportStateIdFunc: getUserTestID(userName), + ImportStateKind: resource.ImportCommandWithID, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"password"}, + }, }, }, ) @@ -436,28 +692,28 @@ func TestAccEncryptedInstanceWithDatabases(t *testing.T) { }, } + testItemID := testutils.ResStr(pfx, "instance", data.TfName) resource.ParallelTest( t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) - t.Logf(" ... working on instance %s", data.TfName) + t.Logf(" ... %s - %s", t.Name(), data.TfName) }, CheckDestroy: testAccCheckPostgresFlexDestroy, ProtoV6ProviderFactories: testutils.TestAccProtoV6ProviderFactories, Steps: []resource.TestStep{ // Create and verify { + PreConfig: func() { + t.Logf(" ... %s - %s", t.Name(), "create and verify") + }, Config: testutils.StringFromTemplateMust( "testdata/instance_template.gompl", data, ), Check: resource.ComposeAggregateTestCheckFunc( - resource.TestCheckResourceAttr( - testutils.ResStr(pfx, "instance", data.TfName), - "name", - data.Name, - ), - resource.TestCheckResourceAttrSet(testutils.ResStr(pfx, "instance", data.TfName), "id"), + defaultEncInstanceTestChecks(testItemID, data), + resource.TestCheckResourceAttr(testutils.ResStr(pfx, "user", userName), "name", userName), resource.TestCheckResourceAttrSet(testutils.ResStr(pfx, "user", userName), "id"), resource.TestCheckResourceAttr(testutils.ResStr(pfx, "database", dbName), "name", dbName), @@ -470,659 +726,6 @@ func TestAccEncryptedInstanceWithDatabases(t *testing.T) { ) } -// func setupMockServer() *httptest.Server { -// mux := http.NewServeMux() -// -// mux.HandleFunc("/api/resources", func(w http.ResponseWriter, r *http.Request) { -// switch r.Method { -// case http.MethodPost: -// w.WriteHeader(http.StatusCreated) -// err := json.NewEncoder(w).Encode(map[string]string{ -// "id": "mock-id-123", -// "name": "test-resource", -// }) -// if err != nil { -// log.Fatalln(err) -// } -// case http.MethodGet: -// w.WriteHeader(http.StatusOK) -// err := json.NewEncoder(w).Encode([]map[string]string{}) -// if err != nil { -// log.Fatalln(err) -// } -// } -// }) -// -// return httptest.NewServer(mux) -//} -// -// func TestUnitResourceCreate(t *testing.T) { -// server := setupMockServer() -// defer server.Close() -// -// // Configure provider to use mock server URL -// err := os.Setenv("API_ENDPOINT", server.URL) -// if err != nil { -// log.Fatalln(err) -// } -// -// // Run unit tests against mock -//} - -// func TestNewInstanceResource(t *testing.T) { -// exData := resData{ -// Region: "eu01", -// ServiceAccountFilePath: sa_file, -// ProjectID: project_id, -// Name: "testRes", -// } -// resource.ParallelTest(t, resource.TestCase{ -// ProtoV6ProviderFactories: testutils.TestAccProtoV6ProviderFactories, -// Steps: []resource.TestStep{ -// { -// Config: testAccResourceEncryptionExampleConfig(exData), -// Check: resource.ComposeAggregateTestCheckFunc( -// resource.TestCheckResourceAttr("example_resource.test", "name", exData.Name), -// resource.TestCheckResourceAttrSet("example_resource.test", "id"), -// ), -// }, -// }, -// }) -// -// //tests := []struct { -// // name string -// // want resource.Resource -// //}{ -// // { -// // name: "create empty instance resource", -// // want: &instanceResource{}, -// // }, -// //} -// //for _, tt := range tests { -// // t.Run(tt.name, func(t *testing.T) { -// // if got := NewInstanceResource(); !reflect.DeepEqual(got, tt.want) { -// // t.Errorf("NewInstanceResource() = %v, want %v", got, tt.want) -// // } -// // }) -// //} -//} - -//// Instance resource data -// var instanceResource = map[string]string{ -// "project_id": testutils.ProjectId, -// "region": "eu01", -// "name": fmt.Sprintf("tf-acc-%s", acctest.RandStringFromCharSet(7, acctest.CharSetAlphaNum)), -// "acl": "192.168.0.0/16", -// "backup_schedule": "00 16 * * *", -// "backup_schedule_updated": "00 12 * * *", -// "retention_days": "33", -// "flavor_cpu": "2", -// "flavor_ram": "4", -// "flavor_description": "Small, Compute optimized", -// "replicas": "1", -// "storage_class": "premium-perf12-stackit", -// "storage_size": "5", -// "version": "14", -// "flavor_id": "2.4", -// "kek_key_id": "UUID1", -// "kek_key_ring_id": "UUID2", -// "kek_key_version": "1", -// "service_account": "service@account.com", -// "access_scope": "SNA", -//} -// -//// User resource data -// var userResource = map[string]string{ -// "username": fmt.Sprintf("tfaccuser%s", acctest.RandStringFromCharSet(4, acctest.CharSetAlpha)), -// "role": "createdb", -// "project_id": testutils.ProjectId, -//} -// -//// Database resource data -// var databaseResource = map[string]string{ -// "name": fmt.Sprintf("tfaccdb%s", acctest.RandStringFromCharSet(4, acctest.CharSetAlphaNum)), -// "project_id": testutils.ProjectId, -//} -// -// func configResources(backupSchedule string, _ *string) string { -// return fmt.Sprintf( -// ` -// %s -// -// -// resource "stackitprivatepreview_postgresflexalpha_instance" "instance" { -// project_id = "%s" -// region = "%s" -// name = "%s" -// backup_schedule = "%s" -// retention_days = %s -// flavor_id = %s -// replicas = %s -// storage = { -// performance_class = "%s" -// size = %s -// } -// encryption = { -// kek_key_id = "%s" -// kek_key_ring_id = "%s" -// kek_key_version = "%s" -// service_account = "%s" -// } -// network = { -// acl = ["%s"] -// access_scope = "%s" -// } -// version = %s -// } -// -// resource "stackitprivatepreview_postgresflexalpha_user" "user" { -// project_id = "%s" -// instance_id = stackitprivatepreview_postgresflexalpha_instance.instance.instance_id -// username = "%s" -// roles = ["%s"] -// } -// -// resource "stackitprivatepreview_postgresflexalpha_database" "database" { -// project_id = "%s" -// instance_id = stackitprivatepreview_postgresflexalpha_instance.instance.instance_id -// name = "%s" -// owner = stackitprivatepreview_postgresflexalpha_user.user.username -// } -// `, -// testutils.PostgresFlexProviderConfig( -// utils.GetEnvOrDefault("TF_ACC_TEST_PROJECT_SERVICE_ACCOUNT_FILE", "~/service-account.json"), -// ), -// instanceResource["project_id"], -// instanceResource["region"], -// instanceResource["name"], -// backupSchedule, -// instanceResource["retention_days"], -// instanceResource["flavor_id"], -// instanceResource["replicas"], -// instanceResource["storage_class"], -// instanceResource["storage_size"], -// instanceResource["kek_key_id"], -// instanceResource["kek_key_ring_id"], -// instanceResource["kek_key_version"], -// instanceResource["service_account"], -// instanceResource["acl"], -// instanceResource["access_scope"], -// instanceResource["version"], -// -// userResource["project_id"], -// userResource["username"], -// userResource["role"], -// -// databaseResource["project_id"], -// databaseResource["name"], -// ) -//} -// -// func TestAccPostgresFlexFlexResource(t *testing.T) { -// resource.ParallelTest( -// t, resource.TestCase{ -// ProtoV6ProviderFactories: testutils.TestAccProtoV6ProviderFactories, -// CheckDestroy: testAccCheckPostgresFlexDestroy, -// Steps: []resource.TestStep{ -// // Creation -// { -// // testdata/ -// // ConfigDirectory: config.TestNameDirectory(), -// -// // testdata// -// // ConfigDirectory: config.TestStepDirectory(), -// Config: configResources(instanceResource["backup_schedule"], &testutils.Region), -// Check: resource.ComposeAggregateTestCheckFunc( -// // Instance -// resource.TestCheckResourceAttr( -// "stackitprivatepreview_postgresflexalpha_instance.instance", -// "project_id", -// instanceResource["project_id"], -// ), -// resource.TestCheckResourceAttrSet( -// "stackitprivatepreview_postgresflexalpha_instance.instance", -// "instance_id", -// ), -// resource.TestCheckResourceAttr( -// "stackitprivatepreview_postgresflexalpha_instance.instance", -// "name", -// instanceResource["name"], -// ), -// resource.TestCheckResourceAttr( -// "stackitprivatepreview_postgresflexalpha_instance.instance", -// "acl.#", -// "1", -// ), -// resource.TestCheckResourceAttr( -// "stackitprivatepreview_postgresflexalpha_instance.instance", -// "acl.0", -// instanceResource["acl"], -// ), -// resource.TestCheckResourceAttrSet( -// "stackitprivatepreview_postgresflexalpha_instance.instance", -// "flavor.id", -// ), -// resource.TestCheckResourceAttrSet( -// "stackitprivatepreview_postgresflexalpha_instance.instance", -// "flavor.description", -// ), -// resource.TestCheckResourceAttr( -// "stackitprivatepreview_postgresflexalpha_instance.instance", -// "backup_schedule", -// instanceResource["backup_schedule"], -// ), -// resource.TestCheckResourceAttr( -// "stackitprivatepreview_postgresflexalpha_instance.instance", -// "flavor.cpu", -// instanceResource["flavor_cpu"], -// ), -// resource.TestCheckResourceAttr( -// "stackitprivatepreview_postgresflexalpha_instance.instance", -// "flavor.ram", -// instanceResource["flavor_ram"], -// ), -// resource.TestCheckResourceAttr( -// "stackitprivatepreview_postgresflexalpha_instance.instance", -// "replicas", -// instanceResource["replicas"], -// ), -// resource.TestCheckResourceAttr( -// "stackitprivatepreview_postgresflexalpha_instance.instance", -// "storage.class", -// instanceResource["storage_class"], -// ), -// resource.TestCheckResourceAttr( -// "stackitprivatepreview_postgresflexalpha_instance.instance", -// "storage.size", -// instanceResource["storage_size"], -// ), -// resource.TestCheckResourceAttr( -// "stackitprivatepreview_postgresflexalpha_instance.instance", -// "version", -// instanceResource["version"], -// ), -// resource.TestCheckResourceAttr( -// "stackitprivatepreview_postgresflexalpha_instance.instance", -// "region", -// testutils.Region, -// ), -// -// // User -// resource.TestCheckResourceAttrPair( -// "stackitprivatepreview_postgresflexalpha_user.user", "project_id", -// "stackitprivatepreview_postgresflexalpha_instance.instance", "project_id", -// ), -// resource.TestCheckResourceAttrPair( -// "stackitprivatepreview_postgresflexalpha_user.user", "instance_id", -// "stackitprivatepreview_postgresflexalpha_instance.instance", "instance_id", -// ), -// resource.TestCheckResourceAttrSet("stackitprivatepreview_postgresflexalpha_user.user", "user_id"), -// resource.TestCheckResourceAttrSet("stackitprivatepreview_postgresflexalpha_user.user", "password"), -// -// // Database -// resource.TestCheckResourceAttrPair( -// "stackitprivatepreview_postgresflexalpha_database.database", "project_id", -// "stackitprivatepreview_postgresflexalpha_instance.instance", "project_id", -// ), -// resource.TestCheckResourceAttrPair( -// "stackitprivatepreview_postgresflexalpha_database.database", "instance_id", -// "stackitprivatepreview_postgresflexalpha_instance.instance", "instance_id", -// ), -// resource.TestCheckResourceAttr( -// "stackitprivatepreview_postgresflexalpha_database.database", -// "name", -// databaseResource["name"], -// ), -// resource.TestCheckResourceAttrPair( -// "stackitprivatepreview_postgresflexalpha_database.database", "owner", -// "stackitprivatepreview_postgresflexalpha_user.user", "username", -// ), -// ), -// }, -// // data source -// { -// Config: fmt.Sprintf( -// ` -// %s -// -// data "stackitprivatepreview_postgresflexalpha_instance" "instance" { -// project_id = stackitprivatepreview_postgresflexalpha_instance.instance.project_id -// instance_id = stackitprivatepreview_postgresflexalpha_instance.instance.instance_id -// } -// -// data "stackitprivatepreview_postgresflexalpha_user" "user" { -// project_id = stackitprivatepreview_postgresflexalpha_instance.instance.project_id -// instance_id = stackitprivatepreview_postgresflexalpha_instance.instance.instance_id -// user_id = stackitprivatepreview_postgresflexalpha_user.user.user_id -// } -// -// data "stackitprivatepreview_postgresflexalpha_database" "database" { -// project_id = stackitprivatepreview_postgresflexalpha_instance.instance.project_id -// instance_id = stackitprivatepreview_postgresflexalpha_instance.instance.instance_id -// database_id = stackitprivatepreview_postgresflexalpha_database.database.database_id -// } -// `, -// configResources(instanceResource["backup_schedule"], nil), -// ), -// Check: resource.ComposeAggregateTestCheckFunc( -// // Instance data -// resource.TestCheckResourceAttr( -// "data.stackitprivatepreview_postgresflexalpha_instance.instance", -// "project_id", -// instanceResource["project_id"], -// ), -// resource.TestCheckResourceAttr( -// "data.stackitprivatepreview_postgresflexalpha_instance.instance", -// "name", -// instanceResource["name"], -// ), -// resource.TestCheckResourceAttrPair( -// "data.stackitprivatepreview_postgresflexalpha_instance.instance", "project_id", -// "stackitprivatepreview_postgresflexalpha_instance.instance", "project_id", -// ), -// resource.TestCheckResourceAttrPair( -// "data.stackitprivatepreview_postgresflexalpha_instance.instance", "instance_id", -// "stackitprivatepreview_postgresflexalpha_instance.instance", "instance_id", -// ), -// resource.TestCheckResourceAttrPair( -// "data.stackitprivatepreview_postgresflexalpha_user.user", "instance_id", -// "stackitprivatepreview_postgresflexalpha_user.user", "instance_id", -// ), -// -// resource.TestCheckResourceAttr( -// "data.stackitprivatepreview_postgresflexalpha_instance.instance", -// "acl.#", -// "1", -// ), -// resource.TestCheckResourceAttr( -// "data.stackitprivatepreview_postgresflexalpha_instance.instance", -// "acl.0", -// instanceResource["acl"], -// ), -// resource.TestCheckResourceAttr( -// "data.stackitprivatepreview_postgresflexalpha_instance.instance", -// "backup_schedule", -// instanceResource["backup_schedule"], -// ), -// resource.TestCheckResourceAttr( -// "data.stackitprivatepreview_postgresflexalpha_instance.instance", -// "flavor.id", -// instanceResource["flavor_id"], -// ), -// resource.TestCheckResourceAttr( -// "data.stackitprivatepreview_postgresflexalpha_instance.instance", -// "flavor.description", -// instanceResource["flavor_description"], -// ), -// resource.TestCheckResourceAttr( -// "data.stackitprivatepreview_postgresflexalpha_instance.instance", -// "flavor.cpu", -// instanceResource["flavor_cpu"], -// ), -// resource.TestCheckResourceAttr( -// "data.stackitprivatepreview_postgresflexalpha_instance.instance", -// "flavor.ram", -// instanceResource["flavor_ram"], -// ), -// resource.TestCheckResourceAttr( -// "data.stackitprivatepreview_postgresflexalpha_instance.instance", -// "replicas", -// instanceResource["replicas"], -// ), -// -// // User data -// resource.TestCheckResourceAttr( -// "data.stackitprivatepreview_postgresflexalpha_user.user", -// "project_id", -// userResource["project_id"], -// ), -// resource.TestCheckResourceAttrSet( -// "data.stackitprivatepreview_postgresflexalpha_user.user", -// "user_id", -// ), -// resource.TestCheckResourceAttr( -// "data.stackitprivatepreview_postgresflexalpha_user.user", -// "username", -// userResource["username"], -// ), -// resource.TestCheckResourceAttr( -// "data.stackitprivatepreview_postgresflexalpha_user.user", -// "roles.#", -// "1", -// ), -// resource.TestCheckResourceAttr( -// "data.stackitprivatepreview_postgresflexalpha_user.user", -// "roles.0", -// userResource["role"], -// ), -// resource.TestCheckResourceAttrSet( -// "data.stackitprivatepreview_postgresflexalpha_user.user", -// "host", -// ), -// resource.TestCheckResourceAttrSet( -// "data.stackitprivatepreview_postgresflexalpha_user.user", -// "port", -// ), -// -// // Database data -// resource.TestCheckResourceAttr( -// "data.stackitprivatepreview_postgresflexalpha_database.database", -// "project_id", -// instanceResource["project_id"], -// ), -// resource.TestCheckResourceAttr( -// "data.stackitprivatepreview_postgresflexalpha_database.database", -// "name", -// databaseResource["name"], -// ), -// resource.TestCheckResourceAttrPair( -// "data.stackitprivatepreview_postgresflexalpha_database.database", -// "instance_id", -// "stackitprivatepreview_postgresflexalpha_instance.instance", -// "instance_id", -// ), -// resource.TestCheckResourceAttrPair( -// "data.stackitprivatepreview_postgresflexalpha_database.database", -// "owner", -// "data.stackitprivatepreview_postgresflexalpha_user.user", -// "username", -// ), -// ), -// }, -// // Import -// { -// ResourceName: "stackitprivatepreview_postgresflexalpha_instance.instance", -// ImportStateIdFunc: func(s *terraform.State) (string, error) { -// r, ok := s.RootModule().Resources["stackitprivatepreview_postgresflexalpha_instance.instance"] -// if !ok { -// return "", fmt.Errorf("couldn't find resource stackitprivatepreview_postgresflexalpha_instance.instance") -// } -// instanceId, ok := r.Primary.Attributes["instance_id"] -// if !ok { -// return "", fmt.Errorf("couldn't find attribute instance_id") -// } -// -// return fmt.Sprintf("%s,%s,%s", testutils.ProjectId, testutils.Region, instanceId), nil -// }, -// ImportState: true, -// ImportStateVerify: true, -// ImportStateVerifyIgnore: []string{"password"}, -// }, -// { -// ResourceName: "stackitprivatepreview_postgresflexalpha_user.user", -// ImportStateIdFunc: func(s *terraform.State) (string, error) { -// r, ok := s.RootModule().Resources["stackitprivatepreview_postgresflexalpha_user.user"] -// if !ok { -// return "", fmt.Errorf("couldn't find resource stackitprivatepreview_postgresflexalpha_user.user") -// } -// instanceId, ok := r.Primary.Attributes["instance_id"] -// if !ok { -// return "", fmt.Errorf("couldn't find attribute instance_id") -// } -// userId, ok := r.Primary.Attributes["user_id"] -// if !ok { -// return "", fmt.Errorf("couldn't find attribute user_id") -// } -// -// return fmt.Sprintf("%s,%s,%s,%s", testutils.ProjectId, testutils.Region, instanceId, userId), nil -// }, -// ImportState: true, -// ImportStateVerify: true, -// ImportStateVerifyIgnore: []string{"password", "uri"}, -// }, -// { -// ResourceName: "stackitprivatepreview_postgresflexalpha_database.database", -// ImportStateIdFunc: func(s *terraform.State) (string, error) { -// r, ok := s.RootModule().Resources["stackitprivatepreview_postgresflexalpha_database.database"] -// if !ok { -// return "", fmt.Errorf("couldn't find resource stackitprivatepreview_postgresflexalpha_database.database") -// } -// instanceId, ok := r.Primary.Attributes["instance_id"] -// if !ok { -// return "", fmt.Errorf("couldn't find attribute instance_id") -// } -// databaseId, ok := r.Primary.Attributes["database_id"] -// if !ok { -// return "", fmt.Errorf("couldn't find attribute database_id") -// } -// -// return fmt.Sprintf( -// "%s,%s,%s,%s", -// testutils.ProjectId, -// testutils.Region, -// instanceId, -// databaseId, -// ), nil -// }, -// ImportState: true, -// ImportStateVerify: true, -// }, -// // Update -// { -// Config: configResources(instanceResource["backup_schedule_updated"], nil), -// Check: resource.ComposeAggregateTestCheckFunc( -// // Instance data -// resource.TestCheckResourceAttr( -// "stackitprivatepreview_postgresflexalpha_instance.instance", -// "project_id", -// instanceResource["project_id"], -// ), -// resource.TestCheckResourceAttrSet( -// "stackitprivatepreview_postgresflexalpha_instance.instance", -// "instance_id", -// ), -// resource.TestCheckResourceAttr( -// "stackitprivatepreview_postgresflexalpha_instance.instance", -// "name", -// instanceResource["name"], -// ), -// resource.TestCheckResourceAttr( -// "stackitprivatepreview_postgresflexalpha_instance.instance", -// "acl.#", -// "1", -// ), -// resource.TestCheckResourceAttr( -// "stackitprivatepreview_postgresflexalpha_instance.instance", -// "acl.0", -// instanceResource["acl"], -// ), -// resource.TestCheckResourceAttr( -// "stackitprivatepreview_postgresflexalpha_instance.instance", -// "backup_schedule", -// instanceResource["backup_schedule_updated"], -// ), -// resource.TestCheckResourceAttrSet( -// "stackitprivatepreview_postgresflexalpha_instance.instance", -// "flavor.id", -// ), -// resource.TestCheckResourceAttrSet( -// "stackitprivatepreview_postgresflexalpha_instance.instance", -// "flavor.description", -// ), -// resource.TestCheckResourceAttr( -// "stackitprivatepreview_postgresflexalpha_instance.instance", -// "flavor.cpu", -// instanceResource["flavor_cpu"], -// ), -// resource.TestCheckResourceAttr( -// "stackitprivatepreview_postgresflexalpha_instance.instance", -// "flavor.ram", -// instanceResource["flavor_ram"], -// ), -// resource.TestCheckResourceAttr( -// "stackitprivatepreview_postgresflexalpha_instance.instance", -// "replicas", -// instanceResource["replicas"], -// ), -// resource.TestCheckResourceAttr( -// "stackitprivatepreview_postgresflexalpha_instance.instance", -// "storage.class", -// instanceResource["storage_class"], -// ), -// resource.TestCheckResourceAttr( -// "stackitprivatepreview_postgresflexalpha_instance.instance", -// "storage.size", -// instanceResource["storage_size"], -// ), -// resource.TestCheckResourceAttr( -// "stackitprivatepreview_postgresflexalpha_instance.instance", -// "version", -// instanceResource["version"], -// ), -// ), -// }, -// // Deletion is done by the framework implicitly -// }, -// }, -// ) -//} -// -// func testAccCheckPostgresFlexDestroy(s *terraform.State) error { -// ctx := context.Background() -// var client *postgresflex.APIClient -// var err error -// if testutils.PostgresFlexCustomEndpoint == "" { -// client, err = postgresflex.NewAPIClient() -// } else { -// client, err = postgresflex.NewAPIClient( -// config.WithEndpoint(testutils.PostgresFlexCustomEndpoint), -// ) -// } -// if err != nil { -// return fmt.Errorf("creating client: %w", err) -// } -// -// instancesToDestroy := []string{} -// for _, rs := range s.RootModule().Resources { -// if rs.Type != "stackitprivatepreview_postgresflexalpha_instance" { -// continue -// } -// // instance terraform ID: = "[project_id],[region],[instance_id]" -// instanceId := strings.Split(rs.Primary.ID, core.Separator)[2] -// instancesToDestroy = append(instancesToDestroy, instanceId) -// } -// -// instancesResp, err := client.ListInstancesRequest(ctx, testutils.ProjectId, testutils.Region).Execute() -// if err != nil { -// return fmt.Errorf("getting instancesResp: %w", err) -// } -// -// items := *instancesResp.Instances -// for i := range items { -// if items[i].Id == nil { -// continue -// } -// if utils.Contains(instancesToDestroy, *items[i].Id) { -// // TODO @mhenselin - does force still exist? -// err := client.DeleteInstanceRequestExecute(ctx, testutils.ProjectId, testutils.Region, *items[i].Id) -// if err != nil { -// return fmt.Errorf("deleting instance %s during CheckDestroy: %w", *items[i].Id, err) -// } -// } -// } -// return nil -//} - func testAccCheckPostgresFlexDestroy(s *terraform.State) error { testutils.Setup() @@ -1206,3 +809,182 @@ func testAccCheckPostgresFlexDestroy(s *terraform.State) error { } return nil } + +func defaultNoEncInstanceTestChecks(testItemID string, data resData) resource.TestCheckFunc { + return resource.ComposeAggregateTestCheckFunc( + defaultInstanceTestChecks(testItemID, data), + + // check absent attr + resource.TestCheckNoResourceAttr(testItemID, "encryption"), + resource.TestCheckNoResourceAttr(testItemID, "encryption.kek_key_id"), + resource.TestCheckNoResourceAttr(testItemID, "encryption.kek_key_ring_id"), + resource.TestCheckNoResourceAttr(testItemID, "encryption.kek_key_version"), + resource.TestCheckNoResourceAttr(testItemID, "encryption.service_account"), + ) +} + +func defaultEncInstanceTestChecks(testItemID string, data resData) resource.TestCheckFunc { + return resource.ComposeAggregateTestCheckFunc( + defaultInstanceTestChecks(testItemID, data), + + // check absent attr + resource.TestCheckResourceAttr(testItemID, "encryption.%", "4"), + resource.TestCheckResourceAttrSet(testItemID, "encryption.kek_key_id"), + resource.TestCheckResourceAttr(testItemID, "encryption.kek_key_id", data.KekKeyID), + resource.TestCheckResourceAttrSet(testItemID, "encryption.kek_key_ring_id"), + resource.TestCheckResourceAttr(testItemID, "encryption.kek_key_ring_id", data.KekKeyRingID), + resource.TestCheckResourceAttrSet(testItemID, "encryption.kek_key_version"), + resource.TestCheckResourceAttr(testItemID, "encryption.kek_key_version", strconv.Itoa(int(data.KekKeyVersion))), + resource.TestCheckResourceAttrSet(testItemID, "encryption.service_account"), + resource.TestCheckResourceAttr(testItemID, "encryption.service_account", data.KekServiceAccount), + ) +} + +func defaultInstanceTestChecks(testItemID string, data resData) resource.TestCheckFunc { + // if AccessScope == SNA these are set + if data.AccessScope == "SNA" { + return resource.ComposeAggregateTestCheckFunc( + basicInstanceTestChecks(testItemID, data), + resource.TestCheckResourceAttrSet(testItemID, "network.instance_address"), + resource.TestCheckResourceAttrSet(testItemID, "network.router_address"), + ) + } + + // if AccessScope == PUBLIC these are empty - but they are set + return resource.ComposeAggregateTestCheckFunc( + basicInstanceTestChecks(testItemID, data), + resource.TestCheckResourceAttr(testItemID, "network.instance_address", ""), + resource.TestCheckResourceAttr(testItemID, "network.router_address", ""), + ) +} + +func basicInstanceTestChecks(testItemID string, data resData) resource.TestCheckFunc { + return resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttrSet(testItemID, "backup_schedule"), + resource.TestCheckResourceAttr(testItemID, "backup_schedule", data.BackupSchedule), + + resource.TestCheckResourceAttr(testItemID, "connection_info.%", "1"), + resource.TestCheckResourceAttr(testItemID, "connection_info.write.%", "2"), + resource.TestCheckResourceAttrSet(testItemID, "connection_info.write.host"), + resource.TestCheckResourceAttrSet(testItemID, "connection_info.write.port"), + + resource.TestCheckResourceAttrSet(testItemID, "flavor_id"), + resource.TestCheckResourceAttr(testItemID, "flavor_id", data.FlavorID), + + resource.TestCheckResourceAttrSet(testItemID, "id"), + resource.TestCheckResourceAttrSet(testItemID, "instance_id"), + + resource.TestCheckResourceAttrSet(testItemID, "is_deletable"), + resource.TestCheckResourceAttr(testItemID, "is_deletable", "true"), + + resource.TestCheckResourceAttrSet(testItemID, "name"), + resource.TestCheckResourceAttr(testItemID, "name", data.Name), + + // network params check + resource.TestCheckResourceAttr(testItemID, "network.%", "4"), + resource.TestCheckResourceAttrSet(testItemID, "network.access_scope"), + resource.TestCheckResourceAttr(testItemID, "network.access_scope", data.AccessScope), + // resource.TestCheckResourceAttrSet(testItemID, "network.acl"), + resource.TestCheckResourceAttr(testItemID, "network.acl.#", strconv.Itoa(len(data.ACLStrings))), + // instance_address and router_address are only checked in enc + + resource.TestCheckResourceAttrSet(testItemID, "project_id"), + resource.TestCheckResourceAttr(testItemID, "project_id", data.ProjectID), + + resource.TestCheckResourceAttrSet(testItemID, "region"), + resource.TestCheckResourceAttr(testItemID, "region", data.Region), + + resource.TestCheckResourceAttrSet(testItemID, "replicas"), + resource.TestCheckResourceAttr(testItemID, "replicas", strconv.Itoa(int(data.Replicas))), + + resource.TestCheckResourceAttrSet(testItemID, "retention_days"), + resource.TestCheckResourceAttr(testItemID, "retention_days", strconv.Itoa(int(data.RetentionDays))), + + resource.TestCheckResourceAttrSet(testItemID, "status"), + resource.TestCheckResourceAttr(testItemID, "status", "READY"), + + // storage params check + resource.TestCheckResourceAttr(testItemID, "storage.%", "2"), + resource.TestCheckResourceAttrSet(testItemID, "storage.performance_class"), + resource.TestCheckResourceAttr(testItemID, "storage.performance_class", data.PerformanceClass), + resource.TestCheckResourceAttrSet(testItemID, "storage.size"), + resource.TestCheckResourceAttr(testItemID, "storage.size", strconv.Itoa(int(data.Size))), + + resource.TestCheckResourceAttrSet(testItemID, "version"), + resource.TestCheckResourceAttr(testItemID, "version", data.Version), + ) +} + +func getInstanceTestID(name string) func(s *terraform.State) (string, error) { + return func(s *terraform.State) (string, error) { + r, ok := s.RootModule().Resources[testutils.ResStr(pfx, "instance", name)] + if !ok { + return "", fmt.Errorf("couldn't find resource stackitprivatepreview_postgresflexalpha_instance.%s", name) + } + projectID, ok := r.Primary.Attributes["project_id"] + if !ok { + return "", fmt.Errorf("couldn't find attribute project_id") + } + 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,%s", projectID, region, instanceID), nil + } +} + +func getDatabaseTestID(name string) func(s *terraform.State) (string, error) { + return func(s *terraform.State) (string, error) { + r, ok := s.RootModule().Resources[testutils.ResStr(pfx, "database", name)] + if !ok { + return "", fmt.Errorf("couldn't find resource stackitprivatepreview_postgresflexalpha_instance.%s", name) + } + projectID, ok := r.Primary.Attributes["project_id"] + if !ok { + return "", fmt.Errorf("couldn't find attribute project_id") + } + 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") + } + databaseID, ok := r.Primary.Attributes["database_id"] + if !ok { + return "", fmt.Errorf("couldn't find attribute database_id") + } + return fmt.Sprintf("%s,%s,%s,%s", projectID, region, instanceID, databaseID), nil + } +} + +func getUserTestID(name string) func(s *terraform.State) (string, error) { + return func(s *terraform.State) (string, error) { + r, ok := s.RootModule().Resources[testutils.ResStr(pfx, "user", name)] + if !ok { + return "", fmt.Errorf("couldn't find resource stackitprivatepreview_postgresflexalpha_instance.%s", name) + } + projectID, ok := r.Primary.Attributes["project_id"] + if !ok { + return "", fmt.Errorf("couldn't find attribute project_id") + } + 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") + } + userID, ok := r.Primary.Attributes["user_id"] + if !ok { + return "", fmt.Errorf("couldn't find attribute user_id") + } + return fmt.Sprintf("%s,%s,%s,%s", projectID, region, instanceID, userID), nil + } +} diff --git a/stackit/internal/services/postgresflexalpha/testdata/instance_template.gompl b/stackit/internal/services/postgresflexalpha/testdata/instance_template.gompl index d0ab3f25..ce6b9ac2 100644 --- a/stackit/internal/services/postgresflexalpha/testdata/instance_template.gompl +++ b/stackit/internal/services/postgresflexalpha/testdata/instance_template.gompl @@ -23,16 +23,21 @@ resource "stackitprivatepreview_postgresflexalpha_instance" "{{ .TfName }}" { } {{ end }} network = { - acl = ["{{ .ACLString }}"] + acl = [{{ range $i, $v := .ACLStrings }}{{if $i}},{{end}}"{{$v}}"{{end}}] access_scope = "{{ .AccessScope }}" } - version = {{ .Version }} +{{ if .Version }} + version = "{{ .Version }}" +{{ end }} } {{ if .Users }} {{ $tfName := .TfName }} {{ range $user := .Users }} resource "stackitprivatepreview_postgresflexalpha_user" "{{ $user.Name }}" { + depends_on = [ + stackitprivatepreview_postgresflexalpha_instance.{{ $tfName }} + ] project_id = "{{ $user.ProjectID }}" instance_id = stackitprivatepreview_postgresflexalpha_instance.{{ $tfName }}.instance_id name = "{{ $user.Name }}" @@ -45,6 +50,10 @@ resource "stackitprivatepreview_postgresflexalpha_user" "{{ $user.Name }}" { {{ $tfName := .TfName }} {{ range $db := .Databases }} resource "stackitprivatepreview_postgresflexalpha_database" "{{ $db.Name }}" { + depends_on = [ + stackitprivatepreview_postgresflexalpha_instance.{{ $tfName }}, + stackitprivatepreview_postgresflexalpha_user.{{ $db.Owner }} + ] project_id = "{{ $db.ProjectID }}" instance_id = stackitprivatepreview_postgresflexalpha_instance.{{ $tfName }}.instance_id name = "{{ $db.Name }}" @@ -52,3 +61,32 @@ resource "stackitprivatepreview_postgresflexalpha_database" "{{ $db.Name }}" { } {{ end }} {{ end }} + +{{ if .DataSourceTest }} +data "stackitprivatepreview_postgresflexalpha_instance" "{{ .TfName }}" { + project_id = stackitprivatepreview_postgresflexalpha_instance.{{ .TfName }}.project_id + instance_id = stackitprivatepreview_postgresflexalpha_instance.{{ .TfName }}.instance_id +} + +{{ if .Users }} +{{ $tfName := .TfName }} +{{ range $user := .Users }} +data "stackitprivatepreview_postgresflexalpha_user" "{{ $user.Name }}" { + project_id = stackitprivatepreview_postgresflexalpha_instance.{{ $tfName }}.project_id + instance_id = stackitprivatepreview_postgresflexalpha_instance.{{ $tfName }}.instance_id + user_id = stackitprivatepreview_postgresflexalpha_user.{{ $user.Name }}.user_id +} +{{ end }} +{{ end }} + +{{ if .Databases }} +{{ $tfName := .TfName }} +{{ range $db := .Databases }} +data "stackitprivatepreview_postgresflexalpha_database" "{{ $db.Name }}" { + project_id = stackitprivatepreview_postgresflexalpha_instance.{{ $tfName }}.project_id + instance_id = stackitprivatepreview_postgresflexalpha_instance.{{ $tfName }}.instance_id + database_id = stackitprivatepreview_postgresflexalpha_database.{{ $db.Name }}.database_id +} +{{ end }} +{{ end }} +{{ end }} diff --git a/stackit/internal/services/postgresflexalpha/user/datasources_gen/user_data_source_gen.go b/stackit/internal/services/postgresflexalpha/user/datasources_gen/user_data_source_gen.go index 29a7cca0..37f3c7c6 100644 --- a/stackit/internal/services/postgresflexalpha/user/datasources_gen/user_data_source_gen.go +++ b/stackit/internal/services/postgresflexalpha/user/datasources_gen/user_data_source_gen.go @@ -35,7 +35,7 @@ func UserDataSourceSchema(ctx context.Context) schema.Schema { MarkdownDescription: "The STACKIT project ID.", }, "region": schema.StringAttribute{ - Required: true, + Optional: true, Description: "The region which should be addressed", MarkdownDescription: "The region which should be addressed", Validators: []validator.String{ diff --git a/stackit/internal/services/postgresflexalpha/user/mapper.go b/stackit/internal/services/postgresflexalpha/user/mapper.go index dcf4545c..70c53b83 100644 --- a/stackit/internal/services/postgresflexalpha/user/mapper.go +++ b/stackit/internal/services/postgresflexalpha/user/mapper.go @@ -116,7 +116,12 @@ func mapResourceFields(userResp *v3alpha1api.GetUserResponse, model *resourceMod return fmt.Errorf("user id not present") } - model.Id = types.Int64Value(userID) + model.Id = utils.BuildInternalTerraformId( + model.ProjectId.ValueString(), + model.Region.ValueString(), + model.InstanceId.ValueString(), + strconv.FormatInt(userID, 10), + ) model.UserId = types.Int64Value(userID) model.Name = types.StringValue(user.Name) diff --git a/stackit/internal/services/postgresflexalpha/user/mapper_test.go b/stackit/internal/services/postgresflexalpha/user/mapper_test.go index 5b07ede8..f8c01fc2 100644 --- a/stackit/internal/services/postgresflexalpha/user/mapper_test.go +++ b/stackit/internal/services/postgresflexalpha/user/mapper_test.go @@ -1,6 +1,7 @@ package postgresflexalpha import ( + "fmt" "testing" "github.com/google/go-cmp/cmp" @@ -165,7 +166,7 @@ func TestMapFieldsCreate(t *testing.T) { }, testRegion, resourceModel{ - Id: types.Int64Value(1), + Id: types.StringValue(fmt.Sprintf("%s,%s,%s,%d", "pid", testRegion, "iid", 1)), UserId: types.Int64Value(1), InstanceId: types.StringValue("iid"), ProjectId: types.StringValue("pid"), @@ -187,7 +188,7 @@ func TestMapFieldsCreate(t *testing.T) { }, testRegion, resourceModel{ - Id: types.Int64Value(1), + Id: types.StringValue(fmt.Sprintf("%s,%s,%s,%d", "pid", testRegion, "iid", 1)), UserId: types.Int64Value(1), InstanceId: types.StringValue("iid"), ProjectId: types.StringValue("pid"), @@ -209,7 +210,7 @@ func TestMapFieldsCreate(t *testing.T) { }, testRegion, resourceModel{ - Id: types.Int64Value(1), + Id: types.StringValue(fmt.Sprintf("%s,%s,%s,%d", "pid", testRegion, "iid", 1)), UserId: types.Int64Value(1), InstanceId: types.StringValue("iid"), ProjectId: types.StringValue("pid"), @@ -249,6 +250,7 @@ func TestMapFieldsCreate(t *testing.T) { tt.description, func(t *testing.T) { state := &resourceModel{ ProjectId: tt.expected.ProjectId, + Region: types.StringValue(testRegion), InstanceId: tt.expected.InstanceId, } @@ -286,7 +288,7 @@ func TestMapFields(t *testing.T) { }, testRegion, resourceModel{ - Id: types.Int64Value(1), + Id: types.StringValue(fmt.Sprintf("%s,%s,%s,%d", "pid", testRegion, "iid", 1)), UserId: types.Int64Value(int64(1)), InstanceId: types.StringValue("iid"), ProjectId: types.StringValue("pid"), @@ -311,7 +313,7 @@ func TestMapFields(t *testing.T) { }, testRegion, resourceModel{ - Id: types.Int64Value(1), + Id: types.StringValue(fmt.Sprintf("%s,%s,%s,%d", "pid", testRegion, "iid", 1)), UserId: types.Int64Value(1), InstanceId: types.StringValue("iid"), ProjectId: types.StringValue("pid"), @@ -339,7 +341,7 @@ func TestMapFields(t *testing.T) { }, testRegion, resourceModel{ - Id: types.Int64Value(1), + Id: types.StringValue(fmt.Sprintf("%s,%s,%s,%d", "pid", testRegion, "iid", 1)), UserId: types.Int64Value(1), InstanceId: types.StringValue("iid"), ProjectId: types.StringValue("pid"), @@ -379,6 +381,7 @@ func TestMapFields(t *testing.T) { state := &resourceModel{ ProjectId: tt.expected.ProjectId, InstanceId: tt.expected.InstanceId, + Region: types.StringValue(tt.region), } err := mapResourceFields(tt.input, state, tt.region) if !tt.isValid && err == nil { @@ -388,7 +391,7 @@ func TestMapFields(t *testing.T) { t.Fatalf("Should not have failed: %v", err) } if tt.isValid { - diff := cmp.Diff(state, &tt.expected) + diff := cmp.Diff(&tt.expected, state) if diff != "" { t.Fatalf("Data does not match: %s", diff) } @@ -476,7 +479,7 @@ func TestToCreatePayload(t *testing.T) { t.Fatalf("Should not have failed: %v", err) } if tt.isValid { - diff := cmp.Diff(output, tt.expected) + diff := cmp.Diff(tt.expected, output) if diff != "" { t.Fatalf("Data does not match: %s", diff) } diff --git a/stackit/internal/services/postgresflexalpha/user/resource.go b/stackit/internal/services/postgresflexalpha/user/resource.go index 065c9552..b7c79f6b 100644 --- a/stackit/internal/services/postgresflexalpha/user/resource.go +++ b/stackit/internal/services/postgresflexalpha/user/resource.go @@ -11,7 +11,7 @@ import ( "time" "github.com/hashicorp/terraform-plugin-framework/diag" - "github.com/hashicorp/terraform-plugin-framework/resource/identityschema" + "github.com/stackitcloud/stackit-sdk-go/core/oapierror" "github.com/stackitcloud/stackit-sdk-go/services/postgresflex/v3alpha1api" postgresflexalpha "tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit/internal/services/postgresflexalpha/user/resources_gen" @@ -34,12 +34,7 @@ var ( _ resource.ResourceWithConfigure = &userResource{} _ resource.ResourceWithImportState = &userResource{} _ resource.ResourceWithModifyPlan = &userResource{} - _ resource.ResourceWithIdentity = &userResource{} _ resource.ResourceWithValidateConfig = &userResource{} - - // Error message constants - extractErrorSummary = "extracting failed" - extractErrorMessage = "Extracting identity data: %v" ) // NewUserResource is a helper function to simplify the provider implementation. @@ -50,14 +45,6 @@ func NewUserResource() resource.Resource { // resourceModel represents the Terraform resource state for a PostgreSQL Flex user. type resourceModel = postgresflexalpha.UserModel -// UserResourceIdentityModel describes the resource's identity attributes. -type UserResourceIdentityModel struct { - ProjectID types.String `tfsdk:"project_id"` - Region types.String `tfsdk:"region"` - InstanceID types.String `tfsdk:"instance_id"` - UserID types.Int64 `tfsdk:"user_id"` -} - // userResource implements the resource handling for a PostgreSQL Flex user. type userResource struct { client *v3alpha1api.APIClient @@ -232,23 +219,14 @@ func (r *userResource) Create( } arg.userID = int64(*id) + model.Id = utils.BuildInternalTerraformId(arg.projectID, arg.region, arg.instanceID, strconv.FormatInt(arg.userID, 10)) + + ctx = tflog.SetField(ctx, "id", model.Id.ValueString()) ctx = tflog.SetField(ctx, "user_id", id) ctx = core.LogResponse(ctx) - // Set data returned by API in identity - identity := UserResourceIdentityModel{ - ProjectID: types.StringValue(arg.projectID), - Region: types.StringValue(arg.region), - InstanceID: types.StringValue(arg.instanceID), - UserID: types.Int64Value(int64(*id)), - } - resp.Diagnostics.Append(resp.Identity.Set(ctx, identity)...) - if resp.Diagnostics.HasError() { - return - } - - model.Id = types.Int64Value(int64(*id)) + model.Id = utils.BuildInternalTerraformId(arg.projectID, arg.region, arg.instanceID, strconv.FormatInt(arg.userID, 10)) model.UserId = types.Int64Value(int64(*id)) model.Password = types.StringValue(userResp.GetPassword()) model.Status = types.StringValue(userResp.GetStatus()) @@ -370,15 +348,14 @@ func (r *userResource) Read( ctx = core.LogResponse(ctx) - // Set data returned by API in identity - identity := UserResourceIdentityModel{ - ProjectID: types.StringValue(arg.projectID), - Region: types.StringValue(arg.region), - InstanceID: types.StringValue(arg.instanceID), - UserID: types.Int64Value(arg.userID), - } - resp.Diagnostics.Append(resp.Identity.Set(ctx, identity)...) - if resp.Diagnostics.HasError() { + err = mapResourceFields(waitResp, &model, model.Region.ValueString()) + if err != nil { + core.LogAndAddError( + ctx, + &resp.Diagnostics, + "read user", + fmt.Sprintf("Wait response mapping: %v", err), + ) return } @@ -457,18 +434,6 @@ func (r *userResource) Update( ctx = core.LogResponse(ctx) - // Set data returned by API in identity - identity := UserResourceIdentityModel{ - ProjectID: types.StringValue(arg.projectID), - Region: types.StringValue(arg.region), - InstanceID: types.StringValue(arg.instanceID), - UserID: types.Int64Value(userID64), - } - resp.Diagnostics.Append(resp.Identity.Set(ctx, identity)...) - if resp.Diagnostics.HasError() { - return - } - // Verify update waitResp, err := postgresflexalphaWait.GetUserByIdWaitHandler( ctx, @@ -525,26 +490,17 @@ func (r *userResource) Delete( if resp.Diagnostics.HasError() { return } - // Read identity data - var identityData UserResourceIdentityModel - resp.Diagnostics.Append(req.Identity.Get(ctx, &identityData)...) - if resp.Diagnostics.HasError() { - return - } ctx = core.InitProviderContext(ctx) - arg, errExt := r.extractIdentityData(model, identityData) - if errExt != nil { - core.LogAndAddError( - ctx, - &resp.Diagnostics, - extractErrorSummary, - fmt.Sprintf(extractErrorMessage, errExt), - ) + arg := clientArg{ + projectID: model.ProjectId.ValueString(), + instanceID: model.InstanceId.ValueString(), + region: model.Region.ValueString(), + userID: model.UserId.ValueInt64(), } - ctx = r.setTFLogFields(ctx, arg) + ctx = r.setTFLogFields(ctx, &arg) ctx = core.InitProviderContext(ctx) userID64 := arg.userID @@ -557,7 +513,14 @@ func (r *userResource) Delete( // Delete existing record set err := r.client.DefaultAPI.DeleteUserRequest(ctx, arg.projectID, arg.region, arg.instanceID, userID).Execute() if err != nil { - core.LogAndAddError(ctx, &resp.Diagnostics, "Error deleting user", fmt.Sprintf("Calling API: %v", err)) + oapiErr, ok := err.(*oapierror.GenericOpenAPIError) // nolint:errorlint //complaining that error.As should be used to catch wrapped errors, but this error should not be wrapped + if ok { + if oapiErr.StatusCode == 404 { + resp.State.RemoveResource(ctx) + return + } + } + core.LogAndAddError(ctx, &resp.Diagnostics, "Error deleting user", fmt.Sprintf("error from API: %v", err)) } ctx = core.LogResponse(ctx) @@ -581,30 +544,6 @@ func (r *userResource) Delete( tflog.Info(ctx, "Postgres Flex user deleted") } -// IdentitySchema defines the fields that are required to uniquely identify a resource. -func (r *userResource) IdentitySchema( - _ context.Context, - _ resource.IdentitySchemaRequest, - response *resource.IdentitySchemaResponse, -) { - response.IdentitySchema = identityschema.Schema{ - Attributes: map[string]identityschema.Attribute{ - "project_id": identityschema.StringAttribute{ - RequiredForImport: true, - }, - "region": identityschema.StringAttribute{ - RequiredForImport: true, - }, - "instance_id": identityschema.StringAttribute{ - RequiredForImport: true, - }, - "user_id": identityschema.Int64Attribute{ - RequiredForImport: true, - }, - }, - } -} - // clientArg holds the arguments for API calls. type clientArg struct { projectID string @@ -622,112 +561,41 @@ func (r *userResource) ImportState( ) { ctx = core.InitProviderContext(ctx) - if req.ID != "" { - idParts := strings.Split(req.ID, core.Separator) - - if len(idParts) != 4 || idParts[0] == "" || idParts[1] == "" || idParts[2] == "" || idParts[3] == "" { - core.LogAndAddError( - ctx, &resp.Diagnostics, - "Error importing user", - fmt.Sprintf( - "Expected import identifier with format [project_id],[region],[instance_id],[user_id], got %q", - req.ID, - ), - ) - return - } - - userID, err := strconv.ParseInt(idParts[3], 10, 64) - if err != nil { - core.LogAndAddError( - ctx, - &resp.Diagnostics, - "Error importing user", - fmt.Sprintf("Invalid user_id format: %q. It must be a valid integer.", idParts[3]), - ) - return - } - - resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("project_id"), idParts[0])...) - resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("region"), idParts[1])...) - resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("instance_id"), idParts[2])...) - resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("user_id"), userID)...) - - tflog.Info(ctx, "Postgres Flex user state imported") + idParts := strings.Split(req.ID, core.Separator) + if len(idParts) != 4 || idParts[0] == "" || idParts[1] == "" || idParts[2] == "" || idParts[3] == "" { + core.LogAndAddError( + ctx, &resp.Diagnostics, + "Error importing user", + fmt.Sprintf( + "Expected import identifier with format [project_id],[region],[instance_id],[user_id], got %q", + req.ID, + ), + ) return } - // If no ID is provided, attempt to read identity attributes from the import configuration - var identityData UserResourceIdentityModel - resp.Diagnostics.Append(req.Identity.Get(ctx, &identityData)...) - if resp.Diagnostics.HasError() { + userID, err := strconv.ParseInt(idParts[3], 10, 64) + if err != nil { + core.LogAndAddError( + ctx, + &resp.Diagnostics, + "Error importing user", + fmt.Sprintf("Invalid user_id format: %q. It must be a valid integer.", idParts[3]), + ) return } - projectID := identityData.ProjectID.ValueString() - region := identityData.Region.ValueString() - instanceID := identityData.InstanceID.ValueString() - userID := identityData.UserID.ValueInt64() - - resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("project_id"), projectID)...) - resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("region"), region)...) - resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("instance_id"), instanceID)...) + idString := utils.BuildInternalTerraformId(idParts...) + resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("id"), idString)...) + resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("project_id"), idParts[0])...) + resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("region"), idParts[1])...) + resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("instance_id"), idParts[2])...) resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("user_id"), userID)...) tflog.Info(ctx, "Postgres Flex user state imported") } -// extractIdentityData extracts essential identifiers from the resource model, falling back to the identity model. -func (r *userResource) extractIdentityData( - model resourceModel, - identity UserResourceIdentityModel, -) (*clientArg, error) { - var projectID, region, instanceID string - var userID int64 - if !model.UserId.IsNull() && !model.UserId.IsUnknown() { - userID = model.UserId.ValueInt64() - } else { - if identity.UserID.IsNull() || identity.UserID.IsUnknown() { - return nil, fmt.Errorf("user_id not found in config") - } - userID = identity.UserID.ValueInt64() - } - - if !model.ProjectId.IsNull() && !model.ProjectId.IsUnknown() { - projectID = model.ProjectId.ValueString() - } else { - if identity.ProjectID.IsNull() || identity.ProjectID.IsUnknown() { - return nil, fmt.Errorf("project_id not found in config") - } - projectID = identity.ProjectID.ValueString() - } - - if !model.Region.IsNull() && !model.Region.IsUnknown() { - region = r.providerData.GetRegionWithOverride(model.Region) - } else { - if identity.Region.IsNull() || identity.Region.IsUnknown() { - return nil, fmt.Errorf("region not found in config") - } - region = r.providerData.GetRegionWithOverride(identity.Region) - } - - if !model.InstanceId.IsNull() && !model.InstanceId.IsUnknown() { - instanceID = model.InstanceId.ValueString() - } else { - if identity.InstanceID.IsNull() || identity.InstanceID.IsUnknown() { - return nil, fmt.Errorf("instance_id not found in config") - } - instanceID = identity.InstanceID.ValueString() - } - return &clientArg{ - projectID: projectID, - instanceID: instanceID, - region: region, - userID: userID, - }, nil -} - // setTFLogFields adds relevant fields to the context for terraform logging purposes. func (r *userResource) setTFLogFields(ctx context.Context, arg *clientArg) context.Context { ctx = tflog.SetField(ctx, "project_id", arg.projectID) diff --git a/stackit/internal/services/postgresflexalpha/user/resources_gen/user_resource_gen.go b/stackit/internal/services/postgresflexalpha/user/resources_gen/user_resource_gen.go index f96d8d93..3e2d1e63 100644 --- a/stackit/internal/services/postgresflexalpha/user/resources_gen/user_resource_gen.go +++ b/stackit/internal/services/postgresflexalpha/user/resources_gen/user_resource_gen.go @@ -14,7 +14,7 @@ import ( func UserResourceSchema(ctx context.Context) schema.Schema { return schema.Schema{ Attributes: map[string]schema.Attribute{ - "id": schema.Int64Attribute{ + "id": schema.StringAttribute{ Computed: true, Description: "The ID of the user.", MarkdownDescription: "The ID of the user.", @@ -75,7 +75,7 @@ func UserResourceSchema(ctx context.Context) schema.Schema { } type UserModel struct { - Id types.Int64 `tfsdk:"id"` + Id types.String `tfsdk:"id"` InstanceId types.String `tfsdk:"instance_id"` Name types.String `tfsdk:"name"` Password types.String `tfsdk:"password"` diff --git a/stackit/internal/services/sqlserverflexalpha/sqlserverflex_acc_test.go b/stackit/internal/services/sqlserverflexalpha/sqlserverflex_acc_test.go index f6971fd1..a8b0d874 100644 --- a/stackit/internal/services/sqlserverflexalpha/sqlserverflex_acc_test.go +++ b/stackit/internal/services/sqlserverflexalpha/sqlserverflex_acc_test.go @@ -198,10 +198,10 @@ func TestAccInstanceNoEncryption(t *testing.T) { Roles: []string{ "##STACKIT_DatabaseManager##", "##STACKIT_LoginManager##", - //"##STACKIT_ProcessManager##", - //"##STACKIT_SQLAgentManager##", - //"##STACKIT_SQLAgentUser##", - //"##STACKIT_ServerManager##", + // "##STACKIT_ProcessManager##", + // "##STACKIT_SQLAgentManager##", + // "##STACKIT_SQLAgentUser##", + // "##STACKIT_ServerManager##", }, }, } diff --git a/stackit/internal/services/sqlserverflexbeta/instance/functions.go b/stackit/internal/services/sqlserverflexbeta/instance/functions.go index 18ad8dc0..b079d741 100644 --- a/stackit/internal/services/sqlserverflexbeta/instance/functions.go +++ b/stackit/internal/services/sqlserverflexbeta/instance/functions.go @@ -11,6 +11,8 @@ import ( "github.com/hashicorp/terraform-plugin-framework/resource" "github.com/hashicorp/terraform-plugin-framework/types" + "tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit/internal/utils" + "github.com/stackitcloud/stackit-sdk-go/services/sqlserverflex/v3beta1api" sqlserverflexbetaDataGen "tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit/internal/services/sqlserverflexbeta/instance/datasources_gen" @@ -27,7 +29,7 @@ func mapResponseToModel( m.Edition = types.StringValue(string(resp.GetEdition())) m.Encryption = handleEncryption(ctx, m, resp) m.FlavorId = types.StringValue(resp.GetFlavorId()) - m.Id = types.StringValue(resp.GetId()) + m.Id = utils.BuildInternalTerraformId(m.ProjectId.ValueString(), m.Region.ValueString(), resp.GetId()) m.InstanceId = types.StringValue(resp.GetId()) m.IsDeletable = types.BoolValue(resp.GetIsDeletable()) m.Name = types.StringValue(resp.GetName()) diff --git a/stackit/internal/services/sqlserverflexbeta/instance/resource.go b/stackit/internal/services/sqlserverflexbeta/instance/resource.go index a824aabf..63bfb383 100644 --- a/stackit/internal/services/sqlserverflexbeta/instance/resource.go +++ b/stackit/internal/services/sqlserverflexbeta/instance/resource.go @@ -10,7 +10,6 @@ import ( "github.com/hashicorp/terraform-plugin-framework/path" "github.com/hashicorp/terraform-plugin-framework/resource" - "github.com/hashicorp/terraform-plugin-framework/resource/identityschema" "github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-plugin-log/tflog" "github.com/stackitcloud/stackit-sdk-go/core/config" @@ -32,7 +31,6 @@ var ( _ resource.ResourceWithConfigure = &instanceResource{} _ resource.ResourceWithImportState = &instanceResource{} _ resource.ResourceWithModifyPlan = &instanceResource{} - _ resource.ResourceWithIdentity = &instanceResource{} ) func NewInstanceResource() resource.Resource { @@ -47,12 +45,6 @@ type instanceResource struct { // resourceModel describes the resource data model. type resourceModel = sqlserverflexbetaResGen.InstanceModel -type InstanceResourceIdentityModel struct { - ProjectID types.String `tfsdk:"project_id"` - Region types.String `tfsdk:"region"` - InstanceID types.String `tfsdk:"instance_id"` -} - func (r *instanceResource) Metadata( _ context.Context, req resource.MetadataRequest, @@ -81,26 +73,6 @@ func (r *instanceResource) Schema(ctx context.Context, _ resource.SchemaRequest, resp.Schema = s } -func (r *instanceResource) IdentitySchema( - _ context.Context, - _ resource.IdentitySchemaRequest, - resp *resource.IdentitySchemaResponse, -) { - resp.IdentitySchema = identityschema.Schema{ - Attributes: map[string]identityschema.Attribute{ - "project_id": identityschema.StringAttribute{ - RequiredForImport: true, // must be set during import by the practitioner - }, - "region": identityschema.StringAttribute{ - RequiredForImport: true, // can be defaulted by the provider configuration - }, - "instance_id": identityschema.StringAttribute{ - RequiredForImport: true, // can be defaulted by the provider configuration - }, - }, - } -} - // Configure adds the provider configured client to the resource. func (r *instanceResource) Configure( ctx context.Context, @@ -190,9 +162,9 @@ func (r *instanceResource) Create(ctx context.Context, req resource.CreateReques ctx = core.InitProviderContext(ctx) - projectId := data.ProjectId.ValueString() + projectID := data.ProjectId.ValueString() region := data.Region.ValueString() - ctx = tflog.SetField(ctx, "project_id", projectId) + ctx = tflog.SetField(ctx, "project_id", projectID) ctx = tflog.SetField(ctx, "region", region) // Generate API request body from model @@ -210,7 +182,7 @@ func (r *instanceResource) Create(ctx context.Context, req resource.CreateReques // Create new Instance createResp, err := r.client.DefaultAPI.CreateInstanceRequest( ctx, - projectId, + projectID, region, ).CreateInstanceRequestPayload(*payload).Execute() if err != nil { @@ -220,24 +192,25 @@ func (r *instanceResource) Create(ctx context.Context, req resource.CreateReques ctx = core.LogResponse(ctx) - instanceId := createResp.Id - data.InstanceId = types.StringValue(instanceId) + instanceID := createResp.Id + data.InstanceId = types.StringValue(instanceID) + data.Id = utils.BuildInternalTerraformId(projectID, region, instanceID) - identity := InstanceResourceIdentityModel{ - ProjectID: types.StringValue(projectId), - Region: types.StringValue(region), - InstanceID: types.StringValue(instanceId), - } - resp.Diagnostics.Append(resp.Identity.Set(ctx, identity)...) - if resp.Diagnostics.HasError() { - return - } + // Set data returned by API in id + resp.Diagnostics.Append( + resp.State.SetAttribute( + ctx, + path.Root("id"), + utils.BuildInternalTerraformId(projectID, region, instanceID), + )..., + ) + resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("instance_id"), instanceID)...) waitResp, err := wait.CreateInstanceWaitHandler( ctx, r.client.DefaultAPI, - projectId, - instanceId, + projectID, + instanceID, region, ).SetSleepBeforeWait( 10 * time.Second, @@ -293,15 +266,15 @@ func (r *instanceResource) Read(ctx context.Context, req resource.ReadRequest, r ctx = core.InitProviderContext(ctx) - projectId := data.ProjectId.ValueString() + projectID := data.ProjectId.ValueString() region := data.Region.ValueString() - ctx = tflog.SetField(ctx, "project_id", projectId) + ctx = tflog.SetField(ctx, "project_id", projectID) ctx = tflog.SetField(ctx, "region", region) - instanceId := data.InstanceId.ValueString() - ctx = tflog.SetField(ctx, "instance_id", instanceId) + instanceID := data.InstanceId.ValueString() + ctx = tflog.SetField(ctx, "instance_id", instanceID) - instanceResp, err := r.client.DefaultAPI.GetInstanceRequest(ctx, projectId, region, instanceId).Execute() + instanceResp, err := r.client.DefaultAPI.GetInstanceRequest(ctx, projectID, region, instanceID).Execute() if err != nil { oapiErr, ok := err.(*oapierror.GenericOpenAPIError) //nolint:errorlint //complaining that error.As should be used to catch wrapped errors, but this error should not be wrapped if ok && oapiErr.StatusCode == http.StatusNotFound { @@ -326,17 +299,6 @@ func (r *instanceResource) Read(ctx context.Context, req resource.ReadRequest, r return } - // Save identity into Terraform state - identity := InstanceResourceIdentityModel{ - ProjectID: types.StringValue(projectId), - Region: types.StringValue(region), - InstanceID: types.StringValue(instanceId), - } - resp.Diagnostics.Append(resp.Identity.Set(ctx, identity)...) - if resp.Diagnostics.HasError() { - return - } - // Save updated data into Terraform state resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) if resp.Diagnostics.HasError() { @@ -357,13 +319,13 @@ func (r *instanceResource) Update(ctx context.Context, req resource.UpdateReques ctx = core.InitProviderContext(ctx) - projectId := data.ProjectId.ValueString() + projectID := data.ProjectId.ValueString() region := data.Region.ValueString() - ctx = tflog.SetField(ctx, "project_id", projectId) + ctx = tflog.SetField(ctx, "project_id", projectID) ctx = tflog.SetField(ctx, "region", region) - instanceId := data.InstanceId.ValueString() - ctx = tflog.SetField(ctx, "instance_id", instanceId) + instanceID := data.InstanceId.ValueString() + ctx = tflog.SetField(ctx, "instance_id", instanceID) // Generate API request body from model payload, err := toUpdatePayload(ctx, &data, resp) @@ -379,9 +341,9 @@ func (r *instanceResource) Update(ctx context.Context, req resource.UpdateReques // Update existing instance err = r.client.DefaultAPI.UpdateInstanceRequest( ctx, - projectId, + projectID, region, - instanceId, + instanceID, ).UpdateInstanceRequestPayload(*payload).Execute() if err != nil { core.LogAndAddError(ctx, &resp.Diagnostics, updateInstanceError, err.Error()) @@ -391,7 +353,7 @@ func (r *instanceResource) Update(ctx context.Context, req resource.UpdateReques ctx = core.LogResponse(ctx) waitResp, err := wait. - UpdateInstanceWaitHandler(ctx, r.client.DefaultAPI, projectId, instanceId, region). + UpdateInstanceWaitHandler(ctx, r.client.DefaultAPI, projectID, instanceID, region). SetSleepBeforeWait(15 * time.Second). SetTimeout(45 * time.Minute). WaitWithContext(ctx) @@ -417,16 +379,6 @@ func (r *instanceResource) Update(ctx context.Context, req resource.UpdateReques return } - identity := InstanceResourceIdentityModel{ - ProjectID: types.StringValue(projectId), - Region: types.StringValue(region), - InstanceID: types.StringValue(instanceId), - } - resp.Diagnostics.Append(resp.Identity.Set(ctx, identity)...) - if resp.Diagnostics.HasError() { - return - } - // Save updated data into Terraform state resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) if resp.Diagnostics.HasError() { @@ -445,25 +397,18 @@ func (r *instanceResource) Delete(ctx context.Context, req resource.DeleteReques return } - // Read identity data - var identityData InstanceResourceIdentityModel - resp.Diagnostics.Append(req.Identity.Get(ctx, &identityData)...) - if resp.Diagnostics.HasError() { - return - } - ctx = core.InitProviderContext(ctx) - projectId := identityData.ProjectID.ValueString() - region := identityData.Region.ValueString() - ctx = tflog.SetField(ctx, "project_id", projectId) + projectID := data.ProjectId.ValueString() + region := data.Region.ValueString() + ctx = tflog.SetField(ctx, "project_id", projectID) ctx = tflog.SetField(ctx, "region", region) - instanceId := identityData.InstanceID.ValueString() - ctx = tflog.SetField(ctx, "instance_id", instanceId) + instanceID := data.InstanceId.ValueString() + ctx = tflog.SetField(ctx, "instance_id", instanceID) // Delete existing instance - err := r.client.DefaultAPI.DeleteInstanceRequest(ctx, projectId, region, instanceId).Execute() + err := r.client.DefaultAPI.DeleteInstanceRequest(ctx, projectID, region, instanceID).Execute() if err != nil { core.LogAndAddError(ctx, &resp.Diagnostics, "Error deleting instance", fmt.Sprintf("Calling API: %v", err)) return @@ -471,7 +416,7 @@ func (r *instanceResource) Delete(ctx context.Context, req resource.DeleteReques ctx = core.LogResponse(ctx) - delResp, err := wait.DeleteInstanceWaitHandler(ctx, r.client.DefaultAPI, projectId, instanceId, region).WaitWithContext(ctx) + delResp, err := wait.DeleteInstanceWaitHandler(ctx, r.client.DefaultAPI, projectID, instanceID, region).WaitWithContext(ctx) if err != nil { core.LogAndAddError( ctx, @@ -506,41 +451,24 @@ func (r *instanceResource) ImportState( ) { ctx = core.InitProviderContext(ctx) - if req.ID != "" { - idParts := strings.Split(req.ID, core.Separator) + idParts := strings.Split(req.ID, core.Separator) - if len(idParts) != 3 || idParts[0] == "" || idParts[1] == "" || idParts[2] == "" { - core.LogAndAddError( - ctx, &resp.Diagnostics, - "Error importing instance", - fmt.Sprintf( - "Expected import identifier with format [project_id],[region],[instance_id] Got: %q", - req.ID, - ), - ) - return - } - - resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("project_id"), idParts[0])...) - resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("region"), idParts[1])...) - resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("instance_id"), idParts[2])...) + if len(idParts) != 3 || idParts[0] == "" || idParts[1] == "" || idParts[2] == "" { + core.LogAndAddError( + ctx, &resp.Diagnostics, + "Error importing instance", + fmt.Sprintf( + "Expected import identifier with format [project_id],[region],[instance_id] Got: %q", + req.ID, + ), + ) return } - // If no ID is provided, attempt to read identity attributes from the import configuration - var identityData InstanceResourceIdentityModel - resp.Diagnostics.Append(req.Identity.Get(ctx, &identityData)...) - if resp.Diagnostics.HasError() { - return - } - - projectId := identityData.ProjectID.ValueString() - region := identityData.Region.ValueString() - instanceId := identityData.InstanceID.ValueString() - - resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("project_id"), projectId)...) - resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("region"), region)...) - resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("instance_id"), instanceId)...) + resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("id"), utils.BuildInternalTerraformId(idParts...).ValueString())...) + resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("project_id"), idParts[0])...) + resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("region"), idParts[1])...) + resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("instance_id"), idParts[2])...) tflog.Info(ctx, "Sqlserverflexbeta instance state imported") } diff --git a/stackit/internal/services/sqlserverflexbeta/sqlserverflex_acc_test.go b/stackit/internal/services/sqlserverflexbeta/sqlserverflex_acc_test.go index c12bfa5d..0d3d8c99 100644 --- a/stackit/internal/services/sqlserverflexbeta/sqlserverflex_acc_test.go +++ b/stackit/internal/services/sqlserverflexbeta/sqlserverflex_acc_test.go @@ -3,13 +3,32 @@ package sqlserverflexbeta_test import ( "context" _ "embed" + "errors" "fmt" + "log" + "net/http" "os" "strconv" + "strings" "testing" + "time" + "github.com/hashicorp/terraform-plugin-testing/compare" "github.com/hashicorp/terraform-plugin-testing/helper/acctest" "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/hashicorp/terraform-plugin-testing/knownvalue" + "github.com/hashicorp/terraform-plugin-testing/plancheck" + "github.com/hashicorp/terraform-plugin-testing/statecheck" + "github.com/hashicorp/terraform-plugin-testing/terraform" + "github.com/hashicorp/terraform-plugin-testing/tfjsonpath" + "github.com/stackitcloud/stackit-sdk-go/core/config" + "github.com/stackitcloud/stackit-sdk-go/core/oapierror" + "github.com/stackitcloud/stackit-sdk-go/core/utils" + + "tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit/internal/core" + wait "tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit/internal/wait/sqlserverflexbeta" + + "github.com/stackitcloud/stackit-sdk-go/services/sqlserverflex/v3beta1api" "tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/internal/testutils" sqlserverflexbeta "tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit/internal/services/sqlserverflexbeta/instance" @@ -20,7 +39,7 @@ import ( fwresource "github.com/hashicorp/terraform-plugin-framework/resource" ) -const providerPrefix = "stackitprivatepreview_sqlserverflexbeta" +const pfx = "stackitprivatepreview_sqlserverflexbeta" func TestInstanceResourceSchema(t *testing.T) { t.Parallel() @@ -59,20 +78,20 @@ func testAccPreCheck(t *testing.T) { type resData struct { ServiceAccountFilePath string - ProjectId string + ProjectID string Region string Name string TfName string - FlavorId string + FlavorID string BackupSchedule string UseEncryption bool - KekKeyId string - KekKeyRingId string + KekKeyID string + KekKeyRingID string KekKeyVersion uint8 KekServiceAccount string PerformanceClass string Size uint32 - AclString string + ACLStrings []string AccessScope string RetentionDays uint32 Version string @@ -82,37 +101,33 @@ type resData struct { type User struct { Name string - ProjectId string + ProjectID string Roles []string } type Database struct { Name string - ProjectId string + ProjectID string Owner string Collation string Compatibility string } -func resName(res, name string) string { - return fmt.Sprintf("%s_%s.%s", providerPrefix, res, name) -} - func getExample() resData { name := acctest.RandomWithPrefix("tf-acc") return resData{ Region: os.Getenv("TF_ACC_REGION"), ServiceAccountFilePath: os.Getenv("TF_ACC_SERVICE_ACCOUNT_FILE"), - ProjectId: os.Getenv("TF_ACC_PROJECT_ID"), + ProjectID: os.Getenv("TF_ACC_PROJECT_ID"), Name: name, TfName: name, - FlavorId: "4.16-Single", + FlavorID: "4.16-Single", BackupSchedule: "0 0 * * *", UseEncryption: false, RetentionDays: 33, PerformanceClass: "premium-perf2-stackit", Size: 10, - AclString: "0.0.0.0/0", + ACLStrings: []string{"0.0.0.0/0"}, AccessScope: "PUBLIC", Version: "2022", } @@ -127,118 +142,160 @@ func TestAccInstance(t *testing.T) { updSizeData := exData updSizeData.Size = 25 + testInstanceID := testutils.ResStr(pfx, "instance", exData.TfName) + + compareValuesSame := statecheck.CompareValue(compare.ValuesSame()) resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) - t.Logf(" ... working on instance %s", exData.TfName) + t.Logf(" ... %s - %s", t.Name(), exData.TfName) }, + CheckDestroy: testAccCheckSQLServerFlexDestroy, ProtoV6ProviderFactories: testutils.TestAccProtoV6ProviderFactories, Steps: []resource.TestStep{ // Create and verify { + PreConfig: func() { + t.Logf("testing: %s - %s", t.Name(), "create and verify") + }, + ExpectNonEmptyPlan: true, Config: testutils.StringFromTemplateMust( "testdata/instance_template.gompl", exData, ), - Check: resource.ComposeAggregateTestCheckFunc( - resource.TestCheckResourceAttr(resName("instance", exData.TfName), "name", exData.Name), - resource.TestCheckResourceAttrSet(resName("instance", exData.TfName), "id"), - // TODO: check all fields - ), + ConfigStateChecks: []statecheck.StateCheck{ + compareValuesSame.AddStateValue( + testInstanceID, + tfjsonpath.New("id"), + ), + statecheck.ExpectKnownValue( + testInstanceID, + tfjsonpath.New("is_deletable"), + knownvalue.Bool(true), + ), + }, + Check: defaultNoEncInstanceTestChecks(testInstanceID, exData), }, // Update name and verify { + PreConfig: func() { + t.Logf("testing: %s - %s", t.Name(), "update name and verify") + }, + ExpectNonEmptyPlan: true, Config: testutils.StringFromTemplateMust( "testdata/instance_template.gompl", updNameData, ), + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectNonEmptyPlan(), + }, + }, Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr(resName("instance", exData.TfName), "name", updNameData.Name), + defaultNoEncInstanceTestChecks(testInstanceID, updNameData), ), }, // Update size and verify { + PreConfig: func() { + t.Logf("testing: %s - %s", t.Name(), "update storage.size and verify") + }, + ExpectNonEmptyPlan: true, Config: testutils.StringFromTemplateMust( "testdata/instance_template.gompl", updSizeData, ), Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr( - testutils.ResStr(providerPrefix, "instance", exData.TfName), - "storage.size", - strconv.Itoa(int(updSizeData.Size)), - ), + defaultNoEncInstanceTestChecks(testInstanceID, updSizeData), ), }, + // Import test + // test instance imports { - RefreshState: true, + PreConfig: func() { + t.Logf("testing: %s - %s", t.Name(), "import instance") + }, + ResourceName: testInstanceID, + // ImportStateIdPrefix: "", + // ImportStateVerifyIdentifierAttribute: "id", + ImportStateIdFunc: getInstanceTestID(exData.TfName), + ImportStateKind: resource.ImportCommandWithID, + ImportState: true, + ImportStateVerify: true, }, - //// Import test - //{ - // ResourceName: resName("instance", exData.TfName), - // ImportState: true, - // ImportStateVerify: true, - // }, }, }) } func TestAccInstanceReApply(t *testing.T) { exData := getExample() + testInstanceID := testutils.ResStr(pfx, "instance", exData.TfName) + compareValuesSame := statecheck.CompareValue(compare.ValuesSame()) resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) - t.Logf(" ... working on instance %s", exData.TfName) + t.Logf(" ... %s - %s", t.Name(), exData.TfName) }, + CheckDestroy: testAccCheckSQLServerFlexDestroy, ProtoV6ProviderFactories: testutils.TestAccProtoV6ProviderFactories, Steps: []resource.TestStep{ // Create and verify { + PreConfig: func() { + t.Logf("testing: %s - %s", t.Name(), "create and verify") + }, Config: testutils.StringFromTemplateMust( "testdata/instance_template.gompl", exData, ), - Check: resource.ComposeAggregateTestCheckFunc( - resource.TestCheckResourceAttr(resName("instance", exData.TfName), "name", exData.Name), - resource.TestCheckResourceAttrSet(resName("instance", exData.TfName), "id"), - // TODO: check all fields - ), + ConfigStateChecks: []statecheck.StateCheck{ + compareValuesSame.AddStateValue( + testInstanceID, + tfjsonpath.New("id"), + ), + statecheck.ExpectKnownValue( + testInstanceID, + tfjsonpath.New("is_deletable"), + knownvalue.Bool(true), + ), + }, + Check: defaultNoEncInstanceTestChecks(testInstanceID, exData), }, - // Create and verify + // Second apply should not have changes { + PreConfig: func() { + t.Logf("testing: %s - %s", t.Name(), "second apply") + }, + ExpectNonEmptyPlan: false, + ResourceName: testInstanceID, Config: testutils.StringFromTemplateMust( "testdata/instance_template.gompl", exData, ), - Check: resource.ComposeAggregateTestCheckFunc( - resource.TestCheckResourceAttr(resName("instance", exData.TfName), "name", exData.Name), - resource.TestCheckResourceAttrSet(resName("instance", exData.TfName), "id"), - // TODO: check all fields - ), + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectEmptyPlan(), + }, + }, + ConfigStateChecks: []statecheck.StateCheck{ + compareValuesSame.AddStateValue( + testInstanceID, + tfjsonpath.New("id"), + ), + statecheck.ExpectKnownValue( + testInstanceID, + tfjsonpath.New("is_deletable"), + knownvalue.Bool(true), + ), + }, }, + // Refresh state test { + PreConfig: func() { + t.Logf("testing: %s - %s", t.Name(), "refresh state") + }, RefreshState: true, }, - // Create and verify - { - Config: testutils.StringFromTemplateMust( - "testdata/instance_template.gompl", - exData, - ), - Check: resource.ComposeAggregateTestCheckFunc( - resource.TestCheckResourceAttr(resName("instance", exData.TfName), "name", exData.Name), - resource.TestCheckResourceAttrSet(resName("instance", exData.TfName), "id"), - // TODO: check all fields - ), - }, - // Import test - { - ResourceName: resName("instance", exData.TfName), - ImportStateKind: resource.ImportBlockWithResourceIdentity, - ImportState: true, - // ImportStateVerify is not supported with plannable import blocks - // ImportStateVerify: true, - }, }, }) } @@ -251,7 +308,7 @@ func TestAccInstanceNoEncryption(t *testing.T) { data.Users = []User{ { Name: userName, - ProjectId: os.Getenv("TF_ACC_PROJECT_ID"), + ProjectID: os.Getenv("TF_ACC_PROJECT_ID"), Roles: []string{ "##STACKIT_DatabaseManager##", "##STACKIT_LoginManager##", @@ -265,16 +322,19 @@ func TestAccInstanceNoEncryption(t *testing.T) { data.Databases = []Database{ { Name: dbName, - ProjectId: os.Getenv("TF_ACC_PROJECT_ID"), + ProjectID: os.Getenv("TF_ACC_PROJECT_ID"), Owner: userName, }, } - + testInstanceID := testutils.ResStr(pfx, "instance", data.TfName) + testDatabaseID := testutils.ResStr(pfx, "database", dbName) + testUserID := testutils.ResStr(pfx, "user", userName) resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) - t.Logf(" ... working on instance %s", data.TfName) + t.Logf(" ... %s - %s", t.Name(), data.TfName) }, + CheckDestroy: testAccCheckSQLServerFlexDestroy, ProtoV6ProviderFactories: testutils.TestAccProtoV6ProviderFactories, Steps: []resource.TestStep{ // Create and verify @@ -284,62 +344,22 @@ func TestAccInstanceNoEncryption(t *testing.T) { data, ), Check: resource.ComposeAggregateTestCheckFunc( - // check instance values are set - resource.TestCheckResourceAttrSet(resName("instance", data.TfName), "id"), - resource.TestCheckResourceAttrSet(resName("instance", data.TfName), "backup_schedule"), - resource.TestCheckResourceAttrSet(resName("instance", data.TfName), "edition"), - resource.TestCheckResourceAttrSet(resName("instance", data.TfName), "flavor_id"), - resource.TestCheckResourceAttrSet(resName("instance", data.TfName), "instance_id"), - resource.TestCheckResourceAttrSet(resName("instance", data.TfName), "is_deletable"), - resource.TestCheckResourceAttrSet(resName("instance", data.TfName), "name"), - resource.TestCheckResourceAttrSet(resName("instance", data.TfName), "replicas"), - resource.TestCheckResourceAttrSet(resName("instance", data.TfName), "retention_days"), - resource.TestCheckResourceAttrSet(resName("instance", data.TfName), "status"), - resource.TestCheckResourceAttrSet(resName("instance", data.TfName), "version"), - - resource.TestCheckNoResourceAttr(resName("instance", data.TfName), "encryption"), - - // resource.TestCheckResourceAttrSet(resName("instance", data.TfName), "encryption"), - // resource.TestCheckResourceAttrSet(resName("instance", data.TfName), "encryption.kek_key_id"), - // resource.TestCheckResourceAttrSet(resName("instance", data.TfName), "encryption.kek_key_version"), - // resource.TestCheckResourceAttrSet(resName("instance", data.TfName), "encryption.kek_key_ring_id"), - // resource.TestCheckResourceAttrSet(resName("instance", data.TfName), "encryption.service_account"), - - // resource.TestCheckResourceAttrSet(resName("instance", data.TfName), "network.access_scope"), - // resource.TestCheckResourceAttrSet(resName("instance", data.TfName), "network.acl"), - - // resource.TestCheckResourceAttrSet(resName("instance", data.TfName), "network.instance_address"), - // resource.TestCheckResourceAttrSet(resName("instance", data.TfName), "network.router_address"), - - // resource.TestCheckResourceAttrSet(resName("instance", data.TfName), "storage.class"), - // resource.TestCheckResourceAttrSet(resName("instance", data.TfName), "storage.size"), - - // check instance values are correct - resource.TestCheckResourceAttr(resName("instance", data.TfName), "name", data.Name), - - // check user values are set - resource.TestCheckResourceAttrSet(resName("user", userName), "id"), - resource.TestCheckResourceAttrSet(resName("user", userName), "username"), - // resource.TestCheckResourceAttrSet(resName("user", userName), "roles"), - - // func(s *terraform.State) error { - // return nil - // }, + defaultNoEncInstanceTestChecks(testInstanceID, data), // check user values are correct - resource.TestCheckResourceAttr(resName("user", userName), "username", userName), - resource.TestCheckResourceAttr(resName("user", userName), "roles.#", strconv.Itoa(len(data.Users[0].Roles))), + resource.TestCheckResourceAttr(testUserID, "username", userName), + resource.TestCheckResourceAttr(testUserID, "roles.#", strconv.Itoa(len(data.Users[0].Roles))), // check database values are set - resource.TestCheckResourceAttrSet(resName("database", dbName), "id"), - resource.TestCheckResourceAttrSet(resName("database", dbName), "name"), - resource.TestCheckResourceAttrSet(resName("database", dbName), "owner"), - resource.TestCheckResourceAttrSet(resName("database", dbName), "compatibility"), - resource.TestCheckResourceAttrSet(resName("database", dbName), "collation"), + resource.TestCheckResourceAttrSet(testDatabaseID, "id"), + resource.TestCheckResourceAttrSet(testDatabaseID, "name"), + resource.TestCheckResourceAttrSet(testDatabaseID, "owner"), + resource.TestCheckResourceAttrSet(testDatabaseID, "compatibility"), + resource.TestCheckResourceAttrSet(testDatabaseID, "collation"), // check database values are correct - resource.TestCheckResourceAttr(resName("database", dbName), "name", dbName), - resource.TestCheckResourceAttr(resName("database", dbName), "owner", userName), + resource.TestCheckResourceAttr(testDatabaseID, "name", dbName), + resource.TestCheckResourceAttr(testDatabaseID, "owner", userName), ), }, }, @@ -354,29 +374,34 @@ func TestAccInstanceEncryption(t *testing.T) { data.Users = []User{ { Name: userName, - ProjectId: os.Getenv("TF_ACC_PROJECT_ID"), + ProjectID: os.Getenv("TF_ACC_PROJECT_ID"), Roles: []string{"##STACKIT_DatabaseManager##", "##STACKIT_LoginManager##"}, }, } data.Databases = []Database{ { Name: dbName, - ProjectId: os.Getenv("TF_ACC_PROJECT_ID"), + ProjectID: os.Getenv("TF_ACC_PROJECT_ID"), Owner: userName, }, } data.UseEncryption = true - data.KekKeyId = "fe039bcf-8d7b-431a-801d-9e81371a6b7b" - data.KekKeyRingId = "6a2d95ab-3c4c-4963-a2bb-08d17a320e27" + data.KekKeyID = "fe039bcf-8d7b-431a-801d-9e81371a6b7b" + data.KekKeyRingID = "6a2d95ab-3c4c-4963-a2bb-08d17a320e27" data.KekKeyVersion = 1 data.KekServiceAccount = "henselinm-u2v3ex1@sa.stackit.cloud" + testInstanceID := testutils.ResStr(pfx, "instance", data.TfName) + testDatabaseID := testutils.ResStr(pfx, "database", dbName) + testUserID := testutils.ResStr(pfx, "user", userName) + resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) - t.Logf(" ... working on instance %s", data.TfName) + t.Logf(" ... %s - %s", t.Name(), data.TfName) }, + CheckDestroy: testAccCheckSQLServerFlexDestroy, ProtoV6ProviderFactories: testutils.TestAccProtoV6ProviderFactories, Steps: []resource.TestStep{ // Create and verify @@ -386,61 +411,296 @@ func TestAccInstanceEncryption(t *testing.T) { data, ), Check: resource.ComposeAggregateTestCheckFunc( - // check instance values are set - resource.TestCheckResourceAttrSet(resName("instance", data.TfName), "id"), - resource.TestCheckResourceAttrSet(resName("instance", data.TfName), "backup_schedule"), - resource.TestCheckResourceAttrSet(resName("instance", data.TfName), "edition"), - resource.TestCheckResourceAttrSet(resName("instance", data.TfName), "flavor_id"), - resource.TestCheckResourceAttrSet(resName("instance", data.TfName), "instance_id"), - resource.TestCheckResourceAttrSet(resName("instance", data.TfName), "is_deletable"), - resource.TestCheckResourceAttrSet(resName("instance", data.TfName), "name"), - resource.TestCheckResourceAttrSet(resName("instance", data.TfName), "replicas"), - resource.TestCheckResourceAttrSet(resName("instance", data.TfName), "retention_days"), - resource.TestCheckResourceAttrSet(resName("instance", data.TfName), "status"), - resource.TestCheckResourceAttrSet(resName("instance", data.TfName), "version"), - - // resource.TestCheckResourceAttrSet(resName("instance", data.TfName), "encryption"), - // resource.TestCheckResourceAttrSet(resName("instance", data.TfName), "encryption.kek_key_id"), - // resource.TestCheckResourceAttrSet(resName("instance", data.TfName), "encryption.kek_key_version"), - // resource.TestCheckResourceAttrSet(resName("instance", data.TfName), "encryption.kek_key_ring_id"), - // resource.TestCheckResourceAttrSet(resName("instance", data.TfName), "encryption.service_account"), - - // resource.TestCheckResourceAttrSet(resName("instance", data.TfName), "network.access_scope"), - // resource.TestCheckResourceAttrSet(resName("instance", data.TfName), "network.acl"), - - // resource.TestCheckResourceAttrSet(resName("instance", data.TfName), "network.instance_address"), - // resource.TestCheckResourceAttrSet(resName("instance", data.TfName), "network.router_address"), - - // resource.TestCheckResourceAttrSet(resName("instance", data.TfName), "storage.class"), - // resource.TestCheckResourceAttrSet(resName("instance", data.TfName), "storage.size"), - - // check instance values are correct - resource.TestCheckResourceAttr(resName("instance", data.TfName), "name", data.Name), + defaultEncInstanceTestChecks(testInstanceID, data), // check user values are set - resource.TestCheckResourceAttrSet(resName("user", userName), "id"), - resource.TestCheckResourceAttrSet(resName("user", userName), "username"), + resource.TestCheckResourceAttrSet(testUserID, "id"), + resource.TestCheckResourceAttrSet(testUserID, "username"), // func(s *terraform.State) error { // return nil // }, // check user values are correct - resource.TestCheckResourceAttr(resName("user", userName), "username", userName), - resource.TestCheckResourceAttr(resName("user", userName), "roles.#", "2"), + resource.TestCheckResourceAttr(testUserID, "username", userName), + resource.TestCheckResourceAttr(testUserID, "roles.#", "2"), // check database values are set - resource.TestCheckResourceAttrSet(resName("database", dbName), "id"), - resource.TestCheckResourceAttrSet(resName("database", dbName), "name"), - resource.TestCheckResourceAttrSet(resName("database", dbName), "owner"), - resource.TestCheckResourceAttrSet(resName("database", dbName), "compatibility"), - resource.TestCheckResourceAttrSet(resName("database", dbName), "collation"), + resource.TestCheckResourceAttrSet(testDatabaseID, "id"), + resource.TestCheckResourceAttrSet(testDatabaseID, "name"), + resource.TestCheckResourceAttrSet(testDatabaseID, "owner"), + resource.TestCheckResourceAttrSet(testDatabaseID, "compatibility"), + resource.TestCheckResourceAttrSet(testDatabaseID, "collation"), // check database values are correct - resource.TestCheckResourceAttr(resName("database", dbName), "name", dbName), - resource.TestCheckResourceAttr(resName("database", dbName), "owner", userName), + resource.TestCheckResourceAttr(testDatabaseID, "name", dbName), + resource.TestCheckResourceAttr(testDatabaseID, "owner", userName), ), }, }, }) } + +func defaultNoEncInstanceTestChecks(testItemID string, data resData) resource.TestCheckFunc { + return resource.ComposeAggregateTestCheckFunc( + defaultInstanceTestChecks(testItemID, data), + + // check absent attr + resource.TestCheckNoResourceAttr(testItemID, "encryption"), + resource.TestCheckNoResourceAttr(testItemID, "encryption.kek_key_id"), + resource.TestCheckNoResourceAttr(testItemID, "encryption.kek_key_ring_id"), + resource.TestCheckNoResourceAttr(testItemID, "encryption.kek_key_version"), + resource.TestCheckNoResourceAttr(testItemID, "encryption.service_account"), + ) +} + +func defaultEncInstanceTestChecks(testItemID string, data resData) resource.TestCheckFunc { + return resource.ComposeAggregateTestCheckFunc( + defaultInstanceTestChecks(testItemID, data), + + // check absent attr + resource.TestCheckResourceAttr(testItemID, "encryption.%", "4"), + resource.TestCheckResourceAttrSet(testItemID, "encryption.kek_key_id"), + resource.TestCheckResourceAttr(testItemID, "encryption.kek_key_id", data.KekKeyID), + resource.TestCheckResourceAttrSet(testItemID, "encryption.kek_key_ring_id"), + resource.TestCheckResourceAttr(testItemID, "encryption.kek_key_ring_id", data.KekKeyRingID), + resource.TestCheckResourceAttrSet(testItemID, "encryption.kek_key_version"), + resource.TestCheckResourceAttr(testItemID, "encryption.kek_key_version", strconv.Itoa(int(data.KekKeyVersion))), + resource.TestCheckResourceAttrSet(testItemID, "encryption.service_account"), + resource.TestCheckResourceAttr(testItemID, "encryption.service_account", data.KekServiceAccount), + ) +} + +func defaultInstanceTestChecks(testItemID string, data resData) resource.TestCheckFunc { + // if AccessScope == SNA these are set + if data.AccessScope == "SNA" { + return resource.ComposeAggregateTestCheckFunc( + basicInstanceTestChecks(testItemID, data), + resource.TestCheckResourceAttrSet(testItemID, "network.instance_address"), + resource.TestCheckResourceAttrSet(testItemID, "network.router_address"), + ) + } + + // if AccessScope == PUBLIC these are empty - but they are set + return resource.ComposeAggregateTestCheckFunc( + basicInstanceTestChecks(testItemID, data), + resource.TestCheckResourceAttr(testItemID, "network.instance_address", ""), + resource.TestCheckResourceAttr(testItemID, "network.router_address", ""), + ) +} + +func basicInstanceTestChecks(testItemID string, data resData) resource.TestCheckFunc { + return resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttrSet(testItemID, "backup_schedule"), + resource.TestCheckResourceAttr(testItemID, "backup_schedule", data.BackupSchedule), + + resource.TestCheckResourceAttrSet(testItemID, "flavor_id"), + resource.TestCheckResourceAttr(testItemID, "flavor_id", data.FlavorID), + + resource.TestCheckResourceAttrSet(testItemID, "id"), + resource.TestCheckResourceAttrSet(testItemID, "instance_id"), + + resource.TestCheckResourceAttrSet(testItemID, "edition"), + + resource.TestCheckResourceAttrSet(testItemID, "is_deletable"), + resource.TestCheckResourceAttr(testItemID, "is_deletable", "true"), + + resource.TestCheckResourceAttrSet(testItemID, "name"), + resource.TestCheckResourceAttr(testItemID, "name", data.Name), + + // network params check + resource.TestCheckResourceAttr(testItemID, "network.%", "4"), + resource.TestCheckResourceAttrSet(testItemID, "network.access_scope"), + resource.TestCheckResourceAttr(testItemID, "network.access_scope", data.AccessScope), + // resource.TestCheckResourceAttrSet(testItemID, "network.acl"), + resource.TestCheckResourceAttr(testItemID, "network.acl.#", strconv.Itoa(len(data.ACLStrings))), + // instance_address and router_address are only checked in enc + + resource.TestCheckResourceAttrSet(testItemID, "project_id"), + resource.TestCheckResourceAttr(testItemID, "project_id", data.ProjectID), + + resource.TestCheckResourceAttrSet(testItemID, "region"), + resource.TestCheckResourceAttr(testItemID, "region", data.Region), + + resource.TestCheckResourceAttrSet(testItemID, "retention_days"), + resource.TestCheckResourceAttr(testItemID, "retention_days", strconv.Itoa(int(data.RetentionDays))), + + resource.TestCheckResourceAttrSet(testItemID, "status"), + resource.TestCheckResourceAttr(testItemID, "status", "READY"), + + // storage params check + resource.TestCheckResourceAttr(testItemID, "storage.%", "2"), + resource.TestCheckResourceAttrSet(testItemID, "storage.class"), + resource.TestCheckResourceAttr(testItemID, "storage.class", data.PerformanceClass), + resource.TestCheckResourceAttrSet(testItemID, "storage.size"), + resource.TestCheckResourceAttr(testItemID, "storage.size", strconv.Itoa(int(data.Size))), + + resource.TestCheckResourceAttrSet(testItemID, "version"), + resource.TestCheckResourceAttr(testItemID, "version", data.Version), + ) +} + +func getInstanceTestID(name string) func(s *terraform.State) (string, error) { + return func(s *terraform.State) (string, error) { + r, ok := s.RootModule().Resources[testutils.ResStr(pfx, "instance", name)] + if !ok { + return "", fmt.Errorf("couldn't find resource stackitprivatepreview_postgresflexalpha_instance.%s", name) + } + projectID, ok := r.Primary.Attributes["project_id"] + if !ok { + return "", fmt.Errorf("couldn't find attribute project_id") + } + 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,%s", projectID, region, instanceID), nil + } +} + +/* + func getDatabaseTestID(name string) func(s *terraform.State) (string, error) { + return func(s *terraform.State) (string, error) { + r, ok := s.RootModule().Resources[testutils.ResStr(pfx, "database", name)] + if !ok { + return "", fmt.Errorf("couldn't find resource stackitprivatepreview_postgresflexalpha_instance.%s", name) + } + projectID, ok := r.Primary.Attributes["project_id"] + if !ok { + return "", fmt.Errorf("couldn't find attribute project_id") + } + 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") + } + databaseID, ok := r.Primary.Attributes["database_id"] + if !ok { + return "", fmt.Errorf("couldn't find attribute database_id") + } + return fmt.Sprintf("%s,%s,%s,%s", projectID, region, instanceID, databaseID), nil + } + } + + func getUserTestID(name string) func(s *terraform.State) (string, error) { + return func(s *terraform.State) (string, error) { + r, ok := s.RootModule().Resources[testutils.ResStr(pfx, "user", name)] + if !ok { + return "", fmt.Errorf("couldn't find resource stackitprivatepreview_postgresflexalpha_instance.%s", name) + } + projectID, ok := r.Primary.Attributes["project_id"] + if !ok { + return "", fmt.Errorf("couldn't find attribute project_id") + } + 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") + } + userID, ok := r.Primary.Attributes["user_id"] + if !ok { + return "", fmt.Errorf("couldn't find attribute user_id") + } + return fmt.Sprintf("%s,%s,%s,%s", projectID, region, instanceID, userID), nil + } + } +*/ +func testAccCheckSQLServerFlexDestroy(s *terraform.State) error { + testutils.Setup() + + pID, ok := os.LookupEnv("TF_ACC_PROJECT_ID") + if !ok { + log.Fatalln("unable to read TF_ACC_PROJECT_ID") + } + + ctx := context.Background() + var client *v3beta1api.APIClient + var err error + + var region, projectID string + region = testutils.Region + if region == "" { + region = "eu01" + } + + projectID = pID + if projectID == "" { + return fmt.Errorf("projectID could not be determined in destroy function") + } + + apiClientConfigOptions := []config.ConfigurationOption{ + config.WithServiceAccountKeyPath(os.Getenv("TF_ACC_SERVICE_ACCOUNT_FILE")), + config.WithRegion(region), + } + if testutils.PostgresFlexCustomEndpoint != "" { + apiClientConfigOptions = append( + apiClientConfigOptions, + config.WithEndpoint(testutils.PostgresFlexCustomEndpoint), + ) + } + client, err = v3beta1api.NewAPIClient(apiClientConfigOptions...) + if err != nil { + log.Fatalln(err) + } + + instancesToDestroy := []string{} + for _, rs := range s.RootModule().Resources { + if rs.Type != "stackitprivatepreview_postgresflexalpha_instance" && + rs.Type != "stackitprivatepreview_postgresflexbeta_instance" { + continue + } + + // instance terraform ID: = "[project_id],[region],[instance_id]" + instanceID := strings.Split(rs.Primary.ID, core.Separator)[2] + instancesToDestroy = append(instancesToDestroy, instanceID) + } + + instancesResp, err := client.DefaultAPI.ListInstancesRequest(ctx, projectID, region). + Size(100). + Execute() + if err != nil { + return fmt.Errorf("getting instancesResp: %w", err) + } + + items := instancesResp.GetInstances() + for i := range items { + if items[i].Id == "" { + continue + } + if utils.Contains(instancesToDestroy, items[i].Id) { + err := client.DefaultAPI.DeleteInstanceRequest(ctx, projectID, region, items[i].Id).Execute() + if err != nil { + return fmt.Errorf("deleting instance %s during CheckDestroy: %w", items[i].Id, err) + } + w := wait.DeleteInstanceWaitHandler( + ctx, + client.DefaultAPI, + testutils.ProjectId, + testutils.Region, + items[i].Id, + ) + _, waitErr := w.SetTimeout(90 * time.Second).WaitWithContext(context.Background()) + if waitErr != nil { + var oapiErr *oapierror.GenericOpenAPIError + isOapiErr := errors.As(waitErr, &oapiErr) + if !isOapiErr { + return fmt.Errorf("could not convert error to oapierror.GenericOpenAPIError") + } + if oapiErr.StatusCode != http.StatusNotFound { + return waitErr + } + } + } + } + return nil +} diff --git a/stackit/internal/services/sqlserverflexbeta/testdata/instance_template.gompl b/stackit/internal/services/sqlserverflexbeta/testdata/instance_template.gompl index e71f3fa0..6d795ed2 100644 --- a/stackit/internal/services/sqlserverflexbeta/testdata/instance_template.gompl +++ b/stackit/internal/services/sqlserverflexbeta/testdata/instance_template.gompl @@ -4,35 +4,37 @@ provider "stackitprivatepreview" { } resource "stackitprivatepreview_sqlserverflexbeta_instance" "{{ .TfName }}" { - project_id = "{{ .ProjectId }}" + project_id = "{{ .ProjectID }}" name = "{{ .Name }}" backup_schedule = "{{ .BackupSchedule }}" retention_days = {{ .RetentionDays }} - flavor_id = "{{ .FlavorId }}" + flavor_id = "{{ .FlavorID }}" storage = { class = "{{ .PerformanceClass }}" size = {{ .Size }} } {{ if .UseEncryption }} encryption = { - kek_key_id = "{{ .KekKeyId }}" - kek_key_ring_id = "{{ .KekKeyRingId }}" + kek_key_id = "{{ .KekKeyID }}" + kek_key_ring_id = "{{ .KekKeyRingID }}" kek_key_version = {{ .KekKeyVersion }} service_account = "{{ .KekServiceAccount }}" } {{ end }} network = { - acl = ["{{ .AclString }}"] + acl = [{{ range $i, $v := .ACLStrings }}{{if $i}},{{end}}"{{$v}}"{{end}}] access_scope = "{{ .AccessScope }}" } +{{ if .Version }} version = "{{ .Version }}" +{{ end }} } {{ if .Users }} {{ $tfName := .TfName }} {{ range $user := .Users }} resource "stackitprivatepreview_sqlserverflexbeta_user" "{{ $user.Name }}" { - project_id = "{{ $user.ProjectId }}" + project_id = "{{ $user.ProjectID }}" instance_id = stackitprivatepreview_sqlserverflexbeta_instance.{{ $tfName }}.instance_id username = "{{ $user.Name }}" roles = [{{ range $i, $v := $user.Roles }}{{if $i}},{{end}}"{{$v}}"{{end}}] @@ -45,7 +47,7 @@ resource "stackitprivatepreview_sqlserverflexbeta_user" "{{ $user.Name }}" { {{ range $db := .Databases }} resource "stackitprivatepreview_sqlserverflexbeta_database" "{{ $db.Name }}" { depends_on = [stackitprivatepreview_sqlserverflexbeta_user.{{ $db.Owner }}] - project_id = "{{ $db.ProjectId }}" + project_id = "{{ $db.ProjectID }}" instance_id = stackitprivatepreview_sqlserverflexbeta_instance.{{ $tfName }}.instance_id name = "{{ $db.Name }}" owner = "{{ $db.Owner }}" diff --git a/stackit/internal/wait/postgresflexalpha/wait.go b/stackit/internal/wait/postgresflexalpha/wait.go index 26f2d729..00295c42 100644 --- a/stackit/internal/wait/postgresflexalpha/wait.go +++ b/stackit/internal/wait/postgresflexalpha/wait.go @@ -2,9 +2,11 @@ package postgresflexalpha import ( "context" + "crypto/rand" "errors" "fmt" "math" + "math/big" "net/http" "time" @@ -29,45 +31,47 @@ const ( // APIClientInstanceInterface Interface needed for tests type APIClientInstanceInterface interface { - GetInstanceRequest(ctx context.Context, projectId, region, instanceId string) v3alpha1api.ApiGetInstanceRequestRequest + GetInstanceRequest(ctx context.Context, projectID, region, instanceID string) v3alpha1api.ApiGetInstanceRequestRequest ListUsersRequest( ctx context.Context, - projectId string, + projectID string, region string, - instanceId string, + instanceID string, ) v3alpha1api.ApiListUsersRequestRequest } // APIClientUserInterface Interface needed for tests type APIClientUserInterface interface { - GetUserRequest(ctx context.Context, projectId, region, instanceId string, userId int32) v3alpha1api.ApiGetUserRequestRequest + GetUserRequest(ctx context.Context, projectID, region, instanceID string, userID int32) v3alpha1api.ApiGetUserRequestRequest } // APIClientDatabaseInterface Interface needed for tests type APIClientDatabaseInterface interface { - GetDatabaseRequest(ctx context.Context, projectId string, region string, instanceId string, databaseId int32) v3alpha1api.ApiGetDatabaseRequestRequest + GetDatabaseRequest(ctx context.Context, projectID string, region string, instanceID string, databaseID int32) v3alpha1api.ApiGetDatabaseRequestRequest } // CreateInstanceWaitHandler will wait for instance creation func CreateInstanceWaitHandler( - ctx context.Context, a APIClientInstanceInterface, projectId, region, - instanceId string, + ctx context.Context, a APIClientInstanceInterface, projectID, region, + instanceID string, ) *wait.AsyncActionHandler[v3alpha1api.GetInstanceResponse] { instanceCreated := false var instanceGetResponse *v3alpha1api.GetInstanceResponse maxWait := time.Minute * 45 startTime := time.Now() extendedTimeout := 0 + maxFailedCount := 3 + failedCount := 0 handler := wait.New( func() (waitFinished bool, response *v3alpha1api.GetInstanceResponse, err error) { if !instanceCreated { - s, err := a.GetInstanceRequest(ctx, projectId, region, instanceId).Execute() - if err != nil { - return false, nil, err + s, getErr := a.GetInstanceRequest(ctx, projectID, region, instanceID).Execute() + if getErr != nil { + return false, nil, getErr } - if s == nil || s.Id != instanceId { + if s == nil || s.Id != instanceID { return false, nil, nil } tflog.Debug( @@ -77,7 +81,7 @@ func CreateInstanceWaitHandler( ) switch s.Status { default: - return true, s, fmt.Errorf("instance with id %s has unexpected status %s", instanceId, s.Status) + return true, s, fmt.Errorf("instance with id %s has unexpected status %s", instanceID, s.Status) case InstanceStateEmpty: return false, nil, nil case InstanceStatePending: @@ -94,30 +98,15 @@ func CreateInstanceWaitHandler( "Wait handler still got status %s after %v for instance: %s", InstanceStateProgressing, maxWait, - instanceId, + instanceID, ), ) if extendedTimeout < 3 { maxWait += time.Minute * 5 extendedTimeout++ - if *s.Network.AccessScope == "SNA" { - ready := true - if s.Network.InstanceAddress == nil { - tflog.Warn(ctx, "Waiting for instance_address") - ready = false - } - if s.Network.RouterAddress == nil { - tflog.Warn(ctx, "Waiting for router_address") - ready = false - } - if !ready { - return false, nil, nil - } - } + return false, nil, nil } - - instanceCreated = true - instanceGetResponse = s + return false, nil, fmt.Errorf("instance after max timeout still in state %s", InstanceStateProgressing) case InstanceStateSuccess: if s.Network.AccessScope != nil && *s.Network.AccessScope == "SNA" { if s.Network.InstanceAddress == nil { @@ -132,8 +121,27 @@ func CreateInstanceWaitHandler( instanceCreated = true instanceGetResponse = s case InstanceStateFailed: - tflog.Warn(ctx, fmt.Sprintf("Wait handler got status FAILURE for instance: %s", instanceId)) - return false, nil, nil + if failedCount < maxFailedCount { + failedCount++ + tflog.Warn( + ctx, "got failed status from API retry", map[string]interface{}{ + "failedCount": failedCount, + }, + ) + var waitCounter int64 = 1 + maxWaitInt := big.NewInt(7) + n, randErr := rand.Int(rand.Reader, maxWaitInt) + if randErr == nil { + waitCounter = n.Int64() + 1 + } + time.Sleep(time.Duration(waitCounter*30) * time.Second) //nolint:gosec // not that important and temporary + return false, nil, nil + } + return true, s, fmt.Errorf( + "update got status FAILURE for instance with id %s after %d retries", + instanceID, + failedCount, + ) // API responds with FAILURE for some seconds and then the instance goes to READY // return true, s, fmt.Errorf("create failed for instance with id %s", instanceId) } @@ -142,7 +150,7 @@ func CreateInstanceWaitHandler( tflog.Info(ctx, "Waiting for instance (calling list users") // // User operations aren't available right after an instance is deemed successful // // To check if they are, perform a users request - _, err = a.ListUsersRequest(ctx, projectId, region, instanceId).Execute() + _, err = a.ListUsersRequest(ctx, projectID, region, instanceID).Execute() if err == nil { return true, instanceGetResponse, nil } @@ -150,7 +158,7 @@ func CreateInstanceWaitHandler( if !ok { return false, nil, err } - // TODO: refactor and cooperate with api guys to mitigate + // TODO: refactor and cooperate with api guys to mitigate // nolint: // reason upfront if oapiErr.StatusCode < 500 { return true, instanceGetResponse, fmt.Errorf( "users request after instance creation returned %d status code", @@ -160,8 +168,6 @@ func CreateInstanceWaitHandler( return false, nil, nil }, ) - // Sleep before wait is set because sometimes API returns 404 right after creation request - handler.SetTimeout(90 * time.Minute).SetSleepBeforeWait(30 * time.Second) return handler } @@ -170,6 +176,8 @@ func PartialUpdateInstanceWaitHandler( ctx context.Context, a APIClientInstanceInterface, projectID, region, instanceID string, ) *wait.AsyncActionHandler[v3alpha1api.GetInstanceResponse] { + maxFailedCount := 3 + failedCount := 0 handler := wait.New( func() (waitFinished bool, response *v3alpha1api.GetInstanceResponse, err error) { s, err := a.GetInstanceRequest(ctx, projectID, region, instanceID).Execute() @@ -195,11 +203,30 @@ func PartialUpdateInstanceWaitHandler( case InstanceStateUnknown: return false, nil, nil case InstanceStateFailed: - return true, s, fmt.Errorf("update got status FAILURE for instance with id %s", instanceID) + if failedCount < maxFailedCount { + failedCount++ + tflog.Warn( + ctx, "got failed status from API retry", map[string]interface{}{ + "failedCount": failedCount, + }, + ) + var waitCounter int64 = 1 + maxWait := big.NewInt(7) + n, err := rand.Int(rand.Reader, maxWait) + if err == nil { + waitCounter = n.Int64() + 1 + } + time.Sleep(time.Duration(waitCounter*30) * time.Second) //nolint:gosec // not that important and temporary + return false, nil, nil + } + return true, s, fmt.Errorf( + "update got status FAILURE for instance with id %s after %d retries", + instanceID, + failedCount, + ) } }, ) - handler.SetTimeout(45 * time.Minute).SetSleepBeforeWait(30 * time.Second) return handler } @@ -295,6 +322,8 @@ func DeleteInstanceWaitHandler( instanceID string, timeout, sleepBeforeWait time.Duration, ) error { + maxFailedCount := 3 + failedCount := 0 handler := wait.New( func() (waitFinished bool, response *v3alpha1api.GetInstanceResponse, err error) { s, err := a.GetInstanceRequest(ctx, projectID, region, instanceID).Execute() @@ -314,6 +343,22 @@ func DeleteInstanceWaitHandler( case InstanceStateEmpty, InstanceStatePending, InstanceStateUnknown, InstanceStateProgressing, InstanceStateSuccess: return false, nil, nil case InstanceStateFailed: + if failedCount < maxFailedCount { + failedCount++ + tflog.Warn( + ctx, "got failed status from API retry", map[string]interface{}{ + "failedCount": failedCount, + }, + ) + var waitCounter int64 = 1 + maxWait := big.NewInt(7) + n, err := rand.Int(rand.Reader, maxWait) + if err == nil { + waitCounter = n.Int64() + 1 + } + time.Sleep(time.Duration(waitCounter*30) * time.Second) //nolint:gosec // not that important and temporary + return false, nil, nil + } return true, nil, fmt.Errorf("wait handler got status FAILURE for instance: %s", instanceID) default: return true, s, fmt.Errorf("instance with id %s has unexpected status %s", instanceID, s.Status) diff --git a/stackit/internal/wait/postgresflexalpha/wait_test.go b/stackit/internal/wait/postgresflexalpha/wait_test.go index faef6cbf..c0a143d6 100644 --- a/stackit/internal/wait/postgresflexalpha/wait_test.go +++ b/stackit/internal/wait/postgresflexalpha/wait_test.go @@ -4,6 +4,7 @@ package postgresflexalpha import ( "context" + "os" "testing" "time" @@ -22,6 +23,8 @@ func TestCreateInstanceWaitHandler(t *testing.T) { usersGetErrorStatus int wantErr bool wantRes *v3alpha1api.GetInstanceResponse + timeout time.Duration + onlyOnLong bool }{ { desc: "create_succeeded", @@ -46,6 +49,7 @@ func TestCreateInstanceWaitHandler(t *testing.T) { }, }, { + onlyOnLong: true, desc: "create_failed", instanceGetFails: false, instanceState: InstanceStateFailed, @@ -56,7 +60,18 @@ func TestCreateInstanceWaitHandler(t *testing.T) { RouterAddress: utils.Ptr("10.0.0.1"), }, wantErr: true, - wantRes: nil, + wantRes: &v3alpha1api.GetInstanceResponse{ + Id: "foo-bar", + Status: InstanceStateFailed, + Network: v3alpha1api.InstanceNetwork{ + AccessScope: nil, + Acl: nil, + InstanceAddress: utils.Ptr("10.0.0.1"), + RouterAddress: utils.Ptr("10.0.0.1"), + }, + }, + // waiter uses random timeouts up to 8 times 30 secs + timeout: 300 * time.Second, }, { desc: "create_failed_2", @@ -142,6 +157,13 @@ func TestCreateInstanceWaitHandler(t *testing.T) { }, } for _, tt := range tests { + if tt.onlyOnLong { + _, ok := os.LookupEnv("TF_RUN_LONG_TESTS") + if !ok { + t.Logf("skipping test '%s' because TF_RUN_LONG_TESTS env var is missing", tt.desc) + continue + } + } t.Run( tt.desc, func(t *testing.T) { instanceID := "foo-bar" @@ -181,9 +203,13 @@ func TestCreateInstanceWaitHandler(t *testing.T) { ListUsersRequestExecuteMock: &listUsersMock, } - handler := CreateInstanceWaitHandler(context.Background(), apiClientMock, "", "", instanceID) + handler := CreateInstanceWaitHandler(context.Background(), apiClientMock, "", "", instanceID). + SetTimeout(10 * time.Millisecond) + if tt.timeout != 0 { + handler.SetTimeout(tt.timeout) + } - gotRes, err := handler.SetTimeout(10 * time.Millisecond).SetSleepBeforeWait(1 * time.Millisecond).WaitWithContext(context.Background()) + gotRes, err := handler.SetSleepBeforeWait(1 * time.Millisecond).WaitWithContext(context.Background()) if (err != nil) != tt.wantErr { t.Fatalf("handler error = %v, wantErr %v", err, tt.wantErr) } @@ -204,6 +230,8 @@ func TestUpdateInstanceWaitHandler(t *testing.T) { instanceNetwork v3alpha1api.InstanceNetwork wantErr bool wantRes *v3alpha1api.GetInstanceResponse + timeout time.Duration + onlyOnLong bool }{ { desc: "update_succeeded", @@ -228,6 +256,7 @@ func TestUpdateInstanceWaitHandler(t *testing.T) { }, }, { + onlyOnLong: true, desc: "update_failed", instanceGetFails: false, instanceState: InstanceStateFailed, @@ -248,6 +277,7 @@ func TestUpdateInstanceWaitHandler(t *testing.T) { RouterAddress: utils.Ptr("10.0.0.1"), }, }, + timeout: 300 * time.Second, }, { desc: "update_failed_2", @@ -283,6 +313,14 @@ func TestUpdateInstanceWaitHandler(t *testing.T) { }, } for _, tt := range tests { + if tt.onlyOnLong { + _, ok := os.LookupEnv("TF_RUN_LONG_TESTS") + if !ok { + t.Logf("skipping test '%s' because TF_RUN_LONG_TESTS env var is missing", tt.desc) + continue + } + } + t.Run( tt.desc, func(t *testing.T) { instanceID := "foo-bar" @@ -316,9 +354,13 @@ func TestUpdateInstanceWaitHandler(t *testing.T) { ListUsersRequestExecuteMock: &listUsersMock, } - handler := PartialUpdateInstanceWaitHandler(context.Background(), apiClientMock, "", "", instanceID) + handler := PartialUpdateInstanceWaitHandler(context.Background(), apiClientMock, "", "", instanceID). + SetTimeout(10 * time.Millisecond) + if tt.timeout > 0 { + handler.SetTimeout(tt.timeout) + } - gotRes, err := handler.SetTimeout(10 * time.Millisecond).WaitWithContext(context.Background()) + gotRes, err := handler.WaitWithContext(context.Background()) if (err != nil) != tt.wantErr { t.Fatalf("handler error = %v, wantErr %v", err, tt.wantErr) } diff --git a/stackit/internal/wait/sqlserverflexbeta/wait.go b/stackit/internal/wait/sqlserverflexbeta/wait.go index a13def0f..18168968 100644 --- a/stackit/internal/wait/sqlserverflexbeta/wait.go +++ b/stackit/internal/wait/sqlserverflexbeta/wait.go @@ -30,35 +30,35 @@ const ( type APIClientInterface interface { GetInstanceRequest( ctx context.Context, - projectId, region, instanceId string, + projectID, region, instanceID string, ) sqlserverflex.ApiGetInstanceRequestRequest GetDatabaseRequest( ctx context.Context, - projectId string, + projectID string, region string, - instanceId string, + instanceID string, databaseName string, ) sqlserverflex.ApiGetDatabaseRequestRequest GetUserRequest( ctx context.Context, - projectId string, + projectID string, region string, - instanceId string, - userId int64, + instanceID string, + userID int64, ) sqlserverflex.ApiGetUserRequestRequest ListRolesRequest( ctx context.Context, - projectId string, + projectID string, region string, - instanceId string, + instanceID string, ) sqlserverflex.ApiListRolesRequestRequest ListUsersRequest( ctx context.Context, - projectId string, + projectID string, region string, - instanceId string, + instanceID string, ) sqlserverflex.ApiListUsersRequestRequest } @@ -66,10 +66,10 @@ type APIClientInterface interface { type APIClientUserInterface interface { DeleteUserRequestExecute( ctx context.Context, - projectId string, + projectID string, region string, - instanceId string, - userId int64, + instanceID string, + userID int64, ) error } @@ -77,11 +77,11 @@ type APIClientUserInterface interface { func CreateInstanceWaitHandler( ctx context.Context, a APIClientInterface, - projectId, instanceId, region string, + projectID, instanceID, region string, ) *wait.AsyncActionHandler[sqlserverflex.GetInstanceResponse] { handler := wait.New( func() (waitFinished bool, response *sqlserverflex.GetInstanceResponse, err error) { - s, err := a.GetInstanceRequest(ctx, projectId, region, instanceId).Execute() + s, err := a.GetInstanceRequest(ctx, projectID, region, instanceID).Execute() if err != nil { var oapiErr *oapierror.GenericOpenAPIError ok := errors.As(err, &oapiErr) @@ -95,7 +95,7 @@ func CreateInstanceWaitHandler( return false, nil, fmt.Errorf("api error: %w", err) } } - if s == nil || s.Id != instanceId { + if s == nil || s.Id != instanceID { return false, nil, nil } switch strings.ToLower(string(s.Status)) { @@ -113,7 +113,7 @@ func CreateInstanceWaitHandler( tflog.Info(ctx, "trying to get roles") time.Sleep(10 * time.Second) - _, rolesErr := a.ListRolesRequest(ctx, projectId, region, instanceId).Execute() + _, rolesErr := a.ListRolesRequest(ctx, projectID, region, instanceID).Execute() if rolesErr != nil { var oapiErr *oapierror.GenericOpenAPIError ok := errors.As(rolesErr, &oapiErr) @@ -137,7 +137,7 @@ func CreateInstanceWaitHandler( tflog.Info(ctx, "trying to get users") time.Sleep(10 * time.Second) - _, usersErr := a.ListUsersRequest(ctx, projectId, region, instanceId).Execute() + _, usersErr := a.ListUsersRequest(ctx, projectID, region, instanceID).Execute() if usersErr != nil { var oapiErr *oapierror.GenericOpenAPIError ok := errors.As(usersErr, &oapiErr) @@ -162,13 +162,13 @@ func CreateInstanceWaitHandler( case strings.ToLower(InstanceStateUnknown): return true, nil, fmt.Errorf( "create failed for instance %s with status %s", - instanceId, + instanceID, InstanceStateUnknown, ) case strings.ToLower(InstanceStateFailed): return true, nil, fmt.Errorf( "create failed for instance %s with status %s", - instanceId, + instanceID, InstanceStateFailed, ) case strings.ToLower(InstanceStatePending), strings.ToLower(InstanceStateProcessing): @@ -182,7 +182,7 @@ func CreateInstanceWaitHandler( default: tflog.Info( ctx, "Wait (create) received unknown status", map[string]interface{}{ - "instanceId": instanceId, + "instanceId": instanceID, "status": s.Status, }, ) @@ -197,22 +197,22 @@ func CreateInstanceWaitHandler( func UpdateInstanceWaitHandler( ctx context.Context, a APIClientInterface, - projectId, instanceId, region string, + projectID, instanceID, region string, ) *wait.AsyncActionHandler[sqlserverflex.GetInstanceResponse] { handler := wait.New( func() (waitFinished bool, response *sqlserverflex.GetInstanceResponse, err error) { - s, err := a.GetInstanceRequest(ctx, projectId, region, instanceId).Execute() + s, err := a.GetInstanceRequest(ctx, projectID, region, instanceID).Execute() if err != nil { return false, nil, err } - if s == nil || s.Id != instanceId { + if s == nil || s.Id != instanceID { return false, nil, nil } switch strings.ToLower(string(s.Status)) { case strings.ToLower(InstanceStateSuccess): return true, s, nil case strings.ToLower(InstanceStateUnknown), strings.ToLower(InstanceStateFailed): - return true, s, fmt.Errorf("update failed for instance with id %s", instanceId) + return true, s, fmt.Errorf("update failed for instance with id %s", instanceID) case strings.ToLower(InstanceStatePending), strings.ToLower(InstanceStateProcessing): tflog.Info( ctx, "request is being handled", map[string]interface{}{ @@ -223,7 +223,7 @@ func UpdateInstanceWaitHandler( default: tflog.Info( ctx, "Wait (update) received unknown status", map[string]interface{}{ - "instanceId": instanceId, + "instanceId": instanceID, "status": s.Status, }, ) @@ -238,11 +238,11 @@ func UpdateInstanceWaitHandler( func DeleteInstanceWaitHandler( ctx context.Context, a APIClientInterface, - projectId, instanceId, region string, + projectID, instanceID, region string, ) *wait.AsyncActionHandler[sqlserverflex.GetInstanceResponse] { handler := wait.New( func() (waitFinished bool, response *sqlserverflex.GetInstanceResponse, err error) { - s, err := a.GetInstanceRequest(ctx, projectId, region, instanceId).Execute() + s, err := a.GetInstanceRequest(ctx, projectID, region, instanceID).Execute() if err == nil { return false, s, nil } @@ -265,11 +265,11 @@ func DeleteInstanceWaitHandler( func CreateDatabaseWaitHandler( ctx context.Context, a APIClientInterface, - projectId, instanceId, region, databaseName string, + projectID, instanceID, region, databaseName string, ) *wait.AsyncActionHandler[sqlserverflex.GetDatabaseResponse] { handler := wait.New( func() (waitFinished bool, response *sqlserverflex.GetDatabaseResponse, err error) { - s, err := a.GetDatabaseRequest(ctx, projectId, region, instanceId, databaseName).Execute() + s, err := a.GetDatabaseRequest(ctx, projectID, region, instanceID, databaseName).Execute() if err != nil { var oapiErr *oapierror.GenericOpenAPIError ok := errors.As(err, &oapiErr) @@ -297,12 +297,12 @@ func CreateDatabaseWaitHandler( func CreateUserWaitHandler( ctx context.Context, a APIClientInterface, - projectId, instanceId, region string, - userId int64, + projectID, instanceID, region string, + userID int64, ) *wait.AsyncActionHandler[sqlserverflex.GetUserResponse] { handler := wait.New( func() (waitFinished bool, response *sqlserverflex.GetUserResponse, err error) { - s, err := a.GetUserRequest(ctx, projectId, region, instanceId, userId).Execute() + s, err := a.GetUserRequest(ctx, projectID, region, instanceID, userID).Execute() if err != nil { var oapiErr *oapierror.GenericOpenAPIError ok := errors.As(err, &oapiErr) @@ -324,7 +324,7 @@ func CreateUserWaitHandler( func WaitForUserWaitHandler( ctx context.Context, a APIClientInterface, - projectId, instanceId, region, userName string, + projectID, instanceID, region, userName string, ) *wait.AsyncActionHandler[sqlserverflex.ListUserResponse] { startTime := time.Now() timeOut := 2 * time.Minute @@ -334,7 +334,7 @@ func WaitForUserWaitHandler( if time.Since(startTime) > timeOut { return false, nil, errors.New("ran into timeout") } - s, err := a.ListUsersRequest(ctx, projectId, region, instanceId).Size(100).Execute() + s, err := a.ListUsersRequest(ctx, projectID, region, instanceID).Size(100).Execute() if err != nil { var oapiErr *oapierror.GenericOpenAPIError ok := errors.As(err, &oapiErr) @@ -376,12 +376,12 @@ func WaitForUserWaitHandler( func DeleteUserWaitHandler( ctx context.Context, a APIClientInterface, - projectId, region, instanceId string, - userId int64, + projectID, region, instanceID string, + userID int64, ) *wait.AsyncActionHandler[struct{}] { handler := wait.New( func() (waitFinished bool, response *struct{}, err error) { - _, err = a.GetUserRequest(ctx, projectId, region, instanceId, userId).Execute() + _, err = a.GetUserRequest(ctx, projectID, region, instanceID, userID).Execute() if err == nil { return false, nil, nil } diff --git a/tools/go.sum b/tools/go.sum index d14741ce..ce4c45eb 100644 --- a/tools/go.sum +++ b/tools/go.sum @@ -1,6 +1,4 @@ -4d63.com/gocheckcompilerdirectives v1.3.0 h1:Ew5y5CtcAAQeTVKUVFrE7EwHMrTO6BggtEj8BZSjZ3A= 4d63.com/gocheckcompilerdirectives v1.3.0/go.mod h1:ofsJ4zx2QAuIP/NO/NAh1ig6R1Fb18/GI7RVMwz7kAY= -4d63.com/gochecknoglobals v0.2.2 h1:H1vdnwnMaZdQW/N+NrkT1SZMTBmcwHe9Vq8lJcYYTtU= 4d63.com/gochecknoglobals v0.2.2/go.mod h1:lLxwTQjL5eIesRbvnzIP3jZtG140FnTdz+AlMa+ogt0= cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= @@ -34,198 +32,105 @@ cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0Zeo cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= -codeberg.org/chavacava/garif v0.2.0 h1:F0tVjhYbuOCnvNcU3YSpO6b3Waw6Bimy4K0mM8y6MfY= codeberg.org/chavacava/garif v0.2.0/go.mod h1:P2BPbVbT4QcvLZrORc2T29szK3xEOlnl0GiPTJmEqBQ= -codeberg.org/polyfloyd/go-errorlint v1.9.0 h1:VkdEEmA1VBpH6ecQoMR4LdphVI3fA4RrCh2an7YmodI= codeberg.org/polyfloyd/go-errorlint v1.9.0/go.mod h1:GPRRu2LzVijNn4YkrZYJfatQIdS+TrcK8rL5Xs24qw8= -dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk= -dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= -dev.gaijin.team/go/exhaustruct/v4 v4.0.0 h1:873r7aNneqoBB3IaFIzhvt2RFYTuHgmMjoKfwODoI1Y= dev.gaijin.team/go/exhaustruct/v4 v4.0.0/go.mod h1:aZ/k2o4Y05aMJtiux15x8iXaumE88YdiB0Ai4fXOzPI= -dev.gaijin.team/go/golib v0.6.0 h1:v6nnznFTs4bppib/NyU1PQxobwDHwCXXl15P7DV5Zgo= dev.gaijin.team/go/golib v0.6.0/go.mod h1:uY1mShx8Z/aNHWDyAkZTkX+uCi5PdX7KsG1eDQa2AVE= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= -github.com/4meepo/tagalign v1.4.3 h1:Bnu7jGWwbfpAie2vyl63Zup5KuRv21olsPIha53BJr8= github.com/4meepo/tagalign v1.4.3/go.mod h1:00WwRjiuSbrRJnSVeGWPLp2epS5Q/l4UEy0apLLS37c= -github.com/Abirdcfly/dupword v0.1.7 h1:2j8sInznrje4I0CMisSL6ipEBkeJUJAmK1/lfoNGWrQ= github.com/Abirdcfly/dupword v0.1.7/go.mod h1:K0DkBeOebJ4VyOICFdppB23Q0YMOgVafM0zYW0n9lF4= -github.com/AdminBenni/iota-mixing v1.0.0 h1:Os6lpjG2dp/AE5fYBPAA1zfa2qMdCAWwPMCgpwKq7wo= github.com/AdminBenni/iota-mixing v1.0.0/go.mod h1:i4+tpAaB+qMVIV9OK3m4/DAynOd5bQFaOu+2AhtBCNY= -github.com/AlwxSin/noinlineerr v1.0.5 h1:RUjt63wk1AYWTXtVXbSqemlbVTb23JOSRiNsshj7TbY= github.com/AlwxSin/noinlineerr v1.0.5/go.mod h1:+QgkkoYrMH7RHvcdxdlI7vYYEdgeoFOVjU9sUhw/rQc= -github.com/Antonboom/errname v1.1.1 h1:bllB7mlIbTVzO9jmSWVWLjxTEbGBVQ1Ff/ClQgtPw9Q= github.com/Antonboom/errname v1.1.1/go.mod h1:gjhe24xoxXp0ScLtHzjiXp0Exi1RFLKJb0bVBtWKCWQ= -github.com/Antonboom/nilnil v1.1.1 h1:9Mdr6BYd8WHCDngQnNVV0b554xyisFioEKi30sksufQ= github.com/Antonboom/nilnil v1.1.1/go.mod h1:yCyAmSw3doopbOWhJlVci+HuyNRuHJKIv6V2oYQa8II= -github.com/Antonboom/testifylint v1.6.4 h1:gs9fUEy+egzxkEbq9P4cpcMB6/G0DYdMeiFS87UiqmQ= github.com/Antonboom/testifylint v1.6.4/go.mod h1:YO33FROXX2OoUfwjz8g+gUxQXio5i9qpVy7nXGbxDD4= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/BurntSushi/toml v1.6.0 h1:dRaEfpa2VI55EwlIW72hMRHdWouJeRF7TPYhI+AUQjk= github.com/BurntSushi/toml v1.6.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= -github.com/Djarvur/go-err113 v0.1.1 h1:eHfopDqXRwAi+YmCUas75ZE0+hoBHJ2GQNLYRSxao4g= github.com/Djarvur/go-err113 v0.1.1/go.mod h1:IaWJdYFLg76t2ihfflPZnM1LIQszWOsFDh2hhhAVF6k= -github.com/Kunde21/markdownfmt/v3 v3.1.0 h1:KiZu9LKs+wFFBQKhrZJrFZwtLnCCWJahL+S+E/3VnM0= github.com/Kunde21/markdownfmt/v3 v3.1.0/go.mod h1:tPXN1RTyOzJwhfHoon9wUr4HGYmWgVxSQN6VBJDkrVc= -github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI= github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= github.com/Masterminds/semver/v3 v3.2.0/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ= -github.com/Masterminds/semver/v3 v3.4.0 h1:Zog+i5UMtVoCU8oKka5P7i9q9HgrJeGzI9SA1Xbatp0= github.com/Masterminds/semver/v3 v3.4.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM= -github.com/Masterminds/sprig/v3 v3.2.3 h1:eL2fZNezLomi0uOLqjQoN6BfsDD+fyLtgbJMAj9n6YA= github.com/Masterminds/sprig/v3 v3.2.3/go.mod h1:rXcFaZ2zZbLRJv/xSysmlgIM1u11eBaRMhvYXJNkGuM= -github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= -github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= -github.com/MirrexOne/unqueryvet v1.5.3 h1:LpT3rsH+IY3cQddWF9bg4C7jsbASdGnrOSofY8IPEiw= github.com/MirrexOne/unqueryvet v1.5.3/go.mod h1:fs9Zq6eh1LRIhsDIsxf9PONVUjYdFHdtkHIgZdJnyPU= -github.com/OpenPeeDeeP/depguard/v2 v2.2.1 h1:vckeWVESWp6Qog7UZSARNqfu/cZqvki8zsuj3piCMx4= github.com/OpenPeeDeeP/depguard/v2 v2.2.1/go.mod h1:q4DKzC4UcVaAvcfd41CZh0PWpGgzrVxUYBlgKNGquUo= -github.com/ProtonMail/go-crypto v1.1.6 h1:ZcV+Ropw6Qn0AX9brlQLAUXfqLBc7Bl+f/DmNxpLfdw= github.com/ProtonMail/go-crypto v1.1.6/go.mod h1:rA3QumHc/FZ8pAHreoekgiAbzpNsfQAosU5td4SnOrE= -github.com/alecthomas/assert/v2 v2.11.0 h1:2Q9r3ki8+JYXvGsDyBXwH3LcJ+WK5D0gc5E8vS6K3D0= -github.com/alecthomas/assert/v2 v2.11.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k= -github.com/alecthomas/chroma/v2 v2.23.1 h1:nv2AVZdTyClGbVQkIzlDm/rnhk1E9bU9nXwmZ/Vk/iY= github.com/alecthomas/chroma/v2 v2.23.1/go.mod h1:NqVhfBR0lte5Ouh3DcthuUCTUpDC9cxBOfyMbMQPs3o= -github.com/alecthomas/go-check-sumtype v0.3.1 h1:u9aUvbGINJxLVXiFvHUlPEaD7VDULsrxJb4Aq31NLkU= github.com/alecthomas/go-check-sumtype v0.3.1/go.mod h1:A8TSiN3UPRw3laIgWEUOHHLPa6/r9MtoigdlP5h3K/E= -github.com/alecthomas/repr v0.5.2 h1:SU73FTI9D1P5UNtvseffFSGmdNci/O6RsqzeXJtP0Qs= -github.com/alecthomas/repr v0.5.2/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= -github.com/alexkohler/nakedret/v2 v2.0.6 h1:ME3Qef1/KIKr3kWX3nti3hhgNxw6aqN5pZmQiFSsuzQ= github.com/alexkohler/nakedret/v2 v2.0.6/go.mod h1:l3RKju/IzOMQHmsEvXwkqMDzHHvurNQfAgE1eVmT40Q= -github.com/alexkohler/prealloc v1.0.2 h1:MPo8cIkGkZytq7WNH9UHv3DIX1mPz1RatPXnZb0zHWQ= github.com/alexkohler/prealloc v1.0.2/go.mod h1:fT39Jge3bQrfA7nPMDngUfvUbQGQeJyGQnR+913SCig= -github.com/alfatraining/structtag v1.0.0 h1:2qmcUqNcCoyVJ0up879K614L9PazjBSFruTB0GOFjCc= github.com/alfatraining/structtag v1.0.0/go.mod h1:p3Xi5SwzTi+Ryj64DqjLWz7XurHxbGsq6y3ubePJPus= -github.com/alingse/asasalint v0.0.11 h1:SFwnQXJ49Kx/1GghOFz1XGqHYKp21Kq1nHad/0WQRnw= github.com/alingse/asasalint v0.0.11/go.mod h1:nCaoMhw7a9kSJObvQyVzNTPBDbNpdocqrSP7t/cW5+I= -github.com/alingse/nilnesserr v0.2.0 h1:raLem5KG7EFVb4UIDAXgrv3N2JIaffeKNtcEXkEWd/w= github.com/alingse/nilnesserr v0.2.0/go.mod h1:1xJPrXonEtX7wyTq8Dytns5P2hNzoWymVUIaKm4HNFg= -github.com/apparentlymart/go-textseg/v15 v15.0.0 h1:uYvfpb3DyLSCGWnctWKGj857c6ew1u1fNQOlOtuGxQY= github.com/apparentlymart/go-textseg/v15 v15.0.0/go.mod h1:K8XmNZdhEBkdlyDdvbmmsvpAG721bKi0joRfFdHIWJ4= -github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= -github.com/ashanbrown/forbidigo/v2 v2.3.0 h1:OZZDOchCgsX5gvToVtEBoV2UWbFfI6RKQTir2UZzSxo= github.com/ashanbrown/forbidigo/v2 v2.3.0/go.mod h1:5p6VmsG5/1xx3E785W9fouMxIOkvY2rRV9nMdWadd6c= -github.com/ashanbrown/makezero/v2 v2.1.0 h1:snuKYMbqosNokUKm+R6/+vOPs8yVAi46La7Ck6QYSaE= github.com/ashanbrown/makezero/v2 v2.1.0/go.mod h1:aEGT/9q3S8DHeE57C88z2a6xydvgx8J5hgXIGWgo0MY= -github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k= github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8= -github.com/bahlo/generic-list-go v0.2.0 h1:5sz/EEAK+ls5wF+NeqDpk5+iNdMDXrh3z3nPnH1Wvgk= github.com/bahlo/generic-list-go v0.2.0/go.mod h1:2KvAjgMlE5NNynlg/5iLrrCCZ2+5xWbdbCW3pNTGyYg= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= -github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= -github.com/bgentry/speakeasy v0.1.0 h1:ByYyxL9InA1OWqxJqqp2A5pYHUrCiAL6K3J+LKSsQkY= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= -github.com/bkielbasa/cyclop v1.2.3 h1:faIVMIGDIANuGPWH031CZJTi2ymOQBULs9H21HSMa5w= github.com/bkielbasa/cyclop v1.2.3/go.mod h1:kHTwA9Q0uZqOADdupvcFJQtp/ksSnytRMe8ztxG8Fuo= -github.com/blizzy78/varnamelen v0.8.0 h1:oqSblyuQvFsW1hbBHh1zfwrKe3kcSj0rnXkKzsQ089M= github.com/blizzy78/varnamelen v0.8.0/go.mod h1:V9TzQZ4fLJ1DSrjVDfl89H7aMnTvKkApdHeyESmyR7k= -github.com/bmatcuk/doublestar/v4 v4.9.1 h1:X8jg9rRZmJd4yRy7ZeNDRnM+T3ZfHv15JiBJ/avrEXE= github.com/bmatcuk/doublestar/v4 v4.9.1/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc= -github.com/bombsimon/wsl/v4 v4.7.0 h1:1Ilm9JBPRczjyUs6hvOPKvd7VL1Q++PL8M0SXBDf+jQ= github.com/bombsimon/wsl/v4 v4.7.0/go.mod h1:uV/+6BkffuzSAVYD+yGyld1AChO7/EuLrCF/8xTiapg= -github.com/bombsimon/wsl/v5 v5.6.0 h1:4z+/sBqC5vUmSp1O0mS+czxwH9+LKXtCWtHH9rZGQL8= github.com/bombsimon/wsl/v5 v5.6.0/go.mod h1:Uqt2EfrMj2NV8UGoN1f1Y3m0NpUVCsUdrNCdet+8LvU= -github.com/breml/bidichk v0.3.3 h1:WSM67ztRusf1sMoqH6/c4OBCUlRVTKq+CbSeo0R17sE= github.com/breml/bidichk v0.3.3/go.mod h1:ISbsut8OnjB367j5NseXEGGgO/th206dVa427kR8YTE= -github.com/breml/errchkjson v0.4.1 h1:keFSS8D7A2T0haP9kzZTi7o26r7kE3vymjZNeNDRDwg= github.com/breml/errchkjson v0.4.1/go.mod h1:a23OvR6Qvcl7DG/Z4o0el6BRAjKnaReoPQFciAl9U3s= -github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMUs= github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0= -github.com/butuzov/ireturn v0.4.0 h1:+s76bF/PfeKEdbG8b54aCocxXmi0wvYdOVsWxVO7n8E= github.com/butuzov/ireturn v0.4.0/go.mod h1:ghI0FrCmap8pDWZwfPisFD1vEc56VKH4NpQUxDHta70= -github.com/butuzov/mirror v1.3.0 h1:HdWCXzmwlQHdVhwvsfBb2Au0r3HyINry3bDWLYXiKoc= github.com/butuzov/mirror v1.3.0/go.mod h1:AEij0Z8YMALaq4yQj9CPPVYOyJQyiexpQEQgihajRfI= -github.com/catenacyber/perfsprint v0.10.1 h1:u7Riei30bk46XsG8nknMhKLXG9BcXz3+3tl/WpKm0PQ= github.com/catenacyber/perfsprint v0.10.1/go.mod h1:DJTGsi/Zufpuus6XPGJyKOTMELe347o6akPvWG9Zcsc= -github.com/ccojocar/zxcvbn-go v1.0.4 h1:FWnCIRMXPj43ukfX000kvBZvV6raSxakYr1nzyNrUcc= github.com/ccojocar/zxcvbn-go v1.0.4/go.mod h1:3GxGX+rHmueTUMvm5ium7irpyjmm7ikxYFOSJB21Das= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/charithe/durationcheck v0.0.11 h1:g1/EX1eIiKS57NTWsYtHDZ/APfeXKhye1DidBcABctk= github.com/charithe/durationcheck v0.0.11/go.mod h1:x5iZaixRNl8ctbM+3B2RrPG5t856TxRyVQEnbIEM2X4= -github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc h1:4pZI35227imm7yK2bGPcfpFEmuY1gc2YSTShr4iJBfs= github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc/go.mod h1:X4/0JoqgTIPSFcRA/P6INZzIuyqdFY5rm8tb41s9okk= -github.com/charmbracelet/lipgloss v1.1.0 h1:vYXsiLHVkK7fp74RkV7b2kq9+zDLoEU4MZoFqR/noCY= github.com/charmbracelet/lipgloss v1.1.0/go.mod h1:/6Q8FR2o+kj8rz4Dq0zQc3vYf7X+B0binUUBwA0aL30= -github.com/charmbracelet/x/ansi v0.10.1 h1:rL3Koar5XvX0pHGfovN03f5cxLbCF2YvLeyz7D2jVDQ= github.com/charmbracelet/x/ansi v0.10.1/go.mod h1:3RQDQ6lDnROptfpWuUVIUG64bD2g2BgntdxH0Ya5TeE= -github.com/charmbracelet/x/cellbuf v0.0.13-0.20250311204145-2c3ea96c31dd h1:vy0GVL4jeHEwG5YOXDmi86oYw2yuYUGqz6a8sLwg0X8= github.com/charmbracelet/x/cellbuf v0.0.13-0.20250311204145-2c3ea96c31dd/go.mod h1:xe0nKWGd3eJgtqZRaN9RjMtK7xUYchjzPr7q6kcvCCs= -github.com/charmbracelet/x/term v0.2.1 h1:AQeHeLZ1OqSXhrAWpYUtZyX1T3zVxfpZuEQMIQaGIAQ= github.com/charmbracelet/x/term v0.2.1/go.mod h1:oQ4enTYFV7QN4m0i9mzHrViD7TQKvNEEkHUMCmsxdUg= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= -github.com/ckaznocha/intrange v0.3.1 h1:j1onQyXvHUsPWujDH6WIjhyH26gkRt/txNlV7LspvJs= github.com/ckaznocha/intrange v0.3.1/go.mod h1:QVepyz1AkUoFQkpEqksSYpNpUo3c5W7nWh/s6SHIJJk= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= -github.com/cloudflare/circl v1.6.1 h1:zqIqSPIndyBh1bjLVVDHMPpVKqp8Su/V+6MeDzzQBQ0= github.com/cloudflare/circl v1.6.1/go.mod h1:uddAzsPgqdMAYatqJ0lsjX1oECcQLIlRpzZh3pJrofs= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= -github.com/curioswitch/go-reassign v0.3.0 h1:dh3kpQHuADL3cobV/sSGETA8DOv457dwl+fbBAhrQPs= github.com/curioswitch/go-reassign v0.3.0/go.mod h1:nApPCCTtqLJN/s8HfItCcKV0jIPwluBOvZP+dsJGA88= -github.com/cyphar/filepath-securejoin v0.4.1 h1:JyxxyPEaktOD+GAnqIqTf9A8tHyAG22rowi7HkoSU1s= -github.com/cyphar/filepath-securejoin v0.4.1/go.mod h1:Sdj7gXlvMcPZsbhwhQ33GguGLDGQL7h7bg04C/+u9jI= -github.com/daixiang0/gci v0.13.7 h1:+0bG5eK9vlI08J+J/NWGbWPTNiXPG4WhNLJOkSxWITQ= github.com/daixiang0/gci v0.13.7/go.mod h1:812WVN6JLFY9S6Tv76twqmNqevN0pa3SX3nih0brVzQ= -github.com/dave/dst v0.27.3 h1:P1HPoMza3cMEquVf9kKy8yXsFirry4zEnWOdYPOoIzY= github.com/dave/dst v0.27.3/go.mod h1:jHh6EOibnHgcUW3WjKHisiooEkYwqpHLBSX1iOBhEyc= -github.com/dave/jennifer v1.7.1 h1:B4jJJDHelWcDhlRQxWeo0Npa/pYKBLrirAQoTN45txo= -github.com/dave/jennifer v1.7.1/go.mod h1:nXbxhEmQfOZhWml3D1cDK5M1FLnMSozpbFN/m3RmGZc= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/denis-tingaikin/go-header v0.5.0 h1:SRdnP5ZKvcO9KKRP1KJrhFR3RrlGuD+42t4429eC9k8= github.com/denis-tingaikin/go-header v0.5.0/go.mod h1:mMenU5bWrok6Wl2UsZjy+1okegmwQ3UgWl4V1D8gjlY= -github.com/dlclark/regexp2 v1.11.5 h1:Q/sSnsKerHeCkc/jSTNq1oCm7KiVgUMZRDUoRu0JQZQ= github.com/dlclark/regexp2 v1.11.5/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= github.com/dprotaso/go-yit v0.0.0-20191028211022-135eb7262960/go.mod h1:9HQzr9D/0PGwMEbC3d5AB7oi67+h4TsQqItC1GVYG58= -github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936 h1:PRxIJD8XjimM5aTknUK9w6DHLDox2r2M3DI4i2pnd3w= github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936/go.mod h1:ttYvX5qlB+mlV1okblJqcSMtR4c52UKxDiX9GRBS8+Q= -github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc= -github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/ettle/strcase v0.2.0 h1:fGNiVF21fHXpX1niBgk0aROov1LagYsOwV/xqKDKR/Q= github.com/ettle/strcase v0.2.0/go.mod h1:DajmHElDSaX76ITe3/VHVyMin4LWSJN5Z909Wp+ED1A= -github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM= github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU= -github.com/fatih/structtag v1.2.0 h1:/OdNE99OxoI/PqaW/SuSK9uxxT3f/tcSZgon/ssNSx4= github.com/fatih/structtag v1.2.0/go.mod h1:mBJUNpUnHmRKrKlQQlmCrh5PuhftFbNv8Ys4/aAZl94= -github.com/firefart/nonamedreturns v1.0.6 h1:vmiBcKV/3EqKY3ZiPxCINmpS431OcE1S47AQUwhrg8E= github.com/firefart/nonamedreturns v1.0.6/go.mod h1:R8NisJnSIpvPWheCq0mNRXJok6D8h7fagJTF8EMEwCo= -github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY= -github.com/frankban/quicktest v1.14.4/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= -github.com/fsnotify/fsnotify v1.5.4 h1:jRbGcIw6P2Meqdwuo0H1p6JVLbL5DHKAKlYndzMwVZI= github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU= -github.com/fzipp/gocyclo v0.6.0 h1:lsblElZG7d3ALtGMx9fmxeTKZaLLpU8mET09yN4BBLo= github.com/fzipp/gocyclo v0.6.0/go.mod h1:rXPyn8fnlpa0R2csP/31uerbiVBugk5whMdlyaLkLoA= -github.com/ghostiam/protogetter v0.3.20 h1:oW7OPFit2FxZOpmMRPP9FffU4uUpfeE/rEdE1f+MzD0= github.com/ghostiam/protogetter v0.3.20/go.mod h1:FjIu5Yfs6FT391m+Fjp3fbAYJ6rkL/J6ySpZBfnODuI= -github.com/go-critic/go-critic v0.14.3 h1:5R1qH2iFeo4I/RJU8vTezdqs08Egi4u5p6vOESA0pog= github.com/go-critic/go-critic v0.14.3/go.mod h1:xwntfW6SYAd7h1OqDzmN6hBX/JxsEKl5up/Y2bsxgVQ= -github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI= -github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic= -github.com/go-git/go-billy/v5 v5.6.2 h1:6Q86EsPXMa7c3YZ3aLAQsMA0VlWmy43r6FHqa/UNbRM= -github.com/go-git/go-billy/v5 v5.6.2/go.mod h1:rcFC2rAsp/erv7CMz9GczHcuD0D32fWzH+MJAU+jaUU= -github.com/go-git/go-git/v5 v5.14.0 h1:/MD3lCrGjCen5WfEAzKg00MJJffKhC8gzS80ycmCi60= -github.com/go-git/go-git/v5 v5.14.0/go.mod h1:Z5Xhoia5PcWA3NF8vRLURn9E5FRhSl7dGj9ItW3Wk5k= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= @@ -235,51 +140,28 @@ github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vb github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= -github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= -github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= -github.com/go-quicktest/qt v1.101.0 h1:O1K29Txy5P2OK0dGo59b7b0LR6wKfIhttaAhHUyn7eI= -github.com/go-quicktest/qt v1.101.0/go.mod h1:14Bz/f7NwaXPtdYEgzsx46kqSxVwTbzVZsDC26tQJow= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 h1:p104kn46Q8WdvHunIJ9dAyjPVtrBPhSr3KT2yUst43I= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= -github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= -github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= -github.com/go-toolsmith/astcast v1.1.0 h1:+JN9xZV1A+Re+95pgnMgDboWNVnIMMQXwfBwLRPgSC8= github.com/go-toolsmith/astcast v1.1.0/go.mod h1:qdcuFWeGGS2xX5bLM/c3U9lewg7+Zu4mr+xPwZIB4ZU= -github.com/go-toolsmith/astcopy v1.1.0 h1:YGwBN0WM+ekI/6SS6+52zLDEf8Yvp3n2seZITCUBt5s= github.com/go-toolsmith/astcopy v1.1.0/go.mod h1:hXM6gan18VA1T/daUEHCFcYiW8Ai1tIwIzHY6srfEAw= github.com/go-toolsmith/astequal v1.0.3/go.mod h1:9Ai4UglvtR+4up+bAD4+hCj7iTo4m/OXVTSLnCyTAx4= github.com/go-toolsmith/astequal v1.1.0/go.mod h1:sedf7VIdCL22LD8qIvv7Nn9MuWJruQA/ysswh64lffQ= -github.com/go-toolsmith/astequal v1.2.0 h1:3Fs3CYZ1k9Vo4FzFhwwewC3CHISHDnVUPC4x0bI2+Cw= github.com/go-toolsmith/astequal v1.2.0/go.mod h1:c8NZ3+kSFtFY/8lPso4v8LuJjdJiUFVnSuU3s0qrrDY= -github.com/go-toolsmith/astfmt v1.1.0 h1:iJVPDPp6/7AaeLJEruMsBUlOYCmvg0MoCfJprsOmcco= github.com/go-toolsmith/astfmt v1.1.0/go.mod h1:OrcLlRwu0CuiIBp/8b5PYF9ktGVZUjlNMV634mhwuQ4= -github.com/go-toolsmith/astp v1.1.0 h1:dXPuCl6u2llURjdPLLDxJeZInAeZ0/eZwFJmqZMnpQA= github.com/go-toolsmith/astp v1.1.0/go.mod h1:0T1xFGz9hicKs8Z5MfAqSUitoUYS30pDMsRVIDHs8CA= -github.com/go-toolsmith/pkgload v1.2.2 h1:0CtmHq/02QhxcF7E9N5LIFcYFsMR5rdovfqTtRKkgIk= -github.com/go-toolsmith/pkgload v1.2.2/go.mod h1:R2hxLNRKuAsiXCo2i5J6ZQPhnPMOVtU+f0arbFPWCus= github.com/go-toolsmith/strparse v1.0.0/go.mod h1:YI2nUKP9YGZnL/L1/DLFBfixrcjslWct4wyljWhSRy8= -github.com/go-toolsmith/strparse v1.1.0 h1:GAioeZUK9TGxnLS+qfdqNbA4z0SSm5zVNtCQiyP2Bvw= github.com/go-toolsmith/strparse v1.1.0/go.mod h1:7ksGy58fsaQkGQlY8WVoBFNyEPMGuJin1rfoPS4lBSQ= -github.com/go-toolsmith/typep v1.1.0 h1:fIRYDyF+JywLfqzyhdiHzRop/GQDxxNhLGQ6gFUNHus= github.com/go-toolsmith/typep v1.1.0/go.mod h1:fVIw+7zjdsMxDA3ITWnH1yOiw1rnTQKCsF/sk2H/qig= -github.com/go-viper/mapstructure/v2 v2.5.0 h1:vM5IJoUAy3d7zRSVtIwQgBj7BiWtMPfmPEgAXnvj1Ro= github.com/go-viper/mapstructure/v2 v2.5.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= -github.com/go-xmlfmt/xmlfmt v1.1.3 h1:t8Ey3Uy7jDSEisW2K3somuMKIpzktkWptA0iFCnRUWY= github.com/go-xmlfmt/xmlfmt v1.1.3/go.mod h1:aUCEOzzezBEjDBbFBoSiya/gduyIiWYRP6CnSFIV8AM= -github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= -github.com/godoc-lint/godoc-lint v0.11.2 h1:Bp0FkJWoSdNsBikdNgIcgtaoo+xz6I/Y9s5WSBQUeeM= github.com/godoc-lint/godoc-lint v0.11.2/go.mod h1:iVpGdL1JCikNH2gGeAn3Hh+AgN5Gx/I/cxV+91L41jo= -github.com/gofrs/flock v0.13.0 h1:95JolYOvGMqeH31+FC7D2+uULf6mG61mEZ/A8dRYMzw= github.com/gofrs/flock v0.13.0/go.mod h1:jxeyy9R1auM5S6JYDBhDt+E2TCo7DkratH4Pgi8P+Z0= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 h1:f+oWsMOmNPc8JmEHVZIycC7hBoQxHH9pNKQORJNozsQ= -github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8/go.mod h1:wcDNUvekVysuuOpQKo3191zZyTpiI6se1N1ULghS0sw= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= @@ -303,29 +185,17 @@ github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/golangci/asciicheck v0.5.0 h1:jczN/BorERZwK8oiFBOGvlGPknhvq0bjnysTj4nUfo0= github.com/golangci/asciicheck v0.5.0/go.mod h1:5RMNAInbNFw2krqN6ibBxN/zfRFa9S6tA1nPdM0l8qQ= -github.com/golangci/dupl v0.0.0-20250308024227-f665c8d69b32 h1:WUvBfQL6EW/40l6OmeSBYQJNSif4O11+bmWEz+C7FYw= github.com/golangci/dupl v0.0.0-20250308024227-f665c8d69b32/go.mod h1:NUw9Zr2Sy7+HxzdjIULge71wI6yEg1lWQr7Evcu8K0E= -github.com/golangci/go-printf-func-name v0.1.1 h1:hIYTFJqAGp1iwoIfsNTpoq1xZAarogrvjO9AfiW3B4U= github.com/golangci/go-printf-func-name v0.1.1/go.mod h1:Es64MpWEZbh0UBtTAICOZiB+miW53w/K9Or/4QogJss= -github.com/golangci/gofmt v0.0.0-20250106114630-d62b90e6713d h1:viFft9sS/dxoYY0aiOTsLKO2aZQAPT4nlQCsimGcSGE= github.com/golangci/gofmt v0.0.0-20250106114630-d62b90e6713d/go.mod h1:ivJ9QDg0XucIkmwhzCDsqcnxxlDStoTl89jDMIoNxKY= -github.com/golangci/golangci-lint/v2 v2.10.1 h1:flhw5Px6ojbLyEFzXvJn5B2HEdkkRlkhE1SnmCbQBiE= github.com/golangci/golangci-lint/v2 v2.10.1/go.mod h1:dBsrOk6zj0vDhlTv+IiJGqkDokR24IVTS7W3EVfPTQY= -github.com/golangci/golines v0.15.0 h1:Qnph25g8Y1c5fdo1X7GaRDGgnMHgnxh4Gk4VfPTtRx0= github.com/golangci/golines v0.15.0/go.mod h1:AZjXd23tbHMpowhtnGlj9KCNsysj72aeZVVHnVcZx10= -github.com/golangci/misspell v0.8.0 h1:qvxQhiE2/5z+BVRo1kwYA8yGz+lOlu5Jfvtx2b04Jbg= github.com/golangci/misspell v0.8.0/go.mod h1:WZyyI2P3hxPY2UVHs3cS8YcllAeyfquQcKfdeE9AFVg= -github.com/golangci/plugin-module-register v0.1.2 h1:e5WM6PO6NIAEcij3B053CohVp3HIYbzSuP53UAYgOpg= github.com/golangci/plugin-module-register v0.1.2/go.mod h1:1+QGTsKBvAIvPvoY/os+G5eoqxWn70HYDm2uvUyGuVw= -github.com/golangci/revgrep v0.8.0 h1:EZBctwbVd0aMeRnNUsFogoyayvKHyxlV3CdUA46FX2s= github.com/golangci/revgrep v0.8.0/go.mod h1:U4R/s9dlXZsg8uJmaR1GrloUr14D7qDl8gi2iPXJH8k= -github.com/golangci/swaggoswag v0.0.0-20250504205917-77f2aca3143e h1:ai0EfmVYE2bRA5htgAG9r7s3tHsfjIhN98WshBTJ9jM= github.com/golangci/swaggoswag v0.0.0-20250504205917-77f2aca3143e/go.mod h1:Vrn4B5oR9qRwM+f54koyeH3yzphlecwERs0el27Fr/s= -github.com/golangci/unconvert v0.0.0-20250410112200-a129a6e6413e h1:gD6P7NEo7Eqtt0ssnqSJNNndxe69DOQ24A5h7+i3KpM= github.com/golangci/unconvert v0.0.0-20250410112200-a129a6e6413e/go.mod h1:h+wZwLjUTJnm/P2rwlbJdRPZXOzaT36/FwnPnY2inzc= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= @@ -340,7 +210,6 @@ github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= @@ -353,93 +222,54 @@ github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hf github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20260115054156-294ebfa9ad83 h1:z2ogiKUYzX5Is6zr/vP9vJGqPwcdqsWjOt+V8J7+bTc= -github.com/google/pprof v0.0.0-20260115054156-294ebfa9ad83/go.mod h1:MxpfABSjhmINe3F1It9d+8exIHFvUqtLIRCdOGNXqiI= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= -github.com/gordonklaus/ineffassign v0.2.0 h1:Uths4KnmwxNJNzq87fwQQDDnbNb7De00VOk9Nu0TySs= github.com/gordonklaus/ineffassign v0.2.0/go.mod h1:TIpymnagPSexySzs7F9FnO1XFTy8IT3a59vmZp5Y9Lw= -github.com/gostaticanalysis/analysisutil v0.7.1 h1:ZMCjoue3DtDWQ5WyU16YbjbQEQ3VuzwxALrpYd+HeKk= github.com/gostaticanalysis/analysisutil v0.7.1/go.mod h1:v21E3hY37WKMGSnbsw2S/ojApNWb6C1//mXO48CXbVc= github.com/gostaticanalysis/comment v1.4.2/go.mod h1:KLUTGDv6HOCotCH8h2erHKmpci2ZoR8VPu34YA2uzdM= -github.com/gostaticanalysis/comment v1.5.0 h1:X82FLl+TswsUMpMh17srGRuKaaXprTaytmEpgnKIDu8= github.com/gostaticanalysis/comment v1.5.0/go.mod h1:V6eb3gpCv9GNVqb6amXzEUX3jXLVK/AdA+IrAMSqvEc= -github.com/gostaticanalysis/forcetypeassert v0.2.0 h1:uSnWrrUEYDr86OCxWa4/Tp2jeYDlogZiZHzGkWFefTk= github.com/gostaticanalysis/forcetypeassert v0.2.0/go.mod h1:M5iPavzE9pPqWyeiVXSFghQjljW1+l/Uke3PXHS6ILY= -github.com/gostaticanalysis/nilerr v0.1.2 h1:S6nk8a9N8g062nsx63kUkF6AzbHGw7zzyHMcpu52xQU= github.com/gostaticanalysis/nilerr v0.1.2/go.mod h1:A19UHhoY3y8ahoL7YKz6sdjDtduwTSI4CsymaC2htPA= github.com/gostaticanalysis/testutil v0.3.1-0.20210208050101-bfb5c8eec0e4/go.mod h1:D+FIZ+7OahH3ePw/izIEeH5I06eKs1IKI4Xr64/Am3M= -github.com/gostaticanalysis/testutil v0.5.0 h1:Dq4wT1DdTwTGCQQv3rl3IvD5Ld0E6HiY+3Zh0sUGqw8= -github.com/gostaticanalysis/testutil v0.5.0/go.mod h1:OLQSbuM6zw2EvCcXTz1lVq5unyoNft372msDY0nY5Hs= -github.com/hashicorp/cli v1.1.7 h1:/fZJ+hNdwfTSfsxMBa9WWMlfjUZbX8/LnUxgAd7lCVU= github.com/hashicorp/cli v1.1.7/go.mod h1:e6Mfpga9OCT1vqzFuoGZiiF/KaG9CbUfO5s3ghU3YgU= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= -github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= -github.com/hashicorp/go-checkpoint v0.5.0 h1:MFYpPZCnQqQTE18jFwSII6eUQrD/oxMFp3mlgcqk5mU= github.com/hashicorp/go-checkpoint v0.5.0/go.mod h1:7nfLNL10NsxqO4iWuW6tWW0HjZuDrwkBuEQsVcpCOgg= github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= -github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= -github.com/hashicorp/go-hclog v1.6.3 h1:Qr2kF+eVWjTiYmU7Y31tYlP1h0q/X3Nl3tPGdaB11/k= -github.com/hashicorp/go-hclog v1.6.3/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= -github.com/hashicorp/go-immutable-radix/v2 v2.1.0 h1:CUW5RYIcysz+D3B+l1mDeXrQ7fUvGGCwJfdASSzbrfo= github.com/hashicorp/go-immutable-radix/v2 v2.1.0/go.mod h1:hgdqLXA4f6NIjRVisM1TJ9aOJVNRqKZj+xDGF6m7PBw= github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= -github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= -github.com/hashicorp/go-retryablehttp v0.7.7 h1:C8hUCYzor8PIfXHa4UrZkU4VvK8o9ISHxT2Q8+VepXU= github.com/hashicorp/go-retryablehttp v0.7.7/go.mod h1:pkQpWZeYWskR+D1tR2O5OcBFOxfA7DoAO6xtkuQnHTk= github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= -github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-version v1.2.1/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= -github.com/hashicorp/go-version v1.8.0 h1:KAkNb1HAiZd1ukkxDFGmokVZe1Xy9HG6NUp+bPle2i4= github.com/hashicorp/go-version v1.8.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k= github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= -github.com/hashicorp/hc-install v0.9.2 h1:v80EtNX4fCVHqzL9Lg/2xkp62bbvQMnvPQ0G+OmtO24= github.com/hashicorp/hc-install v0.9.2/go.mod h1:XUqBQNnuT4RsxoxiM9ZaUk0NX8hi2h+Lb6/c0OZnC/I= -github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= -github.com/hashicorp/terraform-exec v0.24.0 h1:mL0xlk9H5g2bn0pPF6JQZk5YlByqSqrO5VoaNtAf8OE= github.com/hashicorp/terraform-exec v0.24.0/go.mod h1:lluc/rDYfAhYdslLJQg3J0oDqo88oGQAdHR+wDqFvo4= -github.com/hashicorp/terraform-json v0.27.2 h1:BwGuzM6iUPqf9JYM/Z4AF1OJ5VVJEEzoKST/tRDBJKU= github.com/hashicorp/terraform-json v0.27.2/go.mod h1:GzPLJ1PLdUG5xL6xn1OXWIjteQRT2CNT9o/6A9mi9hE= -github.com/hashicorp/terraform-plugin-codegen-framework v0.4.1 h1:eaI/3dsu2T5QAXbA+7N+B+UBj20GdtYnsRuYypKh3S4= github.com/hashicorp/terraform-plugin-codegen-framework v0.4.1/go.mod h1:kpYM23L7NtcfaQdWAN0QFkV/lU0w16qJ2ddAPCI4zAg= -github.com/hashicorp/terraform-plugin-codegen-openapi v0.3.0 h1:IKpc337XKk50QyQPSxLrHwdqSo1E2XqCMxFkWsZcTvc= github.com/hashicorp/terraform-plugin-codegen-openapi v0.3.0/go.mod h1:tT6wl80h7nsMBw+1yZRgJXi+Ys85PUai11weDqysvp4= -github.com/hashicorp/terraform-plugin-codegen-spec v0.2.0 h1:91dQG1A/DxP6vRz9GiytDTrZTXDbhHPvmpYnAyWA/Vw= github.com/hashicorp/terraform-plugin-codegen-spec v0.2.0/go.mod h1:fywrEKpordQypmAjz/HIfm2LuNVmyJ6KDe8XT9GdJxQ= -github.com/hashicorp/terraform-plugin-docs v0.24.0 h1:YNZYd+8cpYclQyXbl1EEngbld8w7/LPOm99GD5nikIU= github.com/hashicorp/terraform-plugin-docs v0.24.0/go.mod h1:YLg+7LEwVmRuJc0EuCw0SPLxuQXw5mW8iJ5ml/kvi+o= -github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM= github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/huandu/xstrings v1.3.3/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= -github.com/huandu/xstrings v1.4.0 h1:D17IlohoQq4UcpqD7fDk80P7l+lwAmlFaBHgOipl2FU= github.com/huandu/xstrings v1.4.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= -github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4= github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY= -github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= -github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A= -github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= -github.com/jgautheron/goconst v1.8.2 h1:y0XF7X8CikZ93fSNT6WBTb/NElBu9IjaY7CCYQrCMX4= github.com/jgautheron/goconst v1.8.2/go.mod h1:A0oxgBCHy55NQn6sYpO7UdnA9p+h7cPtoOZUmvNIako= -github.com/jingyugao/rowserrcheck v1.1.1 h1:zibz55j/MJtLsjP1OF4bSdgXxwL1b+Vn7Tjzq7gFzUs= github.com/jingyugao/rowserrcheck v1.1.1/go.mod h1:4yvlZSDb3IyDTUZJUmpZfm2Hwok+Dtp+nu2qOq+er9c= -github.com/jjti/go-spancheck v0.6.5 h1:lmi7pKxa37oKYIMScialXUK6hP3iY5F1gu+mLBPgYB8= github.com/jjti/go-spancheck v0.6.5/go.mod h1:aEogkeatBrbYsyW6y5TgDfihCulDYciL1B7rG2vSsrU= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= @@ -451,297 +281,175 @@ github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1 github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= -github.com/julz/importas v0.2.0 h1:y+MJN/UdL63QbFJHws9BVC5RpA2iq0kpjrFajTGivjQ= github.com/julz/importas v0.2.0/go.mod h1:pThlt589EnCYtMnmhmRYY/qn9lCf/frPOK+WMx3xiJY= -github.com/karamaru-alpha/copyloopvar v1.2.2 h1:yfNQvP9YaGQR7VaWLYcfZUlRP2eo2vhExWKxD/fP6q0= github.com/karamaru-alpha/copyloopvar v1.2.2/go.mod h1:oY4rGZqZ879JkJMtX3RRkcXRkmUvH0x35ykgaKgsgJY= -github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4= -github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= -github.com/kisielk/errcheck v1.9.0 h1:9xt1zI9EBfcYBvdU1nVrzMzzUPUtPKs9bVSIM3TAb3M= github.com/kisielk/errcheck v1.9.0/go.mod h1:kQxWMMVZgIkDq7U8xtG/n2juOjbLgZtedi0D+/VL/i8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/kkHAIKE/contextcheck v1.1.6 h1:7HIyRcnyzxL9Lz06NGhiKvenXq7Zw6Q0UQu/ttjfJCE= github.com/kkHAIKE/contextcheck v1.1.6/go.mod h1:3dDbMRNBFaq8HFXWC1JyvDSPm43CmE6IuHam8Wr0rkg= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= -github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= -github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/kulti/thelper v0.7.1 h1:fI8QITAoFVLx+y+vSyuLBP+rcVIB8jKooNSCT2EiI98= github.com/kulti/thelper v0.7.1/go.mod h1:NsMjfQEy6sd+9Kfw8kCP61W1I0nerGSYSFnGaxQkcbs= -github.com/kunwardeep/paralleltest v1.0.15 h1:ZMk4Qt306tHIgKISHWFJAO1IDQJLc6uDyJMLyncOb6w= github.com/kunwardeep/paralleltest v1.0.15/go.mod h1:di4moFqtfz3ToSKxhNjhOZL+696QtJGCFe132CbBLGk= -github.com/lasiar/canonicalheader v1.1.2 h1:vZ5uqwvDbyJCnMhmFYimgMZnJMjwljN5VGY0VKbMXb4= github.com/lasiar/canonicalheader v1.1.2/go.mod h1:qJCeLFS0G/QlLQ506T+Fk/fWMa2VmBUiEI2cuMK4djI= -github.com/ldez/exptostd v0.4.5 h1:kv2ZGUVI6VwRfp/+bcQ6Nbx0ghFWcGIKInkG/oFn1aQ= github.com/ldez/exptostd v0.4.5/go.mod h1:QRjHRMXJrCTIm9WxVNH6VW7oN7KrGSht69bIRwvdFsM= -github.com/ldez/gomoddirectives v0.8.0 h1:JqIuTtgvFC2RdH1s357vrE23WJF2cpDCPFgA/TWDGpk= github.com/ldez/gomoddirectives v0.8.0/go.mod h1:jutzamvZR4XYJLr0d5Honycp4Gy6GEg2mS9+2YX3F1Q= -github.com/ldez/grignotin v0.10.1 h1:keYi9rYsgbvqAZGI1liek5c+jv9UUjbvdj3Tbn5fn4o= github.com/ldez/grignotin v0.10.1/go.mod h1:UlDbXFCARrXbWGNGP3S5vsysNXAPhnSuBufpTEbwOas= -github.com/ldez/structtags v0.6.1 h1:bUooFLbXx41tW8SvkfwfFkkjPYvFFs59AAMgVg6DUBk= github.com/ldez/structtags v0.6.1/go.mod h1:YDxVSgDy/MON6ariaxLF2X09bh19qL7MtGBN5MrvbdY= -github.com/ldez/tagliatelle v0.7.2 h1:KuOlL70/fu9paxuxbeqlicJnCspCRjH0x8FW+NfgYUk= github.com/ldez/tagliatelle v0.7.2/go.mod h1:PtGgm163ZplJfZMZ2sf5nhUT170rSuPgBimoyYtdaSI= -github.com/ldez/usetesting v0.5.0 h1:3/QtzZObBKLy1F4F8jLuKJiKBjjVFi1IavpoWbmqLwc= github.com/ldez/usetesting v0.5.0/go.mod h1:Spnb4Qppf8JTuRgblLrEWb7IE6rDmUpGvxY3iRrzvDQ= -github.com/leonklingele/grouper v1.1.2 h1:o1ARBDLOmmasUaNDesWqWCIFH3u7hoFlM84YrjT3mIY= github.com/leonklingele/grouper v1.1.2/go.mod h1:6D0M/HVkhs2yRKRFZUoGjeDy7EZTfFBE9gl4kjmIGkA= -github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY= github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= -github.com/macabu/inamedparam v0.2.0 h1:VyPYpOc10nkhI2qeNUdh3Zket4fcZjEWe35poddBCpE= github.com/macabu/inamedparam v0.2.0/go.mod h1:+Pee9/YfGe5LJ62pYXqB89lJ+0k5bsR8Wgz/C0Zlq3U= -github.com/magiconair/properties v1.8.6 h1:5ibWZ6iY0NctNGWo87LalDlEZ6R41TqbbDamhfG/Qzo= github.com/magiconair/properties v1.8.6/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= -github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= -github.com/manuelarte/embeddedstructfieldcheck v0.4.0 h1:3mAIyaGRtjK6EO9E73JlXLtiy7ha80b2ZVGyacxgfww= github.com/manuelarte/embeddedstructfieldcheck v0.4.0/go.mod h1:z8dFSyXqp+fC6NLDSljRJeNQJJDWnY7RoWFzV3PC6UM= -github.com/manuelarte/funcorder v0.5.0 h1:llMuHXXbg7tD0i/LNw8vGnkDTHFpTnWqKPI85Rknc+8= github.com/manuelarte/funcorder v0.5.0/go.mod h1:Yt3CiUQthSBMBxjShjdXMexmzpP8YGvGLjrxJNkO2hA= -github.com/maratori/testableexamples v1.0.1 h1:HfOQXs+XgfeRBJ+Wz0XfH+FHnoY9TVqL6Fcevpzy4q8= github.com/maratori/testableexamples v1.0.1/go.mod h1:XE2F/nQs7B9N08JgyRmdGjYVGqxWwClLPCGSQhXQSrQ= -github.com/maratori/testpackage v1.1.2 h1:ffDSh+AgqluCLMXhM19f/cpvQAKygKAJXFl9aUjmbqs= github.com/maratori/testpackage v1.1.2/go.mod h1:8F24GdVDFW5Ew43Et02jamrVMNXLUNaOynhDssITGfc= -github.com/matoous/godox v1.1.0 h1:W5mqwbyWrwZv6OQ5Z1a/DHGMOvXYCBP3+Ht7KMoJhq4= github.com/matoous/godox v1.1.0/go.mod h1:jgE/3fUXiTurkdHOLT5WEkThTSuE7yxHv5iWPa80afs= -github.com/matryer/is v1.4.0 h1:sosSmIWwkYITGrxZ25ULNDeKiMNzFSr4V/eqBQP0PeE= github.com/matryer/is v1.4.0/go.mod h1:8I/i5uYgLzgsgEloJE1U6xx5HkBQpAZvepWuujKwMRU= -github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE= github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= -github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= -github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc= github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= -github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= -github.com/mgechev/revive v1.14.0 h1:CC2Ulb3kV7JFYt+izwORoS3VT/+Plb8BvslI/l1yZsc= github.com/mgechev/revive v1.14.0/go.mod h1:MvnujelCZBZCaoDv5B3foPo6WWgULSSFxvfxp7GsPfo= github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= -github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= -github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= -github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= -github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= -github.com/moricho/tparallel v0.3.2 h1:odr8aZVFA3NZrNybggMkYO3rgPRcqjeQUlBBFVxKHTI= github.com/moricho/tparallel v0.3.2/go.mod h1:OQ+K3b4Ln3l2TZveGCywybl68glfLEwFGqvnjok8b+U= -github.com/muesli/termenv v0.16.0 h1:S5AlUN9dENB57rsbnkPyfdGuWIlkmzJjbFf0Tf5FWUc= github.com/muesli/termenv v0.16.0/go.mod h1:ZRfOIKPFDYQoDFF4Olj7/QJbW60Ol/kL1pU3VfY/Cnk= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= -github.com/nakabonne/nestif v0.3.1 h1:wm28nZjhQY5HyYPx+weN3Q65k6ilSBxDb8v5S81B81U= github.com/nakabonne/nestif v0.3.1/go.mod h1:9EtoZochLn5iUprVDmDjqGKPofoUEBL8U4Ngq6aY7OE= -github.com/nishanths/exhaustive v0.12.0 h1:vIY9sALmw6T/yxiASewa4TQcFsVYZQQRUQJhKRf3Swg= github.com/nishanths/exhaustive v0.12.0/go.mod h1:mEZ95wPIZW+x8kC4TgC+9YCUgiST7ecevsVDTgc2obs= -github.com/nishanths/predeclared v0.2.2 h1:V2EPdZPliZymNAn79T8RkNApBjMmVKh5XRpLm/w98Vk= github.com/nishanths/predeclared v0.2.2/go.mod h1:RROzoN6TnGQupbC+lqggsOlcgysk3LMK/HI84Mp280c= -github.com/nunnatsa/ginkgolinter v0.23.0 h1:x3o4DGYOWbBMP/VdNQKgSj+25aJKx2Pe6lHr8gBcgf8= github.com/nunnatsa/ginkgolinter v0.23.0/go.mod h1:9qN1+0akwXEccwV1CAcCDfcoBlWXHB+ML9884pL4SZ4= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= -github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.10.2/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= -github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc= github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c= -github.com/onsi/ginkgo/v2 v2.28.1 h1:S4hj+HbZp40fNKuLUQOYLDgZLwNUVn19N3Atb98NCyI= -github.com/onsi/ginkgo/v2 v2.28.1/go.mod h1:CLtbVInNckU3/+gC8LzkGUb9oF+e8W8TdUsxPwvdOgE= github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro= -github.com/onsi/gomega v1.39.1 h1:1IJLAad4zjPn2PsnhH70V4DKRFlrCzGBNrNaru+Vf28= -github.com/onsi/gomega v1.39.1/go.mod h1:hL6yVALoTOxeWudERyfppUcZXjMwIMLnuSfruD2lcfg= github.com/otiai10/copy v1.2.0/go.mod h1:rrF5dJ5F0t/EWSYODDu4j9/vEeYHMkc8jt0zJChqQWw= -github.com/otiai10/copy v1.14.0 h1:dCI/t1iTdYGtkvCuBG2BgR6KZa83PTclw4U5n2wAllU= -github.com/otiai10/copy v1.14.0/go.mod h1:ECfuL02W+/FkTWZWgQqXPWZgW9oeKCSQ5qVfSc4qc4w= github.com/otiai10/curr v0.0.0-20150429015615-9b4961190c95/go.mod h1:9qAhocn7zKJG+0mI8eUu6xqkFDYS2kb2saOteoSB3cE= github.com/otiai10/curr v1.0.0/go.mod h1:LskTG5wDwr8Rs+nNQ+1LlxRjAtTZZjtJW4rMXl6j4vs= github.com/otiai10/mint v1.3.0/go.mod h1:F5AjcsTsWUqX+Na9fpHb52P8pcRX2CI6A3ctIT91xUo= github.com/otiai10/mint v1.3.1/go.mod h1:/yxELlJQ0ufhjUwhshSj+wFjZ78CnZ48/1wtmBH1OTc= -github.com/pb33f/libopenapi v0.15.0 h1:AoBYIY3HXqDDF8O9kcudlqWaRFZZJmgtueE649oHzIw= github.com/pb33f/libopenapi v0.15.0/go.mod h1:m+4Pwri31UvcnZjuP8M7TlbR906DXJmMvYsbis234xg= -github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8= github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= -github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4= github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY= -github.com/pjbgf/sha1cd v0.3.2 h1:a9wb0bp1oC2TGwStyn0Umc/IGKQnEgF0vVaZ8QF8eo4= -github.com/pjbgf/sha1cd v0.3.2/go.mod h1:zQWigSxVmsHEZow5qaLtPYxpcKMMQpa09ixqBxuCS6A= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/posener/complete v1.2.3 h1:NP0eAhjcjImqslEwo/1hq7gpajME0fTLTezBKDqfXqo= github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= -github.com/prometheus/client_golang v1.12.1 h1:ZiaPsmm9uiBeaSMRznKsCDNtPCS0T3JVDGF+06gjBzk= github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M= github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= -github.com/prometheus/common v0.32.1 h1:hWIdL3N2HoUx3B8j3YN9mWor0qhY/NlEKZEaXxuIRh4= github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= -github.com/prometheus/procfs v0.7.3 h1:4jVXhlkAyzOScmCkXBTOLRLTz8EeU+eyjrwB/EPq0VU= github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= -github.com/quasilyte/go-ruleguard v0.4.5 h1:AGY0tiOT5hJX9BTdx/xBdoCubQUAE2grkqY2lSwvZcA= github.com/quasilyte/go-ruleguard v0.4.5/go.mod h1:Vl05zJ538vcEEwu16V/Hdu7IYZWyKSwIy4c88Ro1kRE= -github.com/quasilyte/go-ruleguard/dsl v0.3.23 h1:lxjt5B6ZCiBeeNO8/oQsegE6fLeCzuMRoVWSkXC4uvY= github.com/quasilyte/go-ruleguard/dsl v0.3.23/go.mod h1:KeCP03KrjuSO0H1kTuZQCWlQPulDV6YMIXmpQss17rU= -github.com/quasilyte/gogrep v0.5.0 h1:eTKODPXbI8ffJMN+W2aE0+oL0z/nh8/5eNdiO34SOAo= github.com/quasilyte/gogrep v0.5.0/go.mod h1:Cm9lpz9NZjEoL1tgZ2OgeUKPIxL1meE7eo60Z6Sk+Ng= -github.com/quasilyte/regex/syntax v0.0.0-20210819130434-b3f0c404a727 h1:TCg2WBOl980XxGFEZSS6KlBGIV0diGdySzxATTWoqaU= github.com/quasilyte/regex/syntax v0.0.0-20210819130434-b3f0c404a727/go.mod h1:rlzQ04UMyJXu/aOvhd8qT+hvDrFpiwqp8MRXDY9szc0= -github.com/quasilyte/stdinfo v0.0.0-20220114132959-f7386bf02567 h1:M8mH9eK4OUR4lu7Gd+PU1fV2/qnDNfzT635KRSObncs= github.com/quasilyte/stdinfo v0.0.0-20220114132959-f7386bf02567/go.mod h1:DWNGW8A4Y+GyBgPuaQJuWiy0XYftx4Xm/y5Jqk9I6VQ= -github.com/raeperd/recvcheck v0.2.0 h1:GnU+NsbiCqdC2XX5+vMZzP+jAJC5fht7rcVTAhX74UI= github.com/raeperd/recvcheck v0.2.0/go.mod h1:n04eYkwIR0JbgD73wT8wL4JjPC3wm0nFtzBnWNocnYU= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= -github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/ryancurrah/gomodguard v1.4.1 h1:eWC8eUMNZ/wM/PWuZBv7JxxqT5fiIKSIyTvjb7Elr+g= github.com/ryancurrah/gomodguard v1.4.1/go.mod h1:qnMJwV1hX9m+YJseXEBhd2s90+1Xn6x9dLz11ualI1I= -github.com/ryanrolds/sqlclosecheck v0.5.1 h1:dibWW826u0P8jNLsLN+En7+RqWWTYrjCB9fJfSfdyCU= github.com/ryanrolds/sqlclosecheck v0.5.1/go.mod h1:2g3dUjoS6AL4huFdv6wn55WpLIDjY7ZgUR4J8HOO/XQ= -github.com/sanposhiho/wastedassign/v2 v2.1.0 h1:crurBF7fJKIORrV85u9UUpePDYGWnwvv3+A96WvwXT0= github.com/sanposhiho/wastedassign/v2 v2.1.0/go.mod h1:+oSmSC+9bQ+VUAxA66nBb0Z7N8CK7mscKTDYC6aIek4= -github.com/santhosh-tekuri/jsonschema/v6 v6.0.2 h1:KRzFb2m7YtdldCEkzs6KqmJw4nqEVZGK7IN2kJkjTuQ= github.com/santhosh-tekuri/jsonschema/v6 v6.0.2/go.mod h1:JXeL+ps8p7/KNMjDQk3TCwPpBy0wYklyWTfbkIzdIFU= -github.com/sashamelentyev/interfacebloat v1.1.0 h1:xdRdJp0irL086OyW1H/RTZTr1h/tMEOsumirXcOJqAw= github.com/sashamelentyev/interfacebloat v1.1.0/go.mod h1:+Y9yU5YdTkrNvoX0xHc84dxiN1iBi9+G8zZIhPVoNjQ= -github.com/sashamelentyev/usestdlibvars v1.29.0 h1:8J0MoRrw4/NAXtjQqTHrbW9NN+3iMf7Knkq057v4XOQ= github.com/sashamelentyev/usestdlibvars v1.29.0/go.mod h1:8PpnjHMk5VdeWlVb4wCdrB8PNbLqZ3wBZTZWkrpZZL8= -github.com/securego/gosec/v2 v2.23.0 h1:h4TtF64qFzvnkqvsHC/knT7YC5fqyOCItlVR8+ptEBo= github.com/securego/gosec/v2 v2.23.0/go.mod h1:qRHEgXLFuYUDkI2T7W7NJAmOkxVhkR0x9xyHOIcMNZ0= github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= -github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 h1:n661drycOFuPLCN3Uc8sB6B/s6Z4t2xvBgU1htSHuq8= -github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4= github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= -github.com/shopspring/decimal v1.3.1 h1:2Usl1nmF/WZucqkFZhnfFYxxxu8LG21F6nPQBE5gKV8= github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= github.com/shurcooL/go v0.0.0-20180423040247-9e1955d9fb6e/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk= github.com/shurcooL/go-goon v0.0.0-20170922171312-37c2f522c041/go.mod h1:N5mDOmsrJOB+vfqUK+7DmDyjhSLIIBnXo9lvZJj3MWQ= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= -github.com/sirupsen/logrus v1.9.4 h1:TsZE7l11zFCLZnZ+teH4Umoq5BhEIfIzfRDZ1Uzql2w= github.com/sirupsen/logrus v1.9.4/go.mod h1:ftWc9WdOfJ0a92nsE2jF5u5ZwH8Bv2zdeOC42RjbV2g= -github.com/sivchari/containedctx v1.0.3 h1:x+etemjbsh2fB5ewm5FeLNi5bUjK0V8n0RB+Wwfd0XE= github.com/sivchari/containedctx v1.0.3/go.mod h1:c1RDvCbnJLtH4lLcYD/GqwiBSSf4F5Qk0xld2rBqzJ4= -github.com/skeema/knownhosts v1.3.1 h1:X2osQ+RAjK76shCbvhHHHVl3ZlgDm8apHEHFqRjnBY8= -github.com/skeema/knownhosts v1.3.1/go.mod h1:r7KTdC8l4uxWRyK2TpQZ/1o5HaSzh06ePQNxPwTcfiY= -github.com/sonatard/noctx v0.4.0 h1:7MC/5Gg4SQ4lhLYR6mvOP6mQVSxCrdyiExo7atBs27o= github.com/sonatard/noctx v0.4.0/go.mod h1:64XdbzFb18XL4LporKXp8poqZtPKbCrqQ402CV+kJas= -github.com/sourcegraph/go-diff v0.7.0 h1:9uLlrd5T46OXs5qpp8L/MTltk0zikUGi0sNNyCpA8G0= github.com/sourcegraph/go-diff v0.7.0/go.mod h1:iBszgVvyxdc8SFZ7gm69go2KDdt3ag071iBaWPF6cjs= -github.com/spf13/afero v1.15.0 h1:b/YBCLWAJdFWJTN9cLhiXXcD7mzKn9Dm86dNnfyQw1I= github.com/spf13/afero v1.15.0/go.mod h1:NC2ByUVxtQs4b3sIUphxK0NioZnmxgyCrfzeuq8lxMg= github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/cast v1.5.1 h1:R+kOtfhWQE6TVQzY+4D7wJLBgkdVasCEFxSUBYBYIlA= github.com/spf13/cast v1.5.1/go.mod h1:b9PdjNptOpzXr7Rq1q9gJML/2cdGQAo69NKzQ10KN48= -github.com/spf13/cobra v1.10.2 h1:DMTTonx5m65Ic0GOoRY2c16WCbHxOOw6xxezuLaBpcU= github.com/spf13/cobra v1.10.2/go.mod h1:7C1pvHqHw5A4vrJfjNwvOdzYu0Gml16OCs2GRiTUUS4= -github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk= github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/spf13/viper v1.12.0 h1:CZ7eSOd3kZoaYDLbXnmzgQI5RlciuXBMA+18HwHRfZQ= github.com/spf13/viper v1.12.0/go.mod h1:b6COn30jlNxbm/V2IqWiNWkJ+vZNiMNksliPCiuKtSI= -github.com/ssgreg/nlreturn/v2 v2.2.1 h1:X4XDI7jstt3ySqGU86YGAURbxw3oTDPK9sPEi6YEwQ0= github.com/ssgreg/nlreturn/v2 v2.2.1/go.mod h1:E/iiPB78hV7Szg2YfRgyIrk1AD6JVMTRkkxBiELzh2I= -github.com/stbenjam/no-sprintf-host-port v0.3.1 h1:AyX7+dxI4IdLBPtDbsGAyqiTSLpCP9hWRrXQDU4Cm/g= github.com/stbenjam/no-sprintf-host-port v0.3.1/go.mod h1:ODbZesTCHMVKthBHskvUUexdcNHAQRXk9NpSsL8p/HQ= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= -github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= -github.com/subosito/gotenv v1.4.1 h1:jyEFiXpy21Wm81FBN71l9VoMMV8H8jG+qIK3GCpY6Qs= github.com/subosito/gotenv v1.4.1/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0= -github.com/tenntenn/modver v1.0.1 h1:2klLppGhDgzJrScMpkj9Ujy3rXPUspSjAcev9tSEBgA= github.com/tenntenn/modver v1.0.1/go.mod h1:bePIyQPb7UeioSRkw3Q0XeMhYZSMx9B8ePqg6SAMGH0= -github.com/tenntenn/text/transform v0.0.0-20200319021203-7eef512accb3 h1:f+jULpRQGxTSkNYKJ51yaw6ChIqO+Je8UqsTKN/cDag= github.com/tenntenn/text/transform v0.0.0-20200319021203-7eef512accb3/go.mod h1:ON8b8w4BN/kE1EOhwT0o+d62W65a6aPw1nouo9LMgyY= -github.com/tetafro/godot v1.5.4 h1:u1ww+gqpRLiIA16yF2PV1CV1n/X3zhyezbNXC3E14Sg= github.com/tetafro/godot v1.5.4/go.mod h1:eOkMrVQurDui411nBY2FA05EYH01r14LuWY/NrVDVcU= -github.com/timakin/bodyclose v0.0.0-20241222091800-1db5c5ca4d67 h1:9LPGD+jzxMlnk5r6+hJnar67cgpDIz/iyD+rfl5r2Vk= github.com/timakin/bodyclose v0.0.0-20241222091800-1db5c5ca4d67/go.mod h1:mkjARE7Yr8qU23YcGMSALbIxTQ9r9QBVahQOBRfU460= -github.com/timonwong/loggercheck v0.11.0 h1:jdaMpYBl+Uq9mWPXv1r8jc5fC3gyXx4/WGwTnnNKn4M= github.com/timonwong/loggercheck v0.11.0/go.mod h1:HEAWU8djynujaAVX7QI65Myb8qgfcZ1uKbdpg3ZzKl8= -github.com/tomarrell/wrapcheck/v2 v2.12.0 h1:H/qQ1aNWz/eeIhxKAFvkfIA+N7YDvq6TWVFL27Of9is= github.com/tomarrell/wrapcheck/v2 v2.12.0/go.mod h1:AQhQuZd0p7b6rfW+vUwHm5OMCGgp63moQ9Qr/0BpIWo= -github.com/tommy-muehle/go-mnd/v2 v2.5.1 h1:NowYhSdyE/1zwK9QCLeRb6USWdoif80Ie+v+yU8u1Zw= github.com/tommy-muehle/go-mnd/v2 v2.5.1/go.mod h1:WsUAkMJMYww6l/ufffCD3m+P7LEvr8TnZn9lwVDlgzw= -github.com/ultraware/funlen v0.2.0 h1:gCHmCn+d2/1SemTdYMiKLAHFYxTYz7z9VIDRaTGyLkI= github.com/ultraware/funlen v0.2.0/go.mod h1:ZE0q4TsJ8T1SQcjmkhN/w+MceuatI6pBFSxxyteHIJA= -github.com/ultraware/whitespace v0.2.0 h1:TYowo2m9Nfj1baEQBjuHzvMRbp19i+RCcRYrSWoFa+g= github.com/ultraware/whitespace v0.2.0/go.mod h1:XcP1RLD81eV4BW8UhQlpaR+SDc2givTvyI8a586WjW8= -github.com/uudashr/gocognit v1.2.0 h1:3BU9aMr1xbhPlvJLSydKwdLN3tEUUrzPSSM8S4hDYRA= github.com/uudashr/gocognit v1.2.0/go.mod h1:k/DdKPI6XBZO1q7HgoV2juESI2/Ofj9AcHPZhBBdrTU= -github.com/uudashr/iface v1.4.1 h1:J16Xl1wyNX9ofhpHmQ9h9gk5rnv2A6lX/2+APLTo0zU= github.com/uudashr/iface v1.4.1/go.mod h1:pbeBPlbuU2qkNDn0mmfrxP2X+wjPMIQAy+r1MBXSXtg= -github.com/vmware-labs/yaml-jsonpath v0.3.2 h1:/5QKeCBGdsInyDCyVNLbXyilb61MXGi9NP674f9Hobk= github.com/vmware-labs/yaml-jsonpath v0.3.2/go.mod h1:U6whw1z03QyqgWdgXxvVnQ90zN1BWz5V+51Ewf8k+rQ= -github.com/wk8/go-ordered-map/v2 v2.1.8 h1:5h/BUHu93oj4gIdvHHHGsScSTMijfx5PeYkE/fJgbpc= github.com/wk8/go-ordered-map/v2 v2.1.8/go.mod h1:5nJHM5DyteebpVlHnWMV0rPz6Zp7+xBAnxjb1X5vnTw= -github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM= -github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= -github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo= github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= -github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0= github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= -github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= -github.com/xen0n/gosmopolitan v1.3.0 h1:zAZI1zefvo7gcpbCOrPSHJZJYA9ZgLfJqtKzZ5pHqQM= github.com/xen0n/gosmopolitan v1.3.0/go.mod h1:rckfr5T6o4lBtM1ga7mLGKZmLxswUoH1zxHgNXOsEt4= -github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no= github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM= -github.com/yagipy/maintidx v1.0.0 h1:h5NvIsCz+nRDapQ0exNv4aJ0yXSI0420omVANTv3GJM= github.com/yagipy/maintidx v1.0.0/go.mod h1:0qNf/I/CCZXSMhsRsrEPDZ+DkekpKLXAJfsTACwgXLk= -github.com/yeya24/promlinter v0.3.0 h1:JVDbMp08lVCP7Y6NP3qHroGAO6z2yGKQtS5JsjqtoFs= github.com/yeya24/promlinter v0.3.0/go.mod h1:cDfJQQYv9uYciW60QT0eeHlFodotkYZlL+YcPQN+mW4= -github.com/ykadowak/zerologlint v0.1.5 h1:Gy/fMz1dFQN9JZTPjv1hxEk+sRWm05row04Yoolgdiw= github.com/ykadowak/zerologlint v0.1.5/go.mod h1:KaUskqF3e/v59oPmdq1U1DnKcuHokl2/K1U4pmIELKg= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= @@ -750,38 +458,22 @@ github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9dec github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= -github.com/yuin/goldmark v1.7.7 h1:5m9rrB1sW3JUMToKFQfb+FGt1U7r57IHu5GrYrG2nqU= github.com/yuin/goldmark v1.7.7/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E= -github.com/yuin/goldmark-meta v1.1.0 h1:pWw+JLHGZe8Rk0EGsMVssiNb/AaPMHfSRszZeUeiOUc= github.com/yuin/goldmark-meta v1.1.0/go.mod h1:U4spWENafuA7Zyg+Lj5RqK/MF+ovMYtBvXi1lBb2VP0= -github.com/zclconf/go-cty v1.17.0 h1:seZvECve6XX4tmnvRzWtJNHdscMtYEx5R7bnnVyd/d0= github.com/zclconf/go-cty v1.17.0/go.mod h1:wqFzcImaLTI6A5HfsRwB0nj5n0MRZFwmey8YoFPPs3U= -gitlab.com/bosi/decorder v0.4.2 h1:qbQaV3zgwnBZ4zPMhGLW4KZe7A7NwxEhJx39R3shffo= gitlab.com/bosi/decorder v0.4.2/go.mod h1:muuhHoaJkA9QLcYHq4Mj8FJUwDZ+EirSHRiaTcTf6T8= -go-simpler.org/assert v0.9.0 h1:PfpmcSvL7yAnWyChSjOz6Sp6m9j5lyK8Ok9pEL31YkQ= -go-simpler.org/assert v0.9.0/go.mod h1:74Eqh5eI6vCK6Y5l3PI8ZYFXG4Sa+tkr70OIPJAUr28= -go-simpler.org/musttag v0.14.0 h1:XGySZATqQYSEV3/YTy+iX+aofbZZllJaqwFWs+RTtSo= go-simpler.org/musttag v0.14.0/go.mod h1:uP8EymctQjJ4Z1kUnjX0u2l60WfUdQxCwSNKzE1JEOE= -go-simpler.org/sloglint v0.11.1 h1:xRbPepLT/MHPTCA6TS/wNfZrDzkGvCCqUv4Bdwc3H7s= go-simpler.org/sloglint v0.11.1/go.mod h1:2PowwiCOK8mjiF+0KGifVOT8ZsCNiFzvfyJeJOIt8MQ= -go.abhg.dev/goldmark/frontmatter v0.2.0 h1:P8kPG0YkL12+aYk2yU3xHv4tcXzeVnN+gU0tJ5JnxRw= go.abhg.dev/goldmark/frontmatter v0.2.0/go.mod h1:XqrEkZuM57djk7zrlRUB02x8I5J0px76YjkOzhB4YlU= -go.augendre.info/arangolint v0.4.0 h1:xSCZjRoS93nXazBSg5d0OGCi9APPLNMmmLrC995tR50= go.augendre.info/arangolint v0.4.0/go.mod h1:l+f/b4plABuFISuKnTGD4RioXiCCgghv2xqst/xOvAA= -go.augendre.info/fatcontext v0.9.0 h1:Gt5jGD4Zcj8CDMVzjOJITlSb9cEch54hjRRlN3qDojE= go.augendre.info/fatcontext v0.9.0/go.mod h1:L94brOAT1OOUNue6ph/2HnwxoNlds9aXDF2FcUntbNw= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= -go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= -go.uber.org/multierr v1.10.0 h1:S0h4aNzvfcFsC3dRF1jLoaov7oRaKqRGC/pUEJ2yvPQ= go.uber.org/multierr v1.10.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= -go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= -go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= @@ -793,7 +485,6 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= -golang.org/x/crypto v0.48.0 h1:/VRzVqiRSggnhY7gNRxPauEQ5Drw9haKdM0jqfcCFts= golang.org/x/crypto v0.48.0/go.mod h1:r0kV5h3qnFPlQnBSrULhlsRfryS2pmewsg+XfMgkVos= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -805,11 +496,9 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0 golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= -golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b h1:M2rDM6z3Fhozi9O7NWsxAkg/yqS/lQJ6PmkyIV3YP+o= golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b/go.mod h1:3//PLf8L/X+8b4vuAfHzxeRUl04Adcb341+IGKfnqS8= golang.org/x/exp/typeparams v0.0.0-20220428152302-39d4317da171/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= golang.org/x/exp/typeparams v0.0.0-20230203172020-98cc5a0785f9/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= -golang.org/x/exp/typeparams v0.0.0-20260209203927-2842357ff358 h1:qWFG1Dj7TBjOjOvhEOkmyGPVoquqUKnIU0lEVLp8xyk= golang.org/x/exp/typeparams v0.0.0-20260209203927-2842357ff358/go.mod h1:4Mzdyp/6jzw9auFDJ3OMF5qksa7UvPnzKqTVGcb04ms= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= @@ -838,7 +527,6 @@ golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91 golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.13.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= -golang.org/x/mod v0.33.0 h1:tHFzIWbBifEmbwtGz65eaWyGiGZatSrT9prnU8DbVL8= golang.org/x/mod v0.33.0/go.mod h1:swjeQEj+6r7fODbD2cqrnje9PnziFuw4bmLbBZFrQ5w= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -883,8 +571,6 @@ golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= golang.org/x/net v0.16.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= -golang.org/x/net v0.50.0 h1:ucWh9eiCGyDR3vtzso0WMQinm2Dnt8cFMuQa9K33J60= -golang.org/x/net v0.50.0/go.mod h1:UgoSli3F/pBgdJBHCTc+tp3gmrU4XswgGRgtnwWTfyM= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -906,7 +592,6 @@ golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sync v0.4.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= -golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -965,9 +650,7 @@ golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k= golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= -golang.org/x/telemetry v0.0.0-20260209163413-e7419c687ee4 h1:bTLqdHv7xrGlFbvf5/TXNxy/iUwwdkjhqQTJDjW7aj0= golang.org/x/telemetry v0.0.0-20260209163413-e7419c687ee4/go.mod h1:g5NllXBEermZrmR51cJDQxmJUHUOfRAaNyWBM+R+548= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= @@ -987,7 +670,6 @@ golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= -golang.org/x/text v0.34.0 h1:oL/Qq0Kdaqxa1KbNeMKwQq0reLCCaFtqu2eNuSeNHbk= golang.org/x/text v0.34.0/go.mod h1:homfLqTYRFyVYemLBFl5GgL/DWEiH5wcsQ5gSh1yziA= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -1043,12 +725,7 @@ golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= golang.org/x/tools v0.14.0/go.mod h1:uYBEerGOWcJyEORxN+Ek8+TT266gXkNlHdJBwexUsBg= -golang.org/x/tools v0.42.0 h1:uNgphsn75Tdz5Ji2q36v/nsFSfR/9BRFvqhGBaJGd5k= golang.org/x/tools v0.42.0/go.mod h1:Ma6lCIwGZvHK6XtgbswSoWroEkhugApmsXyrUmBhfr0= -golang.org/x/tools/go/expect v0.1.1-deprecated h1:jpBZDwmgPhXsKZC6WhL20P4b/wmnpsEAGHaNy0n/rJM= -golang.org/x/tools/go/expect v0.1.1-deprecated/go.mod h1:eihoPOH+FgIqa3FpoTwguz/bVUSGBlGQU67vpBeOrBY= -golang.org/x/tools/go/packages/packagestest v0.1.1-deprecated h1:1h2MnaIAIXISqTFKdENegdpAgUXz6NrPEsbIeWaBRvM= -golang.org/x/tools/go/packages/packagestest v0.1.1-deprecated/go.mod h1:RVAQXBGNv1ib0J382/DPCRS/BPnsGebyM1Gj5VSDpG8= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -1128,32 +805,23 @@ google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGj google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.36.8 h1:xHScyCOEuuwZEc6UtSOvPbAT4zRh0xcNRYekJwfqyMc= google.golang.org/protobuf v1.36.8/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= -gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= -gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= -gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= -gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME= -gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20191026110619-0b21df46bc1d/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= @@ -1162,11 +830,8 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -honnef.co/go/tools v0.7.0 h1:w6WUp1VbkqPEgLz4rkBzH/CSU6HkoqNLp6GstyTx3lU= honnef.co/go/tools v0.7.0/go.mod h1:pm29oPxeP3P82ISxZDgIYeOaf9ta6Pi0EWvCFoLG2vc= -mvdan.cc/gofumpt v0.9.2 h1:zsEMWL8SVKGHNztrx6uZrXdp7AX8r421Vvp23sz7ik4= mvdan.cc/gofumpt v0.9.2/go.mod h1:iB7Hn+ai8lPvofHd9ZFGVg2GOr8sBUw1QUWjNbmIL/s= -mvdan.cc/unparam v0.0.0-20251027182757-5beb8c8f8f15 h1:ssMzja7PDPJV8FStj7hq9IKiuiKhgz9ErWw+m68e7DI= mvdan.cc/unparam v0.0.0-20251027182757-5beb8c8f8f15/go.mod h1:4M5MMXl2kW6fivUT6yRGpLLPNfuGtU2Z0cPvFquGDYU= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=