diff --git a/.github/actions/acc_test/README.md b/.github/actions/acc_test/README.md new file mode 100644 index 00000000..c3484cf2 --- /dev/null +++ b/.github/actions/acc_test/README.md @@ -0,0 +1 @@ +# acceptance test action diff --git a/.github/actions/acc_test/action.yaml b/.github/actions/acc_test/action.yaml new file mode 100644 index 00000000..828e1011 --- /dev/null +++ b/.github/actions/acc_test/action.yaml @@ -0,0 +1,114 @@ +name: Acceptance Testing +description: "Acceptance Testing pipeline" + +inputs: + go-version: + description: "go version to install" + default: '1.25' + required: true + + project_id: + description: "STACKIT project ID for tests" + required: true + + region: + description: "STACKIT region for tests" + default: 'eu01' + required: true + + service_account_json: + description: "STACKIT service account JSON file contents" + required: true + + test_file: + description: "testfile to run" + default: '' + +outputs: + random-number: + description: "Random number" + value: ${{ steps.random-number-generator.outputs.random-number }} + +runs: + using: "composite" + steps: + - name: Random Number Generator + id: random-number-generator + run: echo "random-number=$(echo $RANDOM)" >> $GITHUB_OUTPUT + shell: bash + + - name: Install needed tools + shell: bash + run: | + set -e + apt-get -y -qq update + apt-get -y -qq install jq python3 python3-pip python-is-python3 s3cmd git make wget + + - name: Setup JAVA + uses: actions/setup-java@v5 + with: + distribution: 'temurin' # See 'Supported distributions' for available options + java-version: '21' + + - name: Install Go ${{ inputs.go-version }} + uses: actions/setup-go@v6 + with: + go-version: ${{ inputs.go-version }} + check-latest: true + go-version-file: 'go.mod' + + - name: Install go tools + shell: bash + run: | + set -e + go mod download + go install golang.org/x/tools/cmd/goimports@latest + go install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@v2.7.2 + go install github.com/hashicorp/terraform-plugin-docs/cmd/tfplugindocs@v0.24.0 + + - name: Prepare pkg_gen directory + shell: bash + run: | + go run cmd/main.go build -p + + - name: Run acceptance test file + if: ${{ inputs.test_file != '' }} + shell: bash + run: | + echo "Running acceptance tests for the terraform provider" + echo "${STACKIT_SERVICE_ACCOUNT_JSON}" > ~/.service_account.json + cd stackit + TF_ACC=1 \ + TF_ACC_PROJECT_ID=${TF_ACC_PROJECT_ID} \ + TF_ACC_REGION=${TF_ACC_REGION} \ + go test ${{ inputs.test_file }} -count=1 -timeout=30m + env: + STACKIT_SERVICE_ACCOUNT_JSON: ${{ inputs.service_account_json }} + TF_PROJECT_ID: ${{ inputs.project_id }} + TF_ACC_REGION: ${{ inputs.region }} + # TF_ACC_TEST_PROJECT_SERVICE_ACCOUNT_EMAIL: ${{ secrets.TF_ACC_TEST_PROJECT_SERVICE_ACCOUNT_EMAIL }} + # TF_ACC_TEST_PROJECT_SERVICE_ACCOUNT_TOKEN: ${{ secrets.TF_ACC_TEST_PROJECT_SERVICE_ACCOUNT_TOKEN }} + # TF_ACC_TEST_PROJECT_PARENT_CONTAINER_ID: ${{ secrets.TF_ACC_TEST_PROJECT_PARENT_CONTAINER_ID }} + # TF_ACC_TEST_PROJECT_PARENT_UUID: ${{ secrets.TF_ACC_TEST_PROJECT_PARENT_UUID }} + # TF_ACC_TEST_PROJECT_USER_EMAIL: ${{ secrets.TF_ACC_TEST_PROJECT_USER_EMAIL }} + + - name: Run acceptance tests + if: ${{ inputs.test_file == '' }} + shell: bash + run: | + echo "Running acceptance tests for the terraform provider" + echo "${STACKIT_SERVICE_ACCOUNT_JSON}" > ~/.service_account.json + cd stackit + TF_ACC=1 \ + TF_ACC_PROJECT_ID=${TF_ACC_PROJECT_ID} \ + TF_ACC_REGION=${TF_ACC_REGION} \ + go test ./... -count=1 -timeout=30m + env: + STACKIT_SERVICE_ACCOUNT_JSON: ${{ inputs.service_account_json }} + TF_PROJECT_ID: ${{ inputs.project_id }} + TF_ACC_REGION: ${{ inputs.region }} + # TF_ACC_TEST_PROJECT_SERVICE_ACCOUNT_EMAIL: ${{ secrets.TF_ACC_TEST_PROJECT_SERVICE_ACCOUNT_EMAIL }} + # TF_ACC_TEST_PROJECT_SERVICE_ACCOUNT_TOKEN: ${{ secrets.TF_ACC_TEST_PROJECT_SERVICE_ACCOUNT_TOKEN }} + # TF_ACC_TEST_PROJECT_PARENT_CONTAINER_ID: ${{ secrets.TF_ACC_TEST_PROJECT_PARENT_CONTAINER_ID }} + # TF_ACC_TEST_PROJECT_PARENT_UUID: ${{ secrets.TF_ACC_TEST_PROJECT_PARENT_UUID }} + # TF_ACC_TEST_PROJECT_USER_EMAIL: ${{ secrets.TF_ACC_TEST_PROJECT_USER_EMAIL }} diff --git a/.github/actions/build/action.yaml b/.github/actions/build/action.yaml index fe544618..1fa83ee1 100644 --- a/.github/actions/build/action.yaml +++ b/.github/actions/build/action.yaml @@ -1,4 +1,3 @@ - name: Build description: "Build pipeline" inputs: diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index fbc3f339..186d2b42 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -106,7 +106,7 @@ jobs: needs: config steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Build uses: ./.github/actions/build @@ -150,7 +150,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Check GoReleaser uses: goreleaser/goreleaser-action@v6 diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 254c40f2..7d7106ed 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -18,7 +18,7 @@ jobs: goreleaser: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 with: # Allow goreleaser to access older tag information. fetch-depth: 0 diff --git a/.github/workflows/renovate.yaml b/.github/workflows/renovate.yaml index 12454b9f..90adebe6 100644 --- a/.github/workflows/renovate.yaml +++ b/.github/workflows/renovate.yaml @@ -11,7 +11,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Self-hosted Renovate uses: renovatebot/github-action@v41.0.0 with: diff --git a/.github/workflows/tf-acc-test.yaml b/.github/workflows/tf-acc-test.yaml index a8e6a53f..3b4fb061 100644 --- a/.github/workflows/tf-acc-test.yaml +++ b/.github/workflows/tf-acc-test.yaml @@ -7,21 +7,17 @@ on: workflow_dispatch: jobs: - main: + acc_test: name: Acceptance Tests runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v4 - - name: Install project tools and dependencies - run: make project-tools - - name: Run tests - run: | - make test-acceptance-tf TF_ACC_PROJECT_ID=$${{ secrets.TF_ACC_PROJECT_ID }} TF_ACC_ORGANIZATION_ID=$${{ secrets.TF_ACC_ORGANIZATION_ID }} TF_ACC_REGION="eu01" - env: - STACKIT_SERVICE_ACCOUNT_TOKEN: ${{ secrets.TF_ACC_SERVICE_ACCOUNT_TOKEN }} - TF_ACC_TEST_PROJECT_SERVICE_ACCOUNT_EMAIL: ${{ secrets.TF_ACC_TEST_PROJECT_SERVICE_ACCOUNT_EMAIL }} - TF_ACC_TEST_PROJECT_SERVICE_ACCOUNT_TOKEN: ${{ secrets.TF_ACC_TEST_PROJECT_SERVICE_ACCOUNT_TOKEN }} - TF_ACC_TEST_PROJECT_PARENT_CONTAINER_ID: ${{ secrets.TF_ACC_TEST_PROJECT_PARENT_CONTAINER_ID }} - TF_ACC_TEST_PROJECT_PARENT_UUID: ${{ secrets.TF_ACC_TEST_PROJECT_PARENT_UUID }} - TF_ACC_TEST_PROJECT_USER_EMAIL: ${{ secrets.TF_ACC_TEST_PROJECT_USER_EMAIL }} + uses: actions/checkout@v6 + + - name: Run Test + uses: ./.github/actions/acc_test + with: + go-version: ${{ env.GO_VERSION }} + project_id: ${{ vars.TEST_PROJECT_ID }} + region: 'eu01' + service_account_json: ${{ secrets.TF_ACC_SERVICE_ACCOUNT_JSON }} diff --git a/README.md b/README.md index 1da34359..018f615e 100644 --- a/README.md +++ b/README.md @@ -5,9 +5,9 @@
-# STACKIT Terraform Provider +# STACKIT Terraform Provider (PRIVATE PREVIEW) -[![Go Report Card](https://goreportcard.com/badge/github.com/stackitcloud/terraform-provider-stackit)](https://goreportcard.com/report/github.com/stackitcloud/terraform-provider-stackit) [![GitHub Release](https://img.shields.io/github/v/release/stackitcloud/terraform-provider-stackit)](https://registry.terraform.io/providers/stackitcloud/stackit/latest) ![GitHub go.mod Go version](https://img.shields.io/github/go-mod/go-version/stackitcloud/terraform-provider-stackit) [![GitHub License](https://img.shields.io/github/license/stackitcloud/terraform-provider-stackit)](https://www.apache.org/licenses/LICENSE-2.0) +[![GitHub Release](https://img.shields.io/github/v/release/stackitcloud/terraform-provider-stackit)](https://registry.terraform.io/providers/stackitcloud/stackit/latest) ![GitHub go.mod Go version](https://img.shields.io/github/go-mod/go-version/stackitcloud/terraform-provider-stackit) [![GitHub License](https://img.shields.io/github/license/stackitcloud/terraform-provider-stackit)](https://www.apache.org/licenses/LICENSE-2.0) This project is the official [Terraform Provider](https://registry.terraform.io/providers/stackitcloud/stackit/latest/docs) for [STACKIT](https://www.stackit.de/en/), which allows you to manage STACKIT resources through Terraform. diff --git a/cmd/cmd/build/build.go b/cmd/cmd/build/build.go index a6e0acf9..f210b8d2 100644 --- a/cmd/cmd/build/build.go +++ b/cmd/cmd/build/build.go @@ -39,17 +39,15 @@ type version struct { } type Builder struct { - SkipClone bool - SkipCleanup bool + SkipClone bool + SkipCleanup bool + PackagesOnly bool } func (b *Builder) Build() error { slog.Info("Starting Builder") - - slog.Info(" ... Checking needed commands available") - err := checkCommands([]string{"tfplugingen-framework", "tfplugingen-openapi"}) - if err != nil { - return err + if b.PackagesOnly { + slog.Info(" >>> only generating pkg_gen <<<") } root, err := getRoot() @@ -61,13 +59,23 @@ func (b *Builder) Build() error { } slog.Info(" ... using root directory", "dir", *root) - if !b.SkipCleanup { - slog.Info("Cleaning up old generator directory") - err = os.RemoveAll(path.Join(*root, GEN_REPO_NAME)) + if !b.PackagesOnly { + slog.Info(" ... Checking needed commands available") + err := checkCommands([]string{"tfplugingen-framework", "tfplugingen-openapi"}) if err != nil { return err } + } + if !b.SkipCleanup { + slog.Info("Cleaning up old packages directory") + err = os.RemoveAll(path.Join(*root, "pkg_gen")) + if err != nil { + return err + } + } + + if !b.SkipCleanup && !b.PackagesOnly { slog.Info("Cleaning up old packages directory") err = os.RemoveAll(path.Join(*root, "pkg_gen")) if err != nil { @@ -211,24 +219,26 @@ func (b *Builder) Build() error { } } - slog.Info("Generating service boilerplate") - err = generateServiceFiles(*root, path.Join(*root, GEN_REPO_NAME)) - if err != nil { - return err - } + if !b.PackagesOnly { + slog.Info("Generating service boilerplate") + err = generateServiceFiles(*root, path.Join(*root, GEN_REPO_NAME)) + if err != nil { + return err + } - slog.Info("Copying all service files") - err = CopyDirectory( - path.Join(*root, "generated", "internal", "services"), - path.Join(*root, "stackit", "internal", "services"), - ) - if err != nil { - return err - } + slog.Info("Copying all service files") + err = CopyDirectory( + path.Join(*root, "generated", "internal", "services"), + path.Join(*root, "stackit", "internal", "services"), + ) + if err != nil { + return err + } - err = createBoilerplate(*root, path.Join(*root, "stackit", "internal", "services")) - if err != nil { - return err + err = createBoilerplate(*root, path.Join(*root, "stackit", "internal", "services")) + if err != nil { + return err + } } if !b.SkipCleanup { diff --git a/cmd/cmd/buildCmd.go b/cmd/cmd/buildCmd.go index 0a239215..8902132e 100644 --- a/cmd/cmd/buildCmd.go +++ b/cmd/cmd/buildCmd.go @@ -6,8 +6,9 @@ import ( ) var ( - skipCleanup bool - skipClone bool + skipCleanup bool + skipClone bool + packagesOnly bool ) var buildCmd = &cobra.Command{ @@ -16,8 +17,9 @@ var buildCmd = &cobra.Command{ Long: `...`, RunE: func(cmd *cobra.Command, args []string) error { b := build.Builder{ - SkipClone: skipClone, - SkipCleanup: skipCleanup, + SkipClone: skipClone, + SkipCleanup: skipCleanup, + PackagesOnly: packagesOnly, } return b.Build() }, @@ -30,4 +32,5 @@ func NewBuildCmd() *cobra.Command { func init() { // nolint: gochecknoinits buildCmd.Flags().BoolVarP(&skipCleanup, "skip-clean", "c", false, "Skip cleanup steps") buildCmd.Flags().BoolVarP(&skipClone, "skip-clone", "g", false, "Skip cloning from git") + buildCmd.Flags().BoolVarP(&packagesOnly, "packages-only", "p", false, "Only generate packages") } diff --git a/docs/resources/postgresflexalpha_instance.md b/docs/resources/postgresflexalpha_instance.md index 9ec697ba..fb735ecc 100644 --- a/docs/resources/postgresflexalpha_instance.md +++ b/docs/resources/postgresflexalpha_instance.md @@ -13,21 +13,29 @@ description: |- ## Example Usage ```terraform -resource "stackitprivatepreview_postgresflexalpha_instance" "example" { +resource "stackitprivatepreview_postgresflexalpha_instance" "msh-instance-only" { project_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" name = "example-instance" acl = ["XXX.XXX.XXX.X/XX", "XX.XXX.XX.X/XX"] - backup_schedule = "00 00 * * *" - flavor = { - cpu = 2 - ram = 4 - } - replicas = 3 + backup_schedule = "0 0 * * *" + retention_days = 30 + flavor_id = "flavor.id" + replicas = 1 storage = { - class = "class" - size = 5 + performance_class = "premium-perf2-stackit" + size = 10 } - version = 14 + encryption = { + kek_key_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" + kek_key_ring_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" + kek_key_version = 1 + service_account = "service@account.email" + } + network = { + acl = ["XXX.XXX.XXX.X/XX", "XX.XXX.XX.X/XX"] + access_scope = "PUBLIC" + } + version = 17 } # Only use the import statement, if you want to import an existing postgresflex instance @@ -35,6 +43,15 @@ import { to = stackitprivatepreview_postgresflexalpha_instance.import-example id = "${var.project_id},${var.region},${var.postgres_instance_id}" } + +import { + to = stackitprivatepreview_postgresflexalpha_instance.import-example + identity = { + project_id = var.project_id + region = var.region + instance_id = var.postgres_instance_id + } +} ``` diff --git a/examples/resources/stackitprivatepreview_postgresflexalpha_instance/resource.tf b/examples/resources/stackitprivatepreview_postgresflexalpha_instance/resource.tf index 99faf2e7..1f98284a 100644 --- a/examples/resources/stackitprivatepreview_postgresflexalpha_instance/resource.tf +++ b/examples/resources/stackitprivatepreview_postgresflexalpha_instance/resource.tf @@ -1,22 +1,39 @@ -resource "stackitprivatepreview_postgresflexalpha_instance" "example" { +resource "stackitprivatepreview_postgresflexalpha_instance" "msh-instance-only" { project_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" name = "example-instance" acl = ["XXX.XXX.XXX.X/XX", "XX.XXX.XX.X/XX"] - backup_schedule = "00 00 * * *" - flavor = { - cpu = 2 - ram = 4 - } - replicas = 3 + backup_schedule = "0 0 * * *" + retention_days = 30 + flavor_id = "flavor.id" + replicas = 1 storage = { - class = "class" - size = 5 + performance_class = "premium-perf2-stackit" + size = 10 } - version = 14 + encryption = { + kek_key_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" + kek_key_ring_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" + kek_key_version = 1 + service_account = "service@account.email" + } + network = { + acl = ["XXX.XXX.XXX.X/XX", "XX.XXX.XX.X/XX"] + access_scope = "PUBLIC" + } + version = 17 } # Only use the import statement, if you want to import an existing postgresflex instance import { to = stackitprivatepreview_postgresflexalpha_instance.import-example id = "${var.project_id},${var.region},${var.postgres_instance_id}" -} \ No newline at end of file +} + +import { + to = stackitprivatepreview_postgresflexalpha_instance.import-example + identity = { + project_id = var.project_id + region = var.region + instance_id = var.postgres_instance_id + } +} diff --git a/go.mod b/go.mod index 10aca46d..fc21ec9e 100644 --- a/go.mod +++ b/go.mod @@ -13,6 +13,7 @@ require ( github.com/hashicorp/terraform-plugin-testing v1.14.0 github.com/iancoleman/strcase v0.3.0 github.com/ivanpirog/coloredcobra v1.0.1 + github.com/joho/godotenv v1.5.1 github.com/ldez/go-git-cmd-wrapper/v2 v2.9.1 github.com/spf13/cobra v1.10.2 github.com/stackitcloud/stackit-sdk-go/core v0.21.0 @@ -29,22 +30,13 @@ require ( require ( dario.cat/mergo v1.0.1 // indirect - github.com/BurntSushi/toml v1.2.1 // indirect - github.com/Kunde21/markdownfmt/v3 v3.1.0 // indirect - github.com/Masterminds/goutils v1.1.1 // indirect - github.com/Masterminds/semver/v3 v3.2.0 // indirect - github.com/Masterminds/sprig/v3 v3.2.3 // indirect github.com/ProtonMail/go-crypto v1.3.0 // indirect github.com/agext/levenshtein v1.2.3 // indirect github.com/apparentlymart/go-textseg/v15 v15.0.0 // indirect - github.com/armon/go-radix v1.0.0 // indirect - github.com/bgentry/speakeasy v0.1.0 // indirect - github.com/bmatcuk/doublestar/v4 v4.9.1 // indirect github.com/cloudflare/circl v1.6.2 // indirect github.com/fatih/color v1.18.0 // indirect github.com/golang-jwt/jwt/v5 v5.3.0 // indirect github.com/golang/protobuf v1.5.4 // indirect - github.com/hashicorp/cli v1.1.7 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-checkpoint v0.5.0 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect @@ -59,38 +51,27 @@ require ( github.com/hashicorp/logutils v1.0.0 // indirect github.com/hashicorp/terraform-exec v0.24.0 // indirect github.com/hashicorp/terraform-json v0.27.2 // indirect - github.com/hashicorp/terraform-plugin-docs v0.24.0 // indirect github.com/hashicorp/terraform-plugin-sdk/v2 v2.38.1 // indirect github.com/hashicorp/terraform-registry-address v0.4.0 // indirect github.com/hashicorp/terraform-svchost v0.2.0 // indirect github.com/hashicorp/yamux v0.1.2 // indirect - github.com/huandu/xstrings v1.3.3 // indirect - github.com/imdario/mergo v0.3.15 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/kr/text v0.2.0 // indirect github.com/mattn/go-colorable v0.1.14 // indirect github.com/mattn/go-isatty v0.0.20 // indirect - github.com/mattn/go-runewidth v0.0.9 // indirect github.com/mitchellh/copystructure v1.2.0 // indirect github.com/mitchellh/go-testing-interface v1.14.1 // indirect github.com/mitchellh/go-wordwrap v1.0.1 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/mitchellh/reflectwalk v1.0.2 // indirect github.com/oklog/run v1.2.0 // indirect - github.com/posener/complete v1.2.3 // indirect - github.com/shopspring/decimal v1.3.1 // indirect - github.com/spf13/cast v1.5.0 // indirect github.com/spf13/pflag v1.0.10 // indirect github.com/stretchr/testify v1.11.1 // indirect github.com/vmihailenco/msgpack v4.0.4+incompatible // indirect github.com/vmihailenco/msgpack/v5 v5.4.1 // indirect github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect - github.com/yuin/goldmark v1.7.7 // indirect - github.com/yuin/goldmark-meta v1.1.0 // indirect github.com/zclconf/go-cty v1.17.0 // indirect - go.abhg.dev/goldmark/frontmatter v0.2.0 // indirect golang.org/x/crypto v0.47.0 // indirect - golang.org/x/exp v0.0.0-20230626212559-97b1e661b5df // indirect golang.org/x/mod v0.32.0 // indirect golang.org/x/net v0.49.0 // indirect golang.org/x/sync v0.19.0 // indirect @@ -101,7 +82,6 @@ require ( google.golang.org/genproto/googleapis/rpc v0.0.0-20260120221211-b8f7ae30c516 // indirect google.golang.org/grpc v1.78.0 // indirect google.golang.org/protobuf v1.36.11 // indirect - gopkg.in/yaml.v2 v2.4.0 // indirect ) tool golang.org/x/tools/cmd/goimports diff --git a/go.sum b/go.sum index 59906446..43e5e03e 100644 --- a/go.sum +++ b/go.sum @@ -1,15 +1,5 @@ dario.cat/mergo v1.0.1 h1:Ra4+bf83h2ztPIQYNP99R6m+Y7KfnARDfID+a+vLl4s= dario.cat/mergo v1.0.1/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= -github.com/BurntSushi/toml v1.2.1 h1:9F2/+DoOYIOksmaJFPw1tGFy1eDnIJXg+UHjuD8lTak= -github.com/BurntSushi/toml v1.2.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= -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 h1:3MEsd0SM6jqZojhjLWWeBY+Kcjy9i6MQAeY7YgDP83g= -github.com/Masterminds/semver/v3 v3.2.0/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ= -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/MatusOllah/slogcolor v1.7.0 h1:Nrd7yBPv2EBEEBEwl7WEPRmMd1ozZzw2jm8SLMYDbKs= github.com/MatusOllah/slogcolor v1.7.0/go.mod h1:5y1H50XuQIBvuYTJlmokWi+4FuPiJN5L7Z0jM4K4bYA= github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= @@ -21,12 +11,6 @@ github.com/agext/levenshtein v1.2.3/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki github.com/apparentlymart/go-textseg/v12 v12.0.0/go.mod h1:S/4uRK2UtaQttw1GenVJEynmyUenKwP++x/+DdGV/Ec= 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/bgentry/speakeasy v0.1.0 h1:ByYyxL9InA1OWqxJqqp2A5pYHUrCiAL6K3J+LKSsQkY= -github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= -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/bufbuild/protocompile v0.14.1 h1:iA73zAf/fyljNjQKwYzUHD6AD4R8KMasmwa/FBatYVw= github.com/bufbuild/protocompile v0.14.1/go.mod h1:ppVdAIhbr2H8asPk6k4pY7t9zB1OU5DoEw9xY/FUi1c= github.com/cloudflare/circl v1.6.2 h1:hL7VBpHHKzrV5WTfHCaBsgx/HGbBYlgrwvNXEVDYYsQ= @@ -70,11 +54,8 @@ github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 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/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/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= @@ -87,7 +68,6 @@ github.com/hashicorp/go-cty v1.5.0 h1:EkQ/v+dDNUqnuVpmS5fPqyY71NXVgT5gf32+57xY8g github.com/hashicorp/go-cty v1.5.0/go.mod h1:lFUCG5kd8exDobgSfyj4ONE/dc822kiYMguVKdHGMLM= 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-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-plugin v1.7.0 h1:YghfQH/0QmPNc/AZMTFE3ac8fipZyZECHdDPshfk+mA= @@ -109,8 +89,6 @@ github.com/hashicorp/terraform-exec v0.24.0 h1:mL0xlk9H5g2bn0pPF6JQZk5YlByqSqrO5 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-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/hashicorp/terraform-plugin-framework v1.17.0 h1:JdX50CFrYcYFY31gkmitAEAzLKoBgsK+iaJjDC8OexY= github.com/hashicorp/terraform-plugin-framework v1.17.0/go.mod h1:4OUXKdHNosX+ys6rLgVlgklfxN3WHR5VHSOABeS/BM0= github.com/hashicorp/terraform-plugin-framework-validators v0.19.0 h1:Zz3iGgzxe/1XBkooZCewS0nJAaCFPFPHdNJd8FgE4Ow= @@ -129,13 +107,8 @@ github.com/hashicorp/terraform-svchost v0.2.0 h1:wVc2vMiodOHvNZcQw/3y9af1XSomgjG github.com/hashicorp/terraform-svchost v0.2.0/go.mod h1:/98rrS2yZsbppi4VGVCjwYmh8dqsKzISqK7Hli+0rcQ= github.com/hashicorp/yamux v0.1.2 h1:XtB8kyFOyHXYVFnwT5C3+Bdo8gArse7j2AQ0DA0Uey8= github.com/hashicorp/yamux v0.1.2/go.mod h1:C+zze2n6e/7wshOZep2A70/aQU6QBRWJO/G6FT1wIns= -github.com/huandu/xstrings v1.3.3 h1:/Gcsuc1x8JVbJ9/rlye4xZnVAbEkGauT8lbebqcQws4= -github.com/huandu/xstrings v1.3.3/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= github.com/iancoleman/strcase v0.3.0 h1:nTXanmYxhfFAMjZL34Ov6gkzEsSJZ5DbhxWjvSASxEI= github.com/iancoleman/strcase v0.3.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho= -github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= -github.com/imdario/mergo v0.3.15 h1:M8XP7IuFNsqUx6VPK2P9OSmsYsI/YFaGil0uD21V3dM= -github.com/imdario/mergo v0.3.15/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= @@ -145,6 +118,8 @@ github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOl github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= github.com/jhump/protoreflect v1.17.0 h1:qOEr613fac2lOuTgWN4tPAtLL7fUSbuJL5X5XumQh94= github.com/jhump/protoreflect v1.17.0/go.mod h1:h9+vUUL38jiBzck8ck+6G/aeMX8Z4QUY/NiJPwPNi+8= +github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= +github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= 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/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= @@ -164,9 +139,6 @@ github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Ky github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= 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.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0= -github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= -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-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU= @@ -175,7 +147,6 @@ github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQ github.com/mitchellh/go-wordwrap v1.0.1/go.mod h1:R62XHJLzvMFRBbcrT7m7WgmE1eOyTSsCt+hzestvNj0= 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/oklog/run v1.2.0 h1:O8x3yXwah4A73hJdlrwo/2X6J62gE5qTMusH0dvz60E= @@ -185,21 +156,13 @@ github.com/pjbgf/sha1cd v0.3.2/go.mod h1:zQWigSxVmsHEZow5qaLtPYxpcKMMQpa09ixqBxu github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/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/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/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/skeema/knownhosts v1.3.1 h1:X2osQ+RAjK76shCbvhHHHVl3ZlgDm8apHEHFqRjnBY8= github.com/skeema/knownhosts v1.3.1/go.mod h1:r7KTdC8l4uxWRyK2TpQZ/1o5HaSzh06ePQNxPwTcfiY= -github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w= -github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU= github.com/spf13/cobra v1.4.0/go.mod h1:Wo4iy3BUC+X2Fybo0PDqwJIv3dNRiZLHQymsfxlB84g= github.com/spf13/cobra v1.10.2 h1:DMTTonx5m65Ic0GOoRY2c16WCbHxOOw6xxezuLaBpcU= github.com/spf13/cobra v1.10.2/go.mod h1:7C1pvHqHw5A4vrJfjNwvOdzYu0Gml16OCs2GRiTUUS4= @@ -214,9 +177,6 @@ github.com/stackitcloud/stackit-sdk-go/services/iaasalpha v0.1.23-alpha/go.mod h github.com/stackitcloud/stackit-sdk-go/services/sqlserverflex v1.4.1 h1:6MJdy1xmdE+uOo/F8mR5HSldjPSHpdhwuqS3u9m2EWQ= github.com/stackitcloud/stackit-sdk-go/services/sqlserverflex v1.4.1/go.mod h1:XLr3ZfrT1g8ZZMm7A6RXOPBuhBkikdUN2o/+/Y+Hu+g= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= -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.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= @@ -232,16 +192,10 @@ github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV 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/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= github.com/zclconf/go-cty-debug v0.0.0-20240509010212-0d6042c53940 h1:4r45xpDWB6ZMSMNJFMOjqrGHynW3DIBuR2H9j0ug+Mo= github.com/zclconf/go-cty-debug v0.0.0-20240509010212-0d6042c53940/go.mod h1:CmBdvvj3nqzfzJ6nTCIwDTPZ56aVGvDrmztiO5g3qrM= -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.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8= @@ -257,11 +211,8 @@ go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42s go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= golang.org/x/crypto v0.47.0 h1:V6e3FRj+n4dbpw86FJ8Fv7XVOql7TEwpHapKoMJ/GO8= golang.org/x/crypto v0.47.0/go.mod h1:ff3Y9VzzKbwSSEzWqJsJVBnWmRwRSHt/6Op5n9bQc4A= -golang.org/x/exp v0.0.0-20230626212559-97b1e661b5df h1:UA2aFVmmsIlefxMk29Dp2juaUSth8Pyn3Tq5Y5mJGME= -golang.org/x/exp v0.0.0-20230626212559-97b1e661b5df/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.32.0 h1:9F4d3PHLljb6x//jOyokMv3eX+YDeepZSEo3mFJy93c= golang.org/x/mod v0.32.0/go.mod h1:SgipZ/3h2Ci89DlEtEXWUk/HteuRin+HHhN+WbNhguU= @@ -269,7 +220,6 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= golang.org/x/net v0.49.0 h1:eeHFmOGUTtaaPSGNmjBKpbng9MulQsJURQUAfUwY++o= golang.org/x/net v0.49.0/go.mod h1:/ysNB2EvaqvesRkuLAyjI1ycPZlQHM3q01F02UY/MV8= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -287,7 +237,6 @@ golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.40.0 h1:DBZZqJ2Rkml6QMQsZywtnjnnGvHza6BTfYFWY9kjEWQ= golang.org/x/sys v0.40.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= @@ -295,14 +244,12 @@ golang.org/x/telemetry v0.0.0-20260116145544-c6413dc483f5 h1:i0p03B68+xC1kD2QUO8 golang.org/x/telemetry v0.0.0-20260116145544-c6413dc483f5/go.mod h1:b7fPSJ0pKZ3ccUh8gnTONJxhn3c/PS6tyzQvyqw4iA8= 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= -golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= golang.org/x/term v0.39.0 h1:RclSuaJf32jOqZz74CkPA9qFuVTX7vhLlpfj/IGWlqY= golang.org/x/term v0.39.0/go.mod h1:yxzUCTP/U+FzoxfdKmLaA0RV1WgE0VY7hXBwKtY/4ww= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= -golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.33.0 h1:B3njUFyqtHDUI5jMn1YIr5B0IE2U0qck04r6d4KPAxE= golang.org/x/text v0.33.0/go.mod h1:LuMebE6+rBincTi9+xWTY8TztLzKHc/9C1uBCG27+q8= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -331,9 +278,6 @@ gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntN gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= 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.2/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.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/stackit/internal/services/postgresflexalpha/instance/resource_test.go b/stackit/internal/services/postgresflexalpha/instance/resource_test.go index 46d935a5..c84c1a5d 100644 --- a/stackit/internal/services/postgresflexalpha/instance/resource_test.go +++ b/stackit/internal/services/postgresflexalpha/instance/resource_test.go @@ -1,12 +1,233 @@ package postgresflexalpha import ( - "reflect" + "encoding/json" + "fmt" + "net/http" + "net/http/httptest" + "os" "testing" - "github.com/hashicorp/terraform-plugin-framework/resource" + "github.com/hashicorp/terraform-plugin-testing/helper/acctest" + "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/hashicorp/terraform-plugin-testing/terraform" + "tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit/internal/testutil" ) +var ( + validFlavor = "2.4" + kekKeyRingId = "" + kekKeyVersion = "" + kekKeySA = "" +) + +func testAccPreCheck(t *testing.T) { + // TODO: if needed ... +} + +//func TestAccResourceExample_parallel(t *testing.T) { +// t.Parallel() +// +// exData := resData{ +// Region: "eu01", +// ServiceAccountFilePath: sa_file, +// ProjectID: project_id, +// Name: acctest.RandomWithPrefix("tf-acc"), +// } +// +// resource.Test(t, resource.TestCase{ +// ProtoV6ProviderFactories: testutil.TestAccProtoV6ProviderFactories, +// Steps: []resource.TestStep{ +// { +// Config: testAccResourceEncryptionExampleConfig(exData), +// Check: resource.TestCheckResourceAttrSet("example_resource.test", "id"), +// }, +// }, +// }) +//} + +type resData struct { + ServiceAccountFilePath string + ProjectID string + Region string + Name string + Flavor string + BackupSchedule string + RetentionDays uint32 +} + +func getExample() resData { + return resData{ + Region: testutil.Region, + ServiceAccountFilePath: testutil.ServiceAccountFile, + ProjectID: testutil.ProjectId, + Name: acctest.RandomWithPrefix("tf-acc"), + Flavor: "2.4", + BackupSchedule: "0 0 * * *", + RetentionDays: 33, + } +} + +func TestAccResourceExample_basic(t *testing.T) { + exData := getExample() + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ProtoV6ProviderFactories: testutil.TestAccProtoV6ProviderFactories, + Steps: []resource.TestStep{ + { + Config: testAccResourceNoEncryptionExampleConfig(exData), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("example_resource.test", "name", exData.Name), + resource.TestCheckResourceAttrSet("example_resource.test", "id"), + ), + }, + //// Create and verify + //{ + // Config: testAccResourceNoEncryptionExampleConfig(exData), + // Check: resource.ComposeTestCheckFunc( + // resource.TestCheckResourceAttr("example_resource.test", "name", exData.Name), + // ), + //}, + //// Update and verify + //{ + // Config: testAccResourceNoEncryptionExampleConfig(exData), + // Check: resource.ComposeTestCheckFunc( + // resource.TestCheckResourceAttr("example_resource.test", "name", exData.Name), + // ), + //}, + // Import test + { + ResourceName: "example_resource.test", + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func testAccResourceNoEncryptionExampleConfig(data resData) string { + return fmt.Sprintf(` + +%[1]s + +resource "stackitprivatepreview_postgresflexalpha_instance" "test" { + project_id = %[2]q + name = %[3]q + backup_schedule = %[4]q + retention_days = %[5]d + flavor_id = %[6]q + replicas = 1 + storage = { + performance_class = "premium-perf2-stackit" + size = 10 + } + network = { + acl = ["0.0.0.0/0"] + access_scope = "PUBLIC" + } + version = 17 +} + +`, + testutil.PostgresFlexProviderConfig(data.ServiceAccountFilePath), + data.ProjectID, + data.Name, + data.BackupSchedule, + data.RetentionDays, + data.Flavor, + data.Name, + ) +} + +func testAccResourceEncryptionExampleConfig(data resData) string { + return fmt.Sprintf(` + +%[1]s + +resource "stackitprivatepreview_postgresflexalpha_instance" "test" { + project_id = %[2]q + name = %[3]q + backup_schedule = "0 0 * * *" + retention_days = 45 + flavor_id = "2.1" + replicas = 1 + storage = { + performance_class = "premium-perf2-stackit" + size = 10 + } + encryption = { + kek_key_id = "key01" + kek_key_ring_id = "key_ring_01" + kek_key_version = 1 + service_account = "service@account.email" + } + network = { + acl = ["0.0.0.0/0"] + access_scope = "PUBLIC" + } + version = 14 +} + +`, + testutil.PostgresFlexProviderConfig(data.ServiceAccountFilePath), + data.ProjectID, + data.Name, + ) +} + +func testCheckResourceExists(resourceName string) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[resourceName] + if !ok { + return fmt.Errorf("resource not found: %s", resourceName) + } + + if rs.Primary.ID == "" { + return fmt.Errorf("resource ID not set") + } + + // Verify resource exists in the API + //client := testAccProvider.Meta().(*APIClient) + //_, err := client.GetResource(rs.Primary.ID) + //if err != nil { + // return fmt.Errorf("error fetching resource: %w", err) + //} + + return nil + } +} + +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) + json.NewEncoder(w).Encode(map[string]string{ + "id": "mock-id-123", + "name": "test-resource", + }) + case http.MethodGet: + w.WriteHeader(http.StatusOK) + json.NewEncoder(w).Encode([]map[string]string{}) + } + }) + + return httptest.NewServer(mux) +} + +func TestUnitResourceCreate(t *testing.T) { + server := setupMockServer() + defer server.Close() + + // Configure provider to use mock server URL + os.Setenv("API_ENDPOINT", server.URL) + + // Run unit tests against mock +} + // type postgresFlexClientMocked struct { // returnError bool // getFlavorsResp *postgresflex.GetFlavorsResponse @@ -20,21 +241,40 @@ import ( // return c.getFlavorsResp, nil // } -func TestNewInstanceResource(t *testing.T) { - 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) - } - }) - } -} +//func TestNewInstanceResource(t *testing.T) { +// exData := resData{ +// Region: "eu01", +// ServiceAccountFilePath: sa_file, +// ProjectID: project_id, +// Name: "testRes", +// } +// resource.Test(t, resource.TestCase{ +// ProtoV6ProviderFactories: testutil.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) +// // } +// // }) +// //} +//} diff --git a/stackit/internal/services/postgresflexalpha/postgresflex_acc_test.go b/stackit/internal/services/postgresflexalpha/postgresflex_acc_test.go index a2920107..2a8a12b5 100644 --- a/stackit/internal/services/postgresflexalpha/postgresflex_acc_test.go +++ b/stackit/internal/services/postgresflexalpha/postgresflex_acc_test.go @@ -6,12 +6,15 @@ import ( "context" _ "embed" "fmt" + "log/slog" + "os" "strings" "testing" "github.com/hashicorp/terraform-plugin-testing/helper/acctest" "github.com/hashicorp/terraform-plugin-testing/helper/resource" "github.com/hashicorp/terraform-plugin-testing/terraform" + "github.com/joho/godotenv" "github.com/stackitcloud/stackit-sdk-go/core/utils" "github.com/stackitcloud/stackit-sdk-go/core/config" @@ -26,13 +29,31 @@ var ( resourceSecurityGroupMinConfig string //nolint:unused // needs implementation ) +func setup() { + err := godotenv.Load() + if err != nil { + slog.Info("could not find .env file - not loading .env") + return + } + slog.Info("loaded .env file") +} + +func TestMain(m *testing.M) { + setup() + code := m.Run() + // shutdown() + os.Exit(code) +} + // Instance resource data var instanceResource = map[string]string{ "project_id": testutil.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", @@ -41,75 +62,96 @@ var instanceResource = map[string]string{ "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": instanceResource["project_id"], + "project_id": testutil.ProjectId, } // Database resource data var databaseResource = map[string]string{ - "name": fmt.Sprintf("tfaccdb%s", acctest.RandStringFromCharSet(4, acctest.CharSetAlphaNum)), + "name": fmt.Sprintf("tfaccdb%s", acctest.RandStringFromCharSet(4, acctest.CharSetAlphaNum)), + "project_id": testutil.ProjectId, } -func configResources(backupSchedule string, region *string) string { - var regionConfig string - if region != nil { - regionConfig = fmt.Sprintf(`region = %q`, *region) - } +func configResources(backupSchedule string, _ *string) string { return fmt.Sprintf( ` %s - resource "stackit_postgresflex_instance" "instance" { - project_id = "%s" - name = "%s" - acl = ["%s"] - backup_schedule = "%s" - flavor = { - cpu = %s - ram = %s - } - replicas = %s - storage = { - class = "%s" - size = %s - } - version = "%s" - %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 "stackit_postgresflex_user" "user" { - project_id = stackit_postgresflex_instance.instance.project_id - instance_id = stackit_postgresflex_instance.instance.instance_id + resource "stackitprivatepreview_postgresflexalpha_user" "user" { + project_id = "%s" + instance_id = stackitprivatepreview_postgresflexalpha_instance.instance.instance_id username = "%s" roles = ["%s"] } - resource "stackit_postgresflex_database" "database" { - project_id = stackit_postgresflex_instance.instance.project_id - instance_id = stackit_postgresflex_instance.instance.instance_id + resource "stackitprivatepreview_postgresflexalpha_database" "database" { + project_id = "%s" + instance_id = stackitprivatepreview_postgresflexalpha_instance.instance.instance_id name = "%s" - owner = stackit_postgresflex_user.user.username + owner = stackitprivatepreview_postgresflexalpha_user.user.username } `, - testutil.PostgresFlexProviderConfig(), + testutil.PostgresFlexProviderConfig( + utils.GetEnvOrDefault("TF_ACC_TEST_PROJECT_SERVICE_ACCOUNT_FILE", "~/service-account.json"), + ), instanceResource["project_id"], + instanceResource["region"], instanceResource["name"], - instanceResource["acl"], backupSchedule, - instanceResource["flavor_cpu"], - instanceResource["flavor_ram"], + 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"], - regionConfig, + + userResource["project_id"], userResource["username"], userResource["role"], + + databaseResource["project_id"], databaseResource["name"], ) } @@ -126,107 +168,107 @@ func TestAccPostgresFlexFlexResource(t *testing.T) { Check: resource.ComposeAggregateTestCheckFunc( // Instance resource.TestCheckResourceAttr( - "stackit_postgresflex_instance.instance", + "stackitprivatepreview_postgresflexalpha_instance.instance", "project_id", instanceResource["project_id"], ), resource.TestCheckResourceAttrSet( - "stackit_postgresflex_instance.instance", + "stackitprivatepreview_postgresflexalpha_instance.instance", "instance_id", ), resource.TestCheckResourceAttr( - "stackit_postgresflex_instance.instance", + "stackitprivatepreview_postgresflexalpha_instance.instance", "name", instanceResource["name"], ), resource.TestCheckResourceAttr( - "stackit_postgresflex_instance.instance", + "stackitprivatepreview_postgresflexalpha_instance.instance", "acl.#", "1", ), resource.TestCheckResourceAttr( - "stackit_postgresflex_instance.instance", + "stackitprivatepreview_postgresflexalpha_instance.instance", "acl.0", instanceResource["acl"], ), resource.TestCheckResourceAttrSet( - "stackit_postgresflex_instance.instance", + "stackitprivatepreview_postgresflexalpha_instance.instance", "flavor.id", ), resource.TestCheckResourceAttrSet( - "stackit_postgresflex_instance.instance", + "stackitprivatepreview_postgresflexalpha_instance.instance", "flavor.description", ), resource.TestCheckResourceAttr( - "stackit_postgresflex_instance.instance", + "stackitprivatepreview_postgresflexalpha_instance.instance", "backup_schedule", instanceResource["backup_schedule"], ), resource.TestCheckResourceAttr( - "stackit_postgresflex_instance.instance", + "stackitprivatepreview_postgresflexalpha_instance.instance", "flavor.cpu", instanceResource["flavor_cpu"], ), resource.TestCheckResourceAttr( - "stackit_postgresflex_instance.instance", + "stackitprivatepreview_postgresflexalpha_instance.instance", "flavor.ram", instanceResource["flavor_ram"], ), resource.TestCheckResourceAttr( - "stackit_postgresflex_instance.instance", + "stackitprivatepreview_postgresflexalpha_instance.instance", "replicas", instanceResource["replicas"], ), resource.TestCheckResourceAttr( - "stackit_postgresflex_instance.instance", + "stackitprivatepreview_postgresflexalpha_instance.instance", "storage.class", instanceResource["storage_class"], ), resource.TestCheckResourceAttr( - "stackit_postgresflex_instance.instance", + "stackitprivatepreview_postgresflexalpha_instance.instance", "storage.size", instanceResource["storage_size"], ), resource.TestCheckResourceAttr( - "stackit_postgresflex_instance.instance", + "stackitprivatepreview_postgresflexalpha_instance.instance", "version", instanceResource["version"], ), resource.TestCheckResourceAttr( - "stackit_postgresflex_instance.instance", + "stackitprivatepreview_postgresflexalpha_instance.instance", "region", testutil.Region, ), // User resource.TestCheckResourceAttrPair( - "stackit_postgresflex_user.user", "project_id", - "stackit_postgresflex_instance.instance", "project_id", + "stackitprivatepreview_postgresflexalpha_user.user", "project_id", + "stackitprivatepreview_postgresflexalpha_instance.instance", "project_id", ), resource.TestCheckResourceAttrPair( - "stackit_postgresflex_user.user", "instance_id", - "stackit_postgresflex_instance.instance", "instance_id", + "stackitprivatepreview_postgresflexalpha_user.user", "instance_id", + "stackitprivatepreview_postgresflexalpha_instance.instance", "instance_id", ), - resource.TestCheckResourceAttrSet("stackit_postgresflex_user.user", "user_id"), - resource.TestCheckResourceAttrSet("stackit_postgresflex_user.user", "password"), + resource.TestCheckResourceAttrSet("stackitprivatepreview_postgresflexalpha_user.user", "user_id"), + resource.TestCheckResourceAttrSet("stackitprivatepreview_postgresflexalpha_user.user", "password"), // Database resource.TestCheckResourceAttrPair( - "stackit_postgresflex_database.database", "project_id", - "stackit_postgresflex_instance.instance", "project_id", + "stackitprivatepreview_postgresflexalpha_database.database", "project_id", + "stackitprivatepreview_postgresflexalpha_instance.instance", "project_id", ), resource.TestCheckResourceAttrPair( - "stackit_postgresflex_database.database", "instance_id", - "stackit_postgresflex_instance.instance", "instance_id", + "stackitprivatepreview_postgresflexalpha_database.database", "instance_id", + "stackitprivatepreview_postgresflexalpha_instance.instance", "instance_id", ), resource.TestCheckResourceAttr( - "stackit_postgresflex_database.database", + "stackitprivatepreview_postgresflexalpha_database.database", "name", databaseResource["name"], ), resource.TestCheckResourceAttrPair( - "stackit_postgresflex_database.database", "owner", - "stackit_postgresflex_user.user", "username", + "stackitprivatepreview_postgresflexalpha_database.database", "owner", + "stackitprivatepreview_postgresflexalpha_user.user", "username", ), ), }, @@ -236,21 +278,21 @@ func TestAccPostgresFlexFlexResource(t *testing.T) { ` %s - data "stackit_postgresflex_instance" "instance" { - project_id = stackit_postgresflex_instance.instance.project_id - instance_id = stackit_postgresflex_instance.instance.instance_id + data "stackitprivatepreview_postgresflexalpha_instance" "instance" { + project_id = stackitprivatepreview_postgresflexalpha_instance.instance.project_id + instance_id = stackitprivatepreview_postgresflexalpha_instance.instance.instance_id } - data "stackit_postgresflex_user" "user" { - project_id = stackit_postgresflex_instance.instance.project_id - instance_id = stackit_postgresflex_instance.instance.instance_id - user_id = stackit_postgresflex_user.user.user_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 "stackit_postgresflex_database" "database" { - project_id = stackit_postgresflex_instance.instance.project_id - instance_id = stackit_postgresflex_instance.instance.instance_id - database_id = stackit_postgresflex_database.database.database_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), @@ -258,135 +300,135 @@ func TestAccPostgresFlexFlexResource(t *testing.T) { Check: resource.ComposeAggregateTestCheckFunc( // Instance data resource.TestCheckResourceAttr( - "data.stackit_postgresflex_instance.instance", + "data.stackitprivatepreview_postgresflexalpha_instance.instance", "project_id", instanceResource["project_id"], ), resource.TestCheckResourceAttr( - "data.stackit_postgresflex_instance.instance", + "data.stackitprivatepreview_postgresflexalpha_instance.instance", "name", instanceResource["name"], ), resource.TestCheckResourceAttrPair( - "data.stackit_postgresflex_instance.instance", "project_id", - "stackit_postgresflex_instance.instance", "project_id", + "data.stackitprivatepreview_postgresflexalpha_instance.instance", "project_id", + "stackitprivatepreview_postgresflexalpha_instance.instance", "project_id", ), resource.TestCheckResourceAttrPair( - "data.stackit_postgresflex_instance.instance", "instance_id", - "stackit_postgresflex_instance.instance", "instance_id", + "data.stackitprivatepreview_postgresflexalpha_instance.instance", "instance_id", + "stackitprivatepreview_postgresflexalpha_instance.instance", "instance_id", ), resource.TestCheckResourceAttrPair( - "data.stackit_postgresflex_user.user", "instance_id", - "stackit_postgresflex_user.user", "instance_id", + "data.stackitprivatepreview_postgresflexalpha_user.user", "instance_id", + "stackitprivatepreview_postgresflexalpha_user.user", "instance_id", ), resource.TestCheckResourceAttr( - "data.stackit_postgresflex_instance.instance", + "data.stackitprivatepreview_postgresflexalpha_instance.instance", "acl.#", "1", ), resource.TestCheckResourceAttr( - "data.stackit_postgresflex_instance.instance", + "data.stackitprivatepreview_postgresflexalpha_instance.instance", "acl.0", instanceResource["acl"], ), resource.TestCheckResourceAttr( - "data.stackit_postgresflex_instance.instance", + "data.stackitprivatepreview_postgresflexalpha_instance.instance", "backup_schedule", instanceResource["backup_schedule"], ), resource.TestCheckResourceAttr( - "data.stackit_postgresflex_instance.instance", + "data.stackitprivatepreview_postgresflexalpha_instance.instance", "flavor.id", instanceResource["flavor_id"], ), resource.TestCheckResourceAttr( - "data.stackit_postgresflex_instance.instance", + "data.stackitprivatepreview_postgresflexalpha_instance.instance", "flavor.description", instanceResource["flavor_description"], ), resource.TestCheckResourceAttr( - "data.stackit_postgresflex_instance.instance", + "data.stackitprivatepreview_postgresflexalpha_instance.instance", "flavor.cpu", instanceResource["flavor_cpu"], ), resource.TestCheckResourceAttr( - "data.stackit_postgresflex_instance.instance", + "data.stackitprivatepreview_postgresflexalpha_instance.instance", "flavor.ram", instanceResource["flavor_ram"], ), resource.TestCheckResourceAttr( - "data.stackit_postgresflex_instance.instance", + "data.stackitprivatepreview_postgresflexalpha_instance.instance", "replicas", instanceResource["replicas"], ), // User data resource.TestCheckResourceAttr( - "data.stackit_postgresflex_user.user", + "data.stackitprivatepreview_postgresflexalpha_user.user", "project_id", userResource["project_id"], ), resource.TestCheckResourceAttrSet( - "data.stackit_postgresflex_user.user", + "data.stackitprivatepreview_postgresflexalpha_user.user", "user_id", ), resource.TestCheckResourceAttr( - "data.stackit_postgresflex_user.user", + "data.stackitprivatepreview_postgresflexalpha_user.user", "username", userResource["username"], ), resource.TestCheckResourceAttr( - "data.stackit_postgresflex_user.user", + "data.stackitprivatepreview_postgresflexalpha_user.user", "roles.#", "1", ), resource.TestCheckResourceAttr( - "data.stackit_postgresflex_user.user", + "data.stackitprivatepreview_postgresflexalpha_user.user", "roles.0", userResource["role"], ), resource.TestCheckResourceAttrSet( - "data.stackit_postgresflex_user.user", + "data.stackitprivatepreview_postgresflexalpha_user.user", "host", ), resource.TestCheckResourceAttrSet( - "data.stackit_postgresflex_user.user", + "data.stackitprivatepreview_postgresflexalpha_user.user", "port", ), // Database data resource.TestCheckResourceAttr( - "data.stackit_postgresflex_database.database", + "data.stackitprivatepreview_postgresflexalpha_database.database", "project_id", instanceResource["project_id"], ), resource.TestCheckResourceAttr( - "data.stackit_postgresflex_database.database", + "data.stackitprivatepreview_postgresflexalpha_database.database", "name", databaseResource["name"], ), resource.TestCheckResourceAttrPair( - "data.stackit_postgresflex_database.database", + "data.stackitprivatepreview_postgresflexalpha_database.database", "instance_id", - "stackit_postgresflex_instance.instance", + "stackitprivatepreview_postgresflexalpha_instance.instance", "instance_id", ), resource.TestCheckResourceAttrPair( - "data.stackit_postgresflex_database.database", + "data.stackitprivatepreview_postgresflexalpha_database.database", "owner", - "data.stackit_postgresflex_user.user", + "data.stackitprivatepreview_postgresflexalpha_user.user", "username", ), ), }, // Import { - ResourceName: "stackit_postgresflex_instance.instance", + ResourceName: "stackitprivatepreview_postgresflexalpha_instance.instance", ImportStateIdFunc: func(s *terraform.State) (string, error) { - r, ok := s.RootModule().Resources["stackit_postgresflex_instance.instance"] + r, ok := s.RootModule().Resources["stackitprivatepreview_postgresflexalpha_instance.instance"] if !ok { - return "", fmt.Errorf("couldn't find resource stackit_postgresflex_instance.instance") + return "", fmt.Errorf("couldn't find resource stackitprivatepreview_postgresflexalpha_instance.instance") } instanceId, ok := r.Primary.Attributes["instance_id"] if !ok { @@ -400,11 +442,11 @@ func TestAccPostgresFlexFlexResource(t *testing.T) { ImportStateVerifyIgnore: []string{"password"}, }, { - ResourceName: "stackit_postgresflex_user.user", + ResourceName: "stackitprivatepreview_postgresflexalpha_user.user", ImportStateIdFunc: func(s *terraform.State) (string, error) { - r, ok := s.RootModule().Resources["stackit_postgresflex_user.user"] + r, ok := s.RootModule().Resources["stackitprivatepreview_postgresflexalpha_user.user"] if !ok { - return "", fmt.Errorf("couldn't find resource stackit_postgresflex_user.user") + return "", fmt.Errorf("couldn't find resource stackitprivatepreview_postgresflexalpha_user.user") } instanceId, ok := r.Primary.Attributes["instance_id"] if !ok { @@ -422,11 +464,11 @@ func TestAccPostgresFlexFlexResource(t *testing.T) { ImportStateVerifyIgnore: []string{"password", "uri"}, }, { - ResourceName: "stackit_postgresflex_database.database", + ResourceName: "stackitprivatepreview_postgresflexalpha_database.database", ImportStateIdFunc: func(s *terraform.State) (string, error) { - r, ok := s.RootModule().Resources["stackit_postgresflex_database.database"] + r, ok := s.RootModule().Resources["stackitprivatepreview_postgresflexalpha_database.database"] if !ok { - return "", fmt.Errorf("couldn't find resource stackit_postgresflex_database.database") + return "", fmt.Errorf("couldn't find resource stackitprivatepreview_postgresflexalpha_database.database") } instanceId, ok := r.Primary.Attributes["instance_id"] if !ok { @@ -454,69 +496,69 @@ func TestAccPostgresFlexFlexResource(t *testing.T) { Check: resource.ComposeAggregateTestCheckFunc( // Instance data resource.TestCheckResourceAttr( - "stackit_postgresflex_instance.instance", + "stackitprivatepreview_postgresflexalpha_instance.instance", "project_id", instanceResource["project_id"], ), resource.TestCheckResourceAttrSet( - "stackit_postgresflex_instance.instance", + "stackitprivatepreview_postgresflexalpha_instance.instance", "instance_id", ), resource.TestCheckResourceAttr( - "stackit_postgresflex_instance.instance", + "stackitprivatepreview_postgresflexalpha_instance.instance", "name", instanceResource["name"], ), resource.TestCheckResourceAttr( - "stackit_postgresflex_instance.instance", + "stackitprivatepreview_postgresflexalpha_instance.instance", "acl.#", "1", ), resource.TestCheckResourceAttr( - "stackit_postgresflex_instance.instance", + "stackitprivatepreview_postgresflexalpha_instance.instance", "acl.0", instanceResource["acl"], ), resource.TestCheckResourceAttr( - "stackit_postgresflex_instance.instance", + "stackitprivatepreview_postgresflexalpha_instance.instance", "backup_schedule", instanceResource["backup_schedule_updated"], ), resource.TestCheckResourceAttrSet( - "stackit_postgresflex_instance.instance", + "stackitprivatepreview_postgresflexalpha_instance.instance", "flavor.id", ), resource.TestCheckResourceAttrSet( - "stackit_postgresflex_instance.instance", + "stackitprivatepreview_postgresflexalpha_instance.instance", "flavor.description", ), resource.TestCheckResourceAttr( - "stackit_postgresflex_instance.instance", + "stackitprivatepreview_postgresflexalpha_instance.instance", "flavor.cpu", instanceResource["flavor_cpu"], ), resource.TestCheckResourceAttr( - "stackit_postgresflex_instance.instance", + "stackitprivatepreview_postgresflexalpha_instance.instance", "flavor.ram", instanceResource["flavor_ram"], ), resource.TestCheckResourceAttr( - "stackit_postgresflex_instance.instance", + "stackitprivatepreview_postgresflexalpha_instance.instance", "replicas", instanceResource["replicas"], ), resource.TestCheckResourceAttr( - "stackit_postgresflex_instance.instance", + "stackitprivatepreview_postgresflexalpha_instance.instance", "storage.class", instanceResource["storage_class"], ), resource.TestCheckResourceAttr( - "stackit_postgresflex_instance.instance", + "stackitprivatepreview_postgresflexalpha_instance.instance", "storage.size", instanceResource["storage_size"], ), resource.TestCheckResourceAttr( - "stackit_postgresflex_instance.instance", + "stackitprivatepreview_postgresflexalpha_instance.instance", "version", instanceResource["version"], ), @@ -545,7 +587,7 @@ func testAccCheckPostgresFlexDestroy(s *terraform.State) error { instancesToDestroy := []string{} for _, rs := range s.RootModule().Resources { - if rs.Type != "stackit_postgresflex_instance" { + if rs.Type != "stackitprivatepreview_postgresflexalpha_instance" { continue } // instance terraform ID: = "[project_id],[region],[instance_id]" diff --git a/stackit/internal/services/postgresflexalpha/testdata/resource-complete.tf b/stackit/internal/services/postgresflexalpha/testdata/resource-complete.tf index 8b137891..7a708880 100644 --- a/stackit/internal/services/postgresflexalpha/testdata/resource-complete.tf +++ b/stackit/internal/services/postgresflexalpha/testdata/resource-complete.tf @@ -1 +1,24 @@ - +resource "stackitprivatepreview_postgresflexalpha_instance" "msh-instance-only" { + project_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" + name = "example-instance" + acl = ["XXX.XXX.XXX.X/XX", "XX.XXX.XX.X/XX"] + backup_schedule = "0 0 * * *" + retention_days = 30 + flavor_id = "flavor.id" + replicas = 1 + storage = { + performance_class = "premium-perf2-stackit" + size = 10 + } + encryption = { + kek_key_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" + kek_key_ring_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" + kek_key_version = 1 + service_account = "service@account.email" + } + network = { + acl = ["XXX.XXX.XXX.X/XX", "XX.XXX.XX.X/XX"] + access_scope = "PUBLIC" + } + version = 17 +} diff --git a/stackit/internal/services/sqlserverflexbeta/database/datasource.go b/stackit/internal/services/sqlserverflexbeta/database/datasource.go index 4cc56ea2..bb6c3038 100644 --- a/stackit/internal/services/sqlserverflexbeta/database/datasource.go +++ b/stackit/internal/services/sqlserverflexbeta/database/datasource.go @@ -146,15 +146,11 @@ func (d *databaseDataSource) Read(ctx context.Context, req datasource.ReadReques data.Id = types.Int64Value(dbId) data.TfId = utils.BuildInternalTerraformId(projectId, region, instanceId, databaseName) data.Owner = types.StringValue(databaseResp.GetOwner()) - - // TODO: fill remaining fields - // data.CollationName = types.Sometype(apiResponse.GetCollationName()) - // data.CompatibilityLevel = types.Sometype(apiResponse.GetCompatibilityLevel()) - // data.DatabaseName = types.Sometype(apiResponse.GetDatabaseName()) - // data.Id = types.Sometype(apiResponse.GetId()) - // data.InstanceId = types.Sometype(apiResponse.GetInstanceId()) + data.CollationName = types.StringValue(databaseResp.GetCollationName()) + data.CompatibilityLevel = types.Int64Value(databaseResp.GetCompatibilityLevel()) + data.DatabaseName = types.StringValue(databaseResp.GetName()) + // data.InstanceId = types.StringValue(databaseResp.GetInstanceId()) // data.Name = types.Sometype(apiResponse.GetName()) - // data.Owner = types.Sometype(apiResponse.GetOwner()) // data.ProjectId = types.Sometype(apiResponse.GetProjectId()) // data.Region = types.Sometype(apiResponse.GetRegion()) diff --git a/stackit/internal/services/sqlserverflexbeta/flavors/datasource.go b/stackit/internal/services/sqlserverflexbeta/flavors/datasource.go deleted file mode 100644 index 41b1aad8..00000000 --- a/stackit/internal/services/sqlserverflexbeta/flavors/datasource.go +++ /dev/null @@ -1,118 +0,0 @@ -package sqlserverflexbeta - -import ( - "context" - "fmt" - "net/http" - - "github.com/hashicorp/terraform-plugin-framework/datasource" - "github.com/hashicorp/terraform-plugin-log/tflog" - "tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit/internal/conversion" - "tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit/internal/core" - "tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit/internal/utils" - - sqlserverflexbetaPkg "tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/pkg_gen/sqlserverflexbeta" - - sqlserverflexbetaUtils "tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit/internal/services/sqlserverflexbeta/utils" - - sqlserverflexbetaGen "tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit/internal/services/sqlserverflexbeta/flavors/datasources_gen" -) - -var _ datasource.DataSource = (*flavorsDataSource)(nil) - -const errorPrefix = "[Sqlserverflexbeta - Flavors]" - -func NewFlavorsDataSource() datasource.DataSource { - return &flavorsDataSource{} -} - -type flavorsDataSource struct { - client *sqlserverflexbetaPkg.APIClient - providerData core.ProviderData -} - -func (d *flavorsDataSource) Metadata(_ context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) { - resp.TypeName = req.ProviderTypeName + "_sqlserverflexbeta_flavors" -} - -func (d *flavorsDataSource) Schema(ctx context.Context, _ datasource.SchemaRequest, resp *datasource.SchemaResponse) { - resp.Schema = sqlserverflexbetaGen.FlavorsDataSourceSchema(ctx) -} - -// Configure adds the provider configured client to the data source. -func (d *flavorsDataSource) Configure( - ctx context.Context, - req datasource.ConfigureRequest, - resp *datasource.ConfigureResponse, -) { - var ok bool - d.providerData, ok = conversion.ParseProviderData(ctx, req.ProviderData, &resp.Diagnostics) - if !ok { - return - } - - apiClient := sqlserverflexbetaUtils.ConfigureClient(ctx, &d.providerData, &resp.Diagnostics) - if resp.Diagnostics.HasError() { - return - } - d.client = apiClient - tflog.Info(ctx, fmt.Sprintf("%s client configured", errorPrefix)) -} - -func (d *flavorsDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { - var data sqlserverflexbetaGen.FlavorsModel - - // Read Terraform configuration data into the model - resp.Diagnostics.Append(req.Config.Get(ctx, &data)...) - - if resp.Diagnostics.HasError() { - return - } - - ctx = core.InitProviderContext(ctx) - - projectId := data.ProjectId.ValueString() - region := d.providerData.GetRegionWithOverride(data.Region) - flavorsId := data.FlavorsId.ValueString() - - ctx = tflog.SetField(ctx, "project_id", projectId) - ctx = tflog.SetField(ctx, "region", region) - ctx = tflog.SetField(ctx, "flavors_id", flavorsId) - - flavorsResp, err := d.client.GetFlavorsRequest(ctx, projectId, region, flavorsId).Execute() - if err != nil { - utils.LogError( - ctx, - &resp.Diagnostics, - err, - "Reading flavors", - fmt.Sprintf("flavors with ID %q does not exist in project %q.", flavorsId, projectId), - map[int]string{ - http.StatusForbidden: fmt.Sprintf("Project with ID %q not found or forbidden access", projectId), - }, - ) - resp.State.RemoveResource(ctx) - return - } - - ctx = core.LogResponse(ctx) - - // Todo: Read API call logic - - // Example data value setting - // data.Id = types.StringValue("example-id") - - err = mapResponseToModel(ctx, flavorsResp, &data, resp.Diagnostics) - if err != nil { - core.LogAndAddError( - ctx, - &resp.Diagnostics, - fmt.Sprintf("%s Read", errorPrefix), - fmt.Sprintf("Processing API payload: %v", err), - ) - return - } - - // Save data into Terraform state - resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) -} diff --git a/stackit/internal/services/sqlserverflexbeta/flavors/datasources_gen/flavors_data_source_gen.go b/stackit/internal/services/sqlserverflexbeta/flavors/datasources_gen/flavors_data_source_gen.go deleted file mode 100644 index 94b526be..00000000 --- a/stackit/internal/services/sqlserverflexbeta/flavors/datasources_gen/flavors_data_source_gen.go +++ /dev/null @@ -1,1909 +0,0 @@ -// Code generated by terraform-plugin-framework-generator DO NOT EDIT. - -package sqlserverflexbeta - -import ( - "context" - "fmt" - "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator" - "github.com/hashicorp/terraform-plugin-framework/attr" - "github.com/hashicorp/terraform-plugin-framework/diag" - "github.com/hashicorp/terraform-plugin-framework/schema/validator" - "github.com/hashicorp/terraform-plugin-framework/types" - "github.com/hashicorp/terraform-plugin-framework/types/basetypes" - "github.com/hashicorp/terraform-plugin-go/tftypes" - "strings" - - "github.com/hashicorp/terraform-plugin-framework/datasource/schema" -) - -func FlavorsDataSourceSchema(ctx context.Context) schema.Schema { - return schema.Schema{ - Attributes: map[string]schema.Attribute{ - "flavors": schema.ListNestedAttribute{ - NestedObject: schema.NestedAttributeObject{ - Attributes: map[string]schema.Attribute{ - "cpu": schema.Int64Attribute{ - Computed: true, - Description: "The cpu count of the instance.", - MarkdownDescription: "The cpu count of the instance.", - }, - "description": schema.StringAttribute{ - Computed: true, - Description: "The flavor description.", - MarkdownDescription: "The flavor description.", - }, - "id": schema.StringAttribute{ - Computed: true, - Description: "The id of the instance flavor.", - MarkdownDescription: "The id of the instance flavor.", - }, - "max_gb": schema.Int64Attribute{ - Computed: true, - Description: "maximum storage which can be ordered for the flavor in Gigabyte.", - MarkdownDescription: "maximum storage which can be ordered for the flavor in Gigabyte.", - }, - "memory": schema.Int64Attribute{ - Computed: true, - Description: "The memory of the instance in Gibibyte.", - MarkdownDescription: "The memory of the instance in Gibibyte.", - }, - "min_gb": schema.Int64Attribute{ - Computed: true, - Description: "minimum storage which is required to order in Gigabyte.", - MarkdownDescription: "minimum storage which is required to order in Gigabyte.", - }, - "node_type": schema.StringAttribute{ - Computed: true, - Description: "defines the nodeType it can be either single or HA", - MarkdownDescription: "defines the nodeType it can be either single or HA", - }, - "storage_classes": schema.ListNestedAttribute{ - NestedObject: schema.NestedAttributeObject{ - Attributes: map[string]schema.Attribute{ - "class": schema.StringAttribute{ - Computed: true, - }, - "max_io_per_sec": schema.Int64Attribute{ - Computed: true, - }, - "max_through_in_mb": schema.Int64Attribute{ - Computed: true, - }, - }, - CustomType: StorageClassesType{ - ObjectType: types.ObjectType{ - AttrTypes: StorageClassesValue{}.AttributeTypes(ctx), - }, - }, - }, - Computed: true, - Description: "maximum storage which can be ordered for the flavor in Gigabyte.", - MarkdownDescription: "maximum storage which can be ordered for the flavor in Gigabyte.", - }, - }, - CustomType: FlavorsType{ - ObjectType: types.ObjectType{ - AttrTypes: FlavorsValue{}.AttributeTypes(ctx), - }, - }, - }, - Computed: true, - Description: "List of flavors available for the project.", - MarkdownDescription: "List of flavors available for the project.", - }, - "page": schema.Int64Attribute{ - Optional: true, - Computed: true, - Description: "Number of the page of items list to be returned.", - MarkdownDescription: "Number of the page of items list to be returned.", - }, - "pagination": schema.SingleNestedAttribute{ - Attributes: map[string]schema.Attribute{ - "page": schema.Int64Attribute{ - Computed: true, - }, - "size": schema.Int64Attribute{ - Computed: true, - }, - "sort": schema.StringAttribute{ - Computed: true, - }, - "total_pages": schema.Int64Attribute{ - Computed: true, - }, - "total_rows": schema.Int64Attribute{ - Computed: true, - }, - }, - CustomType: PaginationType{ - ObjectType: types.ObjectType{ - AttrTypes: PaginationValue{}.AttributeTypes(ctx), - }, - }, - Computed: true, - }, - "project_id": schema.StringAttribute{ - Required: true, - Description: "The STACKIT project ID.", - MarkdownDescription: "The STACKIT project ID.", - }, - "region": schema.StringAttribute{ - Required: true, - Description: "The region which should be addressed", - MarkdownDescription: "The region which should be addressed", - Validators: []validator.String{ - stringvalidator.OneOf( - "eu01", - ), - }, - }, - "size": schema.Int64Attribute{ - Optional: true, - Computed: true, - Description: "Number of items to be returned on each page.", - MarkdownDescription: "Number of items to be returned on each page.", - }, - "sort": schema.StringAttribute{ - Optional: true, - Computed: true, - Description: "Sorting of the flavors to be returned on each page.", - MarkdownDescription: "Sorting of the flavors to be returned on each page.", - Validators: []validator.String{ - stringvalidator.OneOf( - "index.desc", - "index.asc", - "cpu.desc", - "cpu.asc", - "flavor_description.asc", - "flavor_description.desc", - "id.desc", - "id.asc", - "size_max.desc", - "size_max.asc", - "ram.desc", - "ram.asc", - "size_min.desc", - "size_min.asc", - "storage_class.asc", - "storage_class.desc", - "node_type.asc", - "node_type.desc", - ), - }, - }, - }, - } -} - -type FlavorsModel struct { - Flavors types.List `tfsdk:"flavors"` - Page types.Int64 `tfsdk:"page"` - Pagination PaginationValue `tfsdk:"pagination"` - ProjectId types.String `tfsdk:"project_id"` - Region types.String `tfsdk:"region"` - Size types.Int64 `tfsdk:"size"` - Sort types.String `tfsdk:"sort"` -} - -var _ basetypes.ObjectTypable = FlavorsType{} - -type FlavorsType struct { - basetypes.ObjectType -} - -func (t FlavorsType) Equal(o attr.Type) bool { - other, ok := o.(FlavorsType) - - if !ok { - return false - } - - return t.ObjectType.Equal(other.ObjectType) -} - -func (t FlavorsType) String() string { - return "FlavorsType" -} - -func (t FlavorsType) ValueFromObject(ctx context.Context, in basetypes.ObjectValue) (basetypes.ObjectValuable, diag.Diagnostics) { - var diags diag.Diagnostics - - attributes := in.Attributes() - - cpuAttribute, ok := attributes["cpu"] - - if !ok { - diags.AddError( - "Attribute Missing", - `cpu is missing from object`) - - return nil, diags - } - - cpuVal, ok := cpuAttribute.(basetypes.Int64Value) - - if !ok { - diags.AddError( - "Attribute Wrong Type", - fmt.Sprintf(`cpu expected to be basetypes.Int64Value, was: %T`, cpuAttribute)) - } - - descriptionAttribute, ok := attributes["description"] - - if !ok { - diags.AddError( - "Attribute Missing", - `description is missing from object`) - - return nil, diags - } - - descriptionVal, ok := descriptionAttribute.(basetypes.StringValue) - - if !ok { - diags.AddError( - "Attribute Wrong Type", - fmt.Sprintf(`description expected to be basetypes.StringValue, was: %T`, descriptionAttribute)) - } - - idAttribute, ok := attributes["id"] - - if !ok { - diags.AddError( - "Attribute Missing", - `id is missing from object`) - - return nil, diags - } - - idVal, ok := idAttribute.(basetypes.StringValue) - - if !ok { - diags.AddError( - "Attribute Wrong Type", - fmt.Sprintf(`id expected to be basetypes.StringValue, was: %T`, idAttribute)) - } - - maxGbAttribute, ok := attributes["max_gb"] - - if !ok { - diags.AddError( - "Attribute Missing", - `max_gb is missing from object`) - - return nil, diags - } - - maxGbVal, ok := maxGbAttribute.(basetypes.Int64Value) - - if !ok { - diags.AddError( - "Attribute Wrong Type", - fmt.Sprintf(`max_gb expected to be basetypes.Int64Value, was: %T`, maxGbAttribute)) - } - - memoryAttribute, ok := attributes["memory"] - - if !ok { - diags.AddError( - "Attribute Missing", - `memory is missing from object`) - - return nil, diags - } - - memoryVal, ok := memoryAttribute.(basetypes.Int64Value) - - if !ok { - diags.AddError( - "Attribute Wrong Type", - fmt.Sprintf(`memory expected to be basetypes.Int64Value, was: %T`, memoryAttribute)) - } - - minGbAttribute, ok := attributes["min_gb"] - - if !ok { - diags.AddError( - "Attribute Missing", - `min_gb is missing from object`) - - return nil, diags - } - - minGbVal, ok := minGbAttribute.(basetypes.Int64Value) - - if !ok { - diags.AddError( - "Attribute Wrong Type", - fmt.Sprintf(`min_gb expected to be basetypes.Int64Value, was: %T`, minGbAttribute)) - } - - nodeTypeAttribute, ok := attributes["node_type"] - - if !ok { - diags.AddError( - "Attribute Missing", - `node_type is missing from object`) - - return nil, diags - } - - nodeTypeVal, ok := nodeTypeAttribute.(basetypes.StringValue) - - if !ok { - diags.AddError( - "Attribute Wrong Type", - fmt.Sprintf(`node_type expected to be basetypes.StringValue, was: %T`, nodeTypeAttribute)) - } - - storageClassesAttribute, ok := attributes["storage_classes"] - - if !ok { - diags.AddError( - "Attribute Missing", - `storage_classes is missing from object`) - - return nil, diags - } - - storageClassesVal, ok := storageClassesAttribute.(basetypes.ListValue) - - if !ok { - diags.AddError( - "Attribute Wrong Type", - fmt.Sprintf(`storage_classes expected to be basetypes.ListValue, was: %T`, storageClassesAttribute)) - } - - if diags.HasError() { - return nil, diags - } - - return FlavorsValue{ - Cpu: cpuVal, - Description: descriptionVal, - Id: idVal, - MaxGb: maxGbVal, - Memory: memoryVal, - MinGb: minGbVal, - NodeType: nodeTypeVal, - StorageClasses: storageClassesVal, - state: attr.ValueStateKnown, - }, diags -} - -func NewFlavorsValueNull() FlavorsValue { - return FlavorsValue{ - state: attr.ValueStateNull, - } -} - -func NewFlavorsValueUnknown() FlavorsValue { - return FlavorsValue{ - state: attr.ValueStateUnknown, - } -} - -func NewFlavorsValue(attributeTypes map[string]attr.Type, attributes map[string]attr.Value) (FlavorsValue, diag.Diagnostics) { - var diags diag.Diagnostics - - // Reference: https://github.com/hashicorp/terraform-plugin-framework/issues/521 - ctx := context.Background() - - for name, attributeType := range attributeTypes { - attribute, ok := attributes[name] - - if !ok { - diags.AddError( - "Missing FlavorsValue Attribute Value", - "While creating a FlavorsValue value, a missing attribute value was detected. "+ - "A FlavorsValue must contain values for all attributes, even if null or unknown. "+ - "This is always an issue with the provider and should be reported to the provider developers.\n\n"+ - fmt.Sprintf("FlavorsValue Attribute Name (%s) Expected Type: %s", name, attributeType.String()), - ) - - continue - } - - if !attributeType.Equal(attribute.Type(ctx)) { - diags.AddError( - "Invalid FlavorsValue Attribute Type", - "While creating a FlavorsValue value, an invalid attribute value was detected. "+ - "A FlavorsValue must use a matching attribute type for the value. "+ - "This is always an issue with the provider and should be reported to the provider developers.\n\n"+ - fmt.Sprintf("FlavorsValue Attribute Name (%s) Expected Type: %s\n", name, attributeType.String())+ - fmt.Sprintf("FlavorsValue Attribute Name (%s) Given Type: %s", name, attribute.Type(ctx)), - ) - } - } - - for name := range attributes { - _, ok := attributeTypes[name] - - if !ok { - diags.AddError( - "Extra FlavorsValue Attribute Value", - "While creating a FlavorsValue value, an extra attribute value was detected. "+ - "A FlavorsValue must not contain values beyond the expected attribute types. "+ - "This is always an issue with the provider and should be reported to the provider developers.\n\n"+ - fmt.Sprintf("Extra FlavorsValue Attribute Name: %s", name), - ) - } - } - - if diags.HasError() { - return NewFlavorsValueUnknown(), diags - } - - cpuAttribute, ok := attributes["cpu"] - - if !ok { - diags.AddError( - "Attribute Missing", - `cpu is missing from object`) - - return NewFlavorsValueUnknown(), diags - } - - cpuVal, ok := cpuAttribute.(basetypes.Int64Value) - - if !ok { - diags.AddError( - "Attribute Wrong Type", - fmt.Sprintf(`cpu expected to be basetypes.Int64Value, was: %T`, cpuAttribute)) - } - - descriptionAttribute, ok := attributes["description"] - - if !ok { - diags.AddError( - "Attribute Missing", - `description is missing from object`) - - return NewFlavorsValueUnknown(), diags - } - - descriptionVal, ok := descriptionAttribute.(basetypes.StringValue) - - if !ok { - diags.AddError( - "Attribute Wrong Type", - fmt.Sprintf(`description expected to be basetypes.StringValue, was: %T`, descriptionAttribute)) - } - - idAttribute, ok := attributes["id"] - - if !ok { - diags.AddError( - "Attribute Missing", - `id is missing from object`) - - return NewFlavorsValueUnknown(), diags - } - - idVal, ok := idAttribute.(basetypes.StringValue) - - if !ok { - diags.AddError( - "Attribute Wrong Type", - fmt.Sprintf(`id expected to be basetypes.StringValue, was: %T`, idAttribute)) - } - - maxGbAttribute, ok := attributes["max_gb"] - - if !ok { - diags.AddError( - "Attribute Missing", - `max_gb is missing from object`) - - return NewFlavorsValueUnknown(), diags - } - - maxGbVal, ok := maxGbAttribute.(basetypes.Int64Value) - - if !ok { - diags.AddError( - "Attribute Wrong Type", - fmt.Sprintf(`max_gb expected to be basetypes.Int64Value, was: %T`, maxGbAttribute)) - } - - memoryAttribute, ok := attributes["memory"] - - if !ok { - diags.AddError( - "Attribute Missing", - `memory is missing from object`) - - return NewFlavorsValueUnknown(), diags - } - - memoryVal, ok := memoryAttribute.(basetypes.Int64Value) - - if !ok { - diags.AddError( - "Attribute Wrong Type", - fmt.Sprintf(`memory expected to be basetypes.Int64Value, was: %T`, memoryAttribute)) - } - - minGbAttribute, ok := attributes["min_gb"] - - if !ok { - diags.AddError( - "Attribute Missing", - `min_gb is missing from object`) - - return NewFlavorsValueUnknown(), diags - } - - minGbVal, ok := minGbAttribute.(basetypes.Int64Value) - - if !ok { - diags.AddError( - "Attribute Wrong Type", - fmt.Sprintf(`min_gb expected to be basetypes.Int64Value, was: %T`, minGbAttribute)) - } - - nodeTypeAttribute, ok := attributes["node_type"] - - if !ok { - diags.AddError( - "Attribute Missing", - `node_type is missing from object`) - - return NewFlavorsValueUnknown(), diags - } - - nodeTypeVal, ok := nodeTypeAttribute.(basetypes.StringValue) - - if !ok { - diags.AddError( - "Attribute Wrong Type", - fmt.Sprintf(`node_type expected to be basetypes.StringValue, was: %T`, nodeTypeAttribute)) - } - - storageClassesAttribute, ok := attributes["storage_classes"] - - if !ok { - diags.AddError( - "Attribute Missing", - `storage_classes is missing from object`) - - return NewFlavorsValueUnknown(), diags - } - - storageClassesVal, ok := storageClassesAttribute.(basetypes.ListValue) - - if !ok { - diags.AddError( - "Attribute Wrong Type", - fmt.Sprintf(`storage_classes expected to be basetypes.ListValue, was: %T`, storageClassesAttribute)) - } - - if diags.HasError() { - return NewFlavorsValueUnknown(), diags - } - - return FlavorsValue{ - Cpu: cpuVal, - Description: descriptionVal, - Id: idVal, - MaxGb: maxGbVal, - Memory: memoryVal, - MinGb: minGbVal, - NodeType: nodeTypeVal, - StorageClasses: storageClassesVal, - state: attr.ValueStateKnown, - }, diags -} - -func NewFlavorsValueMust(attributeTypes map[string]attr.Type, attributes map[string]attr.Value) FlavorsValue { - object, diags := NewFlavorsValue(attributeTypes, attributes) - - if diags.HasError() { - // This could potentially be added to the diag package. - diagsStrings := make([]string, 0, len(diags)) - - for _, diagnostic := range diags { - diagsStrings = append(diagsStrings, fmt.Sprintf( - "%s | %s | %s", - diagnostic.Severity(), - diagnostic.Summary(), - diagnostic.Detail())) - } - - panic("NewFlavorsValueMust received error(s): " + strings.Join(diagsStrings, "\n")) - } - - return object -} - -func (t FlavorsType) ValueFromTerraform(ctx context.Context, in tftypes.Value) (attr.Value, error) { - if in.Type() == nil { - return NewFlavorsValueNull(), nil - } - - if !in.Type().Equal(t.TerraformType(ctx)) { - return nil, fmt.Errorf("expected %s, got %s", t.TerraformType(ctx), in.Type()) - } - - if !in.IsKnown() { - return NewFlavorsValueUnknown(), nil - } - - if in.IsNull() { - return NewFlavorsValueNull(), nil - } - - attributes := map[string]attr.Value{} - - val := map[string]tftypes.Value{} - - err := in.As(&val) - - if err != nil { - return nil, err - } - - for k, v := range val { - a, err := t.AttrTypes[k].ValueFromTerraform(ctx, v) - - if err != nil { - return nil, err - } - - attributes[k] = a - } - - return NewFlavorsValueMust(FlavorsValue{}.AttributeTypes(ctx), attributes), nil -} - -func (t FlavorsType) ValueType(ctx context.Context) attr.Value { - return FlavorsValue{} -} - -var _ basetypes.ObjectValuable = FlavorsValue{} - -type FlavorsValue struct { - Cpu basetypes.Int64Value `tfsdk:"cpu"` - Description basetypes.StringValue `tfsdk:"description"` - Id basetypes.StringValue `tfsdk:"id"` - MaxGb basetypes.Int64Value `tfsdk:"max_gb"` - Memory basetypes.Int64Value `tfsdk:"memory"` - MinGb basetypes.Int64Value `tfsdk:"min_gb"` - NodeType basetypes.StringValue `tfsdk:"node_type"` - StorageClasses basetypes.ListValue `tfsdk:"storage_classes"` - state attr.ValueState -} - -func (v FlavorsValue) ToTerraformValue(ctx context.Context) (tftypes.Value, error) { - attrTypes := make(map[string]tftypes.Type, 8) - - var val tftypes.Value - var err error - - attrTypes["cpu"] = basetypes.Int64Type{}.TerraformType(ctx) - attrTypes["description"] = basetypes.StringType{}.TerraformType(ctx) - attrTypes["id"] = basetypes.StringType{}.TerraformType(ctx) - attrTypes["max_gb"] = basetypes.Int64Type{}.TerraformType(ctx) - attrTypes["memory"] = basetypes.Int64Type{}.TerraformType(ctx) - attrTypes["min_gb"] = basetypes.Int64Type{}.TerraformType(ctx) - attrTypes["node_type"] = basetypes.StringType{}.TerraformType(ctx) - attrTypes["storage_classes"] = basetypes.ListType{ - ElemType: StorageClassesValue{}.Type(ctx), - }.TerraformType(ctx) - - objectType := tftypes.Object{AttributeTypes: attrTypes} - - switch v.state { - case attr.ValueStateKnown: - vals := make(map[string]tftypes.Value, 8) - - val, err = v.Cpu.ToTerraformValue(ctx) - - if err != nil { - return tftypes.NewValue(objectType, tftypes.UnknownValue), err - } - - vals["cpu"] = val - - val, err = v.Description.ToTerraformValue(ctx) - - if err != nil { - return tftypes.NewValue(objectType, tftypes.UnknownValue), err - } - - vals["description"] = val - - val, err = v.Id.ToTerraformValue(ctx) - - if err != nil { - return tftypes.NewValue(objectType, tftypes.UnknownValue), err - } - - vals["id"] = val - - val, err = v.MaxGb.ToTerraformValue(ctx) - - if err != nil { - return tftypes.NewValue(objectType, tftypes.UnknownValue), err - } - - vals["max_gb"] = val - - val, err = v.Memory.ToTerraformValue(ctx) - - if err != nil { - return tftypes.NewValue(objectType, tftypes.UnknownValue), err - } - - vals["memory"] = val - - val, err = v.MinGb.ToTerraformValue(ctx) - - if err != nil { - return tftypes.NewValue(objectType, tftypes.UnknownValue), err - } - - vals["min_gb"] = val - - val, err = v.NodeType.ToTerraformValue(ctx) - - if err != nil { - return tftypes.NewValue(objectType, tftypes.UnknownValue), err - } - - vals["node_type"] = val - - val, err = v.StorageClasses.ToTerraformValue(ctx) - - if err != nil { - return tftypes.NewValue(objectType, tftypes.UnknownValue), err - } - - vals["storage_classes"] = val - - if err := tftypes.ValidateValue(objectType, vals); err != nil { - return tftypes.NewValue(objectType, tftypes.UnknownValue), err - } - - return tftypes.NewValue(objectType, vals), nil - case attr.ValueStateNull: - return tftypes.NewValue(objectType, nil), nil - case attr.ValueStateUnknown: - return tftypes.NewValue(objectType, tftypes.UnknownValue), nil - default: - panic(fmt.Sprintf("unhandled Object state in ToTerraformValue: %s", v.state)) - } -} - -func (v FlavorsValue) IsNull() bool { - return v.state == attr.ValueStateNull -} - -func (v FlavorsValue) IsUnknown() bool { - return v.state == attr.ValueStateUnknown -} - -func (v FlavorsValue) String() string { - return "FlavorsValue" -} - -func (v FlavorsValue) ToObjectValue(ctx context.Context) (basetypes.ObjectValue, diag.Diagnostics) { - var diags diag.Diagnostics - - storageClasses := types.ListValueMust( - StorageClassesType{ - basetypes.ObjectType{ - AttrTypes: StorageClassesValue{}.AttributeTypes(ctx), - }, - }, - v.StorageClasses.Elements(), - ) - - if v.StorageClasses.IsNull() { - storageClasses = types.ListNull( - StorageClassesType{ - basetypes.ObjectType{ - AttrTypes: StorageClassesValue{}.AttributeTypes(ctx), - }, - }, - ) - } - - if v.StorageClasses.IsUnknown() { - storageClasses = types.ListUnknown( - StorageClassesType{ - basetypes.ObjectType{ - AttrTypes: StorageClassesValue{}.AttributeTypes(ctx), - }, - }, - ) - } - - attributeTypes := map[string]attr.Type{ - "cpu": basetypes.Int64Type{}, - "description": basetypes.StringType{}, - "id": basetypes.StringType{}, - "max_gb": basetypes.Int64Type{}, - "memory": basetypes.Int64Type{}, - "min_gb": basetypes.Int64Type{}, - "node_type": basetypes.StringType{}, - "storage_classes": basetypes.ListType{ - ElemType: StorageClassesValue{}.Type(ctx), - }, - } - - if v.IsNull() { - return types.ObjectNull(attributeTypes), diags - } - - if v.IsUnknown() { - return types.ObjectUnknown(attributeTypes), diags - } - - objVal, diags := types.ObjectValue( - attributeTypes, - map[string]attr.Value{ - "cpu": v.Cpu, - "description": v.Description, - "id": v.Id, - "max_gb": v.MaxGb, - "memory": v.Memory, - "min_gb": v.MinGb, - "node_type": v.NodeType, - "storage_classes": storageClasses, - }) - - return objVal, diags -} - -func (v FlavorsValue) Equal(o attr.Value) bool { - other, ok := o.(FlavorsValue) - - if !ok { - return false - } - - if v.state != other.state { - return false - } - - if v.state != attr.ValueStateKnown { - return true - } - - if !v.Cpu.Equal(other.Cpu) { - return false - } - - if !v.Description.Equal(other.Description) { - return false - } - - if !v.Id.Equal(other.Id) { - return false - } - - if !v.MaxGb.Equal(other.MaxGb) { - return false - } - - if !v.Memory.Equal(other.Memory) { - return false - } - - if !v.MinGb.Equal(other.MinGb) { - return false - } - - if !v.NodeType.Equal(other.NodeType) { - return false - } - - if !v.StorageClasses.Equal(other.StorageClasses) { - return false - } - - return true -} - -func (v FlavorsValue) Type(ctx context.Context) attr.Type { - return FlavorsType{ - basetypes.ObjectType{ - AttrTypes: v.AttributeTypes(ctx), - }, - } -} - -func (v FlavorsValue) AttributeTypes(ctx context.Context) map[string]attr.Type { - return map[string]attr.Type{ - "cpu": basetypes.Int64Type{}, - "description": basetypes.StringType{}, - "id": basetypes.StringType{}, - "max_gb": basetypes.Int64Type{}, - "memory": basetypes.Int64Type{}, - "min_gb": basetypes.Int64Type{}, - "node_type": basetypes.StringType{}, - "storage_classes": basetypes.ListType{ - ElemType: StorageClassesValue{}.Type(ctx), - }, - } -} - -var _ basetypes.ObjectTypable = StorageClassesType{} - -type StorageClassesType struct { - basetypes.ObjectType -} - -func (t StorageClassesType) Equal(o attr.Type) bool { - other, ok := o.(StorageClassesType) - - if !ok { - return false - } - - return t.ObjectType.Equal(other.ObjectType) -} - -func (t StorageClassesType) String() string { - return "StorageClassesType" -} - -func (t StorageClassesType) ValueFromObject(ctx context.Context, in basetypes.ObjectValue) (basetypes.ObjectValuable, diag.Diagnostics) { - var diags diag.Diagnostics - - attributes := in.Attributes() - - classAttribute, ok := attributes["class"] - - if !ok { - diags.AddError( - "Attribute Missing", - `class is missing from object`) - - return nil, diags - } - - classVal, ok := classAttribute.(basetypes.StringValue) - - if !ok { - diags.AddError( - "Attribute Wrong Type", - fmt.Sprintf(`class expected to be basetypes.StringValue, was: %T`, classAttribute)) - } - - maxIoPerSecAttribute, ok := attributes["max_io_per_sec"] - - if !ok { - diags.AddError( - "Attribute Missing", - `max_io_per_sec is missing from object`) - - return nil, diags - } - - maxIoPerSecVal, ok := maxIoPerSecAttribute.(basetypes.Int64Value) - - if !ok { - diags.AddError( - "Attribute Wrong Type", - fmt.Sprintf(`max_io_per_sec expected to be basetypes.Int64Value, was: %T`, maxIoPerSecAttribute)) - } - - maxThroughInMbAttribute, ok := attributes["max_through_in_mb"] - - if !ok { - diags.AddError( - "Attribute Missing", - `max_through_in_mb is missing from object`) - - return nil, diags - } - - maxThroughInMbVal, ok := maxThroughInMbAttribute.(basetypes.Int64Value) - - if !ok { - diags.AddError( - "Attribute Wrong Type", - fmt.Sprintf(`max_through_in_mb expected to be basetypes.Int64Value, was: %T`, maxThroughInMbAttribute)) - } - - if diags.HasError() { - return nil, diags - } - - return StorageClassesValue{ - Class: classVal, - MaxIoPerSec: maxIoPerSecVal, - MaxThroughInMb: maxThroughInMbVal, - state: attr.ValueStateKnown, - }, diags -} - -func NewStorageClassesValueNull() StorageClassesValue { - return StorageClassesValue{ - state: attr.ValueStateNull, - } -} - -func NewStorageClassesValueUnknown() StorageClassesValue { - return StorageClassesValue{ - state: attr.ValueStateUnknown, - } -} - -func NewStorageClassesValue(attributeTypes map[string]attr.Type, attributes map[string]attr.Value) (StorageClassesValue, diag.Diagnostics) { - var diags diag.Diagnostics - - // Reference: https://github.com/hashicorp/terraform-plugin-framework/issues/521 - ctx := context.Background() - - for name, attributeType := range attributeTypes { - attribute, ok := attributes[name] - - if !ok { - diags.AddError( - "Missing StorageClassesValue Attribute Value", - "While creating a StorageClassesValue value, a missing attribute value was detected. "+ - "A StorageClassesValue must contain values for all attributes, even if null or unknown. "+ - "This is always an issue with the provider and should be reported to the provider developers.\n\n"+ - fmt.Sprintf("StorageClassesValue Attribute Name (%s) Expected Type: %s", name, attributeType.String()), - ) - - continue - } - - if !attributeType.Equal(attribute.Type(ctx)) { - diags.AddError( - "Invalid StorageClassesValue Attribute Type", - "While creating a StorageClassesValue value, an invalid attribute value was detected. "+ - "A StorageClassesValue must use a matching attribute type for the value. "+ - "This is always an issue with the provider and should be reported to the provider developers.\n\n"+ - fmt.Sprintf("StorageClassesValue Attribute Name (%s) Expected Type: %s\n", name, attributeType.String())+ - fmt.Sprintf("StorageClassesValue Attribute Name (%s) Given Type: %s", name, attribute.Type(ctx)), - ) - } - } - - for name := range attributes { - _, ok := attributeTypes[name] - - if !ok { - diags.AddError( - "Extra StorageClassesValue Attribute Value", - "While creating a StorageClassesValue value, an extra attribute value was detected. "+ - "A StorageClassesValue must not contain values beyond the expected attribute types. "+ - "This is always an issue with the provider and should be reported to the provider developers.\n\n"+ - fmt.Sprintf("Extra StorageClassesValue Attribute Name: %s", name), - ) - } - } - - if diags.HasError() { - return NewStorageClassesValueUnknown(), diags - } - - classAttribute, ok := attributes["class"] - - if !ok { - diags.AddError( - "Attribute Missing", - `class is missing from object`) - - return NewStorageClassesValueUnknown(), diags - } - - classVal, ok := classAttribute.(basetypes.StringValue) - - if !ok { - diags.AddError( - "Attribute Wrong Type", - fmt.Sprintf(`class expected to be basetypes.StringValue, was: %T`, classAttribute)) - } - - maxIoPerSecAttribute, ok := attributes["max_io_per_sec"] - - if !ok { - diags.AddError( - "Attribute Missing", - `max_io_per_sec is missing from object`) - - return NewStorageClassesValueUnknown(), diags - } - - maxIoPerSecVal, ok := maxIoPerSecAttribute.(basetypes.Int64Value) - - if !ok { - diags.AddError( - "Attribute Wrong Type", - fmt.Sprintf(`max_io_per_sec expected to be basetypes.Int64Value, was: %T`, maxIoPerSecAttribute)) - } - - maxThroughInMbAttribute, ok := attributes["max_through_in_mb"] - - if !ok { - diags.AddError( - "Attribute Missing", - `max_through_in_mb is missing from object`) - - return NewStorageClassesValueUnknown(), diags - } - - maxThroughInMbVal, ok := maxThroughInMbAttribute.(basetypes.Int64Value) - - if !ok { - diags.AddError( - "Attribute Wrong Type", - fmt.Sprintf(`max_through_in_mb expected to be basetypes.Int64Value, was: %T`, maxThroughInMbAttribute)) - } - - if diags.HasError() { - return NewStorageClassesValueUnknown(), diags - } - - return StorageClassesValue{ - Class: classVal, - MaxIoPerSec: maxIoPerSecVal, - MaxThroughInMb: maxThroughInMbVal, - state: attr.ValueStateKnown, - }, diags -} - -func NewStorageClassesValueMust(attributeTypes map[string]attr.Type, attributes map[string]attr.Value) StorageClassesValue { - object, diags := NewStorageClassesValue(attributeTypes, attributes) - - if diags.HasError() { - // This could potentially be added to the diag package. - diagsStrings := make([]string, 0, len(diags)) - - for _, diagnostic := range diags { - diagsStrings = append(diagsStrings, fmt.Sprintf( - "%s | %s | %s", - diagnostic.Severity(), - diagnostic.Summary(), - diagnostic.Detail())) - } - - panic("NewStorageClassesValueMust received error(s): " + strings.Join(diagsStrings, "\n")) - } - - return object -} - -func (t StorageClassesType) ValueFromTerraform(ctx context.Context, in tftypes.Value) (attr.Value, error) { - if in.Type() == nil { - return NewStorageClassesValueNull(), nil - } - - if !in.Type().Equal(t.TerraformType(ctx)) { - return nil, fmt.Errorf("expected %s, got %s", t.TerraformType(ctx), in.Type()) - } - - if !in.IsKnown() { - return NewStorageClassesValueUnknown(), nil - } - - if in.IsNull() { - return NewStorageClassesValueNull(), nil - } - - attributes := map[string]attr.Value{} - - val := map[string]tftypes.Value{} - - err := in.As(&val) - - if err != nil { - return nil, err - } - - for k, v := range val { - a, err := t.AttrTypes[k].ValueFromTerraform(ctx, v) - - if err != nil { - return nil, err - } - - attributes[k] = a - } - - return NewStorageClassesValueMust(StorageClassesValue{}.AttributeTypes(ctx), attributes), nil -} - -func (t StorageClassesType) ValueType(ctx context.Context) attr.Value { - return StorageClassesValue{} -} - -var _ basetypes.ObjectValuable = StorageClassesValue{} - -type StorageClassesValue struct { - Class basetypes.StringValue `tfsdk:"class"` - MaxIoPerSec basetypes.Int64Value `tfsdk:"max_io_per_sec"` - MaxThroughInMb basetypes.Int64Value `tfsdk:"max_through_in_mb"` - state attr.ValueState -} - -func (v StorageClassesValue) ToTerraformValue(ctx context.Context) (tftypes.Value, error) { - attrTypes := make(map[string]tftypes.Type, 3) - - var val tftypes.Value - var err error - - attrTypes["class"] = basetypes.StringType{}.TerraformType(ctx) - attrTypes["max_io_per_sec"] = basetypes.Int64Type{}.TerraformType(ctx) - attrTypes["max_through_in_mb"] = basetypes.Int64Type{}.TerraformType(ctx) - - objectType := tftypes.Object{AttributeTypes: attrTypes} - - switch v.state { - case attr.ValueStateKnown: - vals := make(map[string]tftypes.Value, 3) - - val, err = v.Class.ToTerraformValue(ctx) - - if err != nil { - return tftypes.NewValue(objectType, tftypes.UnknownValue), err - } - - vals["class"] = val - - val, err = v.MaxIoPerSec.ToTerraformValue(ctx) - - if err != nil { - return tftypes.NewValue(objectType, tftypes.UnknownValue), err - } - - vals["max_io_per_sec"] = val - - val, err = v.MaxThroughInMb.ToTerraformValue(ctx) - - if err != nil { - return tftypes.NewValue(objectType, tftypes.UnknownValue), err - } - - vals["max_through_in_mb"] = val - - if err := tftypes.ValidateValue(objectType, vals); err != nil { - return tftypes.NewValue(objectType, tftypes.UnknownValue), err - } - - return tftypes.NewValue(objectType, vals), nil - case attr.ValueStateNull: - return tftypes.NewValue(objectType, nil), nil - case attr.ValueStateUnknown: - return tftypes.NewValue(objectType, tftypes.UnknownValue), nil - default: - panic(fmt.Sprintf("unhandled Object state in ToTerraformValue: %s", v.state)) - } -} - -func (v StorageClassesValue) IsNull() bool { - return v.state == attr.ValueStateNull -} - -func (v StorageClassesValue) IsUnknown() bool { - return v.state == attr.ValueStateUnknown -} - -func (v StorageClassesValue) String() string { - return "StorageClassesValue" -} - -func (v StorageClassesValue) ToObjectValue(ctx context.Context) (basetypes.ObjectValue, diag.Diagnostics) { - var diags diag.Diagnostics - - attributeTypes := map[string]attr.Type{ - "class": basetypes.StringType{}, - "max_io_per_sec": basetypes.Int64Type{}, - "max_through_in_mb": basetypes.Int64Type{}, - } - - if v.IsNull() { - return types.ObjectNull(attributeTypes), diags - } - - if v.IsUnknown() { - return types.ObjectUnknown(attributeTypes), diags - } - - objVal, diags := types.ObjectValue( - attributeTypes, - map[string]attr.Value{ - "class": v.Class, - "max_io_per_sec": v.MaxIoPerSec, - "max_through_in_mb": v.MaxThroughInMb, - }) - - return objVal, diags -} - -func (v StorageClassesValue) Equal(o attr.Value) bool { - other, ok := o.(StorageClassesValue) - - if !ok { - return false - } - - if v.state != other.state { - return false - } - - if v.state != attr.ValueStateKnown { - return true - } - - if !v.Class.Equal(other.Class) { - return false - } - - if !v.MaxIoPerSec.Equal(other.MaxIoPerSec) { - return false - } - - if !v.MaxThroughInMb.Equal(other.MaxThroughInMb) { - return false - } - - return true -} - -func (v StorageClassesValue) Type(ctx context.Context) attr.Type { - return StorageClassesType{ - basetypes.ObjectType{ - AttrTypes: v.AttributeTypes(ctx), - }, - } -} - -func (v StorageClassesValue) AttributeTypes(ctx context.Context) map[string]attr.Type { - return map[string]attr.Type{ - "class": basetypes.StringType{}, - "max_io_per_sec": basetypes.Int64Type{}, - "max_through_in_mb": basetypes.Int64Type{}, - } -} - -var _ basetypes.ObjectTypable = PaginationType{} - -type PaginationType struct { - basetypes.ObjectType -} - -func (t PaginationType) Equal(o attr.Type) bool { - other, ok := o.(PaginationType) - - if !ok { - return false - } - - return t.ObjectType.Equal(other.ObjectType) -} - -func (t PaginationType) String() string { - return "PaginationType" -} - -func (t PaginationType) ValueFromObject(ctx context.Context, in basetypes.ObjectValue) (basetypes.ObjectValuable, diag.Diagnostics) { - var diags diag.Diagnostics - - attributes := in.Attributes() - - pageAttribute, ok := attributes["page"] - - if !ok { - diags.AddError( - "Attribute Missing", - `page is missing from object`) - - return nil, diags - } - - pageVal, ok := pageAttribute.(basetypes.Int64Value) - - if !ok { - diags.AddError( - "Attribute Wrong Type", - fmt.Sprintf(`page expected to be basetypes.Int64Value, was: %T`, pageAttribute)) - } - - sizeAttribute, ok := attributes["size"] - - if !ok { - diags.AddError( - "Attribute Missing", - `size is missing from object`) - - return nil, diags - } - - sizeVal, ok := sizeAttribute.(basetypes.Int64Value) - - if !ok { - diags.AddError( - "Attribute Wrong Type", - fmt.Sprintf(`size expected to be basetypes.Int64Value, was: %T`, sizeAttribute)) - } - - sortAttribute, ok := attributes["sort"] - - if !ok { - diags.AddError( - "Attribute Missing", - `sort is missing from object`) - - return nil, diags - } - - sortVal, ok := sortAttribute.(basetypes.StringValue) - - if !ok { - diags.AddError( - "Attribute Wrong Type", - fmt.Sprintf(`sort expected to be basetypes.StringValue, was: %T`, sortAttribute)) - } - - totalPagesAttribute, ok := attributes["total_pages"] - - if !ok { - diags.AddError( - "Attribute Missing", - `total_pages is missing from object`) - - return nil, diags - } - - totalPagesVal, ok := totalPagesAttribute.(basetypes.Int64Value) - - if !ok { - diags.AddError( - "Attribute Wrong Type", - fmt.Sprintf(`total_pages expected to be basetypes.Int64Value, was: %T`, totalPagesAttribute)) - } - - totalRowsAttribute, ok := attributes["total_rows"] - - if !ok { - diags.AddError( - "Attribute Missing", - `total_rows is missing from object`) - - return nil, diags - } - - totalRowsVal, ok := totalRowsAttribute.(basetypes.Int64Value) - - if !ok { - diags.AddError( - "Attribute Wrong Type", - fmt.Sprintf(`total_rows expected to be basetypes.Int64Value, was: %T`, totalRowsAttribute)) - } - - if diags.HasError() { - return nil, diags - } - - return PaginationValue{ - Page: pageVal, - Size: sizeVal, - Sort: sortVal, - TotalPages: totalPagesVal, - TotalRows: totalRowsVal, - state: attr.ValueStateKnown, - }, diags -} - -func NewPaginationValueNull() PaginationValue { - return PaginationValue{ - state: attr.ValueStateNull, - } -} - -func NewPaginationValueUnknown() PaginationValue { - return PaginationValue{ - state: attr.ValueStateUnknown, - } -} - -func NewPaginationValue(attributeTypes map[string]attr.Type, attributes map[string]attr.Value) (PaginationValue, diag.Diagnostics) { - var diags diag.Diagnostics - - // Reference: https://github.com/hashicorp/terraform-plugin-framework/issues/521 - ctx := context.Background() - - for name, attributeType := range attributeTypes { - attribute, ok := attributes[name] - - if !ok { - diags.AddError( - "Missing PaginationValue Attribute Value", - "While creating a PaginationValue value, a missing attribute value was detected. "+ - "A PaginationValue must contain values for all attributes, even if null or unknown. "+ - "This is always an issue with the provider and should be reported to the provider developers.\n\n"+ - fmt.Sprintf("PaginationValue Attribute Name (%s) Expected Type: %s", name, attributeType.String()), - ) - - continue - } - - if !attributeType.Equal(attribute.Type(ctx)) { - diags.AddError( - "Invalid PaginationValue Attribute Type", - "While creating a PaginationValue value, an invalid attribute value was detected. "+ - "A PaginationValue must use a matching attribute type for the value. "+ - "This is always an issue with the provider and should be reported to the provider developers.\n\n"+ - fmt.Sprintf("PaginationValue Attribute Name (%s) Expected Type: %s\n", name, attributeType.String())+ - fmt.Sprintf("PaginationValue Attribute Name (%s) Given Type: %s", name, attribute.Type(ctx)), - ) - } - } - - for name := range attributes { - _, ok := attributeTypes[name] - - if !ok { - diags.AddError( - "Extra PaginationValue Attribute Value", - "While creating a PaginationValue value, an extra attribute value was detected. "+ - "A PaginationValue must not contain values beyond the expected attribute types. "+ - "This is always an issue with the provider and should be reported to the provider developers.\n\n"+ - fmt.Sprintf("Extra PaginationValue Attribute Name: %s", name), - ) - } - } - - if diags.HasError() { - return NewPaginationValueUnknown(), diags - } - - pageAttribute, ok := attributes["page"] - - if !ok { - diags.AddError( - "Attribute Missing", - `page is missing from object`) - - return NewPaginationValueUnknown(), diags - } - - pageVal, ok := pageAttribute.(basetypes.Int64Value) - - if !ok { - diags.AddError( - "Attribute Wrong Type", - fmt.Sprintf(`page expected to be basetypes.Int64Value, was: %T`, pageAttribute)) - } - - sizeAttribute, ok := attributes["size"] - - if !ok { - diags.AddError( - "Attribute Missing", - `size is missing from object`) - - return NewPaginationValueUnknown(), diags - } - - sizeVal, ok := sizeAttribute.(basetypes.Int64Value) - - if !ok { - diags.AddError( - "Attribute Wrong Type", - fmt.Sprintf(`size expected to be basetypes.Int64Value, was: %T`, sizeAttribute)) - } - - sortAttribute, ok := attributes["sort"] - - if !ok { - diags.AddError( - "Attribute Missing", - `sort is missing from object`) - - return NewPaginationValueUnknown(), diags - } - - sortVal, ok := sortAttribute.(basetypes.StringValue) - - if !ok { - diags.AddError( - "Attribute Wrong Type", - fmt.Sprintf(`sort expected to be basetypes.StringValue, was: %T`, sortAttribute)) - } - - totalPagesAttribute, ok := attributes["total_pages"] - - if !ok { - diags.AddError( - "Attribute Missing", - `total_pages is missing from object`) - - return NewPaginationValueUnknown(), diags - } - - totalPagesVal, ok := totalPagesAttribute.(basetypes.Int64Value) - - if !ok { - diags.AddError( - "Attribute Wrong Type", - fmt.Sprintf(`total_pages expected to be basetypes.Int64Value, was: %T`, totalPagesAttribute)) - } - - totalRowsAttribute, ok := attributes["total_rows"] - - if !ok { - diags.AddError( - "Attribute Missing", - `total_rows is missing from object`) - - return NewPaginationValueUnknown(), diags - } - - totalRowsVal, ok := totalRowsAttribute.(basetypes.Int64Value) - - if !ok { - diags.AddError( - "Attribute Wrong Type", - fmt.Sprintf(`total_rows expected to be basetypes.Int64Value, was: %T`, totalRowsAttribute)) - } - - if diags.HasError() { - return NewPaginationValueUnknown(), diags - } - - return PaginationValue{ - Page: pageVal, - Size: sizeVal, - Sort: sortVal, - TotalPages: totalPagesVal, - TotalRows: totalRowsVal, - state: attr.ValueStateKnown, - }, diags -} - -func NewPaginationValueMust(attributeTypes map[string]attr.Type, attributes map[string]attr.Value) PaginationValue { - object, diags := NewPaginationValue(attributeTypes, attributes) - - if diags.HasError() { - // This could potentially be added to the diag package. - diagsStrings := make([]string, 0, len(diags)) - - for _, diagnostic := range diags { - diagsStrings = append(diagsStrings, fmt.Sprintf( - "%s | %s | %s", - diagnostic.Severity(), - diagnostic.Summary(), - diagnostic.Detail())) - } - - panic("NewPaginationValueMust received error(s): " + strings.Join(diagsStrings, "\n")) - } - - return object -} - -func (t PaginationType) ValueFromTerraform(ctx context.Context, in tftypes.Value) (attr.Value, error) { - if in.Type() == nil { - return NewPaginationValueNull(), nil - } - - if !in.Type().Equal(t.TerraformType(ctx)) { - return nil, fmt.Errorf("expected %s, got %s", t.TerraformType(ctx), in.Type()) - } - - if !in.IsKnown() { - return NewPaginationValueUnknown(), nil - } - - if in.IsNull() { - return NewPaginationValueNull(), nil - } - - attributes := map[string]attr.Value{} - - val := map[string]tftypes.Value{} - - err := in.As(&val) - - if err != nil { - return nil, err - } - - for k, v := range val { - a, err := t.AttrTypes[k].ValueFromTerraform(ctx, v) - - if err != nil { - return nil, err - } - - attributes[k] = a - } - - return NewPaginationValueMust(PaginationValue{}.AttributeTypes(ctx), attributes), nil -} - -func (t PaginationType) ValueType(ctx context.Context) attr.Value { - return PaginationValue{} -} - -var _ basetypes.ObjectValuable = PaginationValue{} - -type PaginationValue struct { - Page basetypes.Int64Value `tfsdk:"page"` - Size basetypes.Int64Value `tfsdk:"size"` - Sort basetypes.StringValue `tfsdk:"sort"` - TotalPages basetypes.Int64Value `tfsdk:"total_pages"` - TotalRows basetypes.Int64Value `tfsdk:"total_rows"` - state attr.ValueState -} - -func (v PaginationValue) ToTerraformValue(ctx context.Context) (tftypes.Value, error) { - attrTypes := make(map[string]tftypes.Type, 5) - - var val tftypes.Value - var err error - - attrTypes["page"] = basetypes.Int64Type{}.TerraformType(ctx) - attrTypes["size"] = basetypes.Int64Type{}.TerraformType(ctx) - attrTypes["sort"] = basetypes.StringType{}.TerraformType(ctx) - attrTypes["total_pages"] = basetypes.Int64Type{}.TerraformType(ctx) - attrTypes["total_rows"] = basetypes.Int64Type{}.TerraformType(ctx) - - objectType := tftypes.Object{AttributeTypes: attrTypes} - - switch v.state { - case attr.ValueStateKnown: - vals := make(map[string]tftypes.Value, 5) - - val, err = v.Page.ToTerraformValue(ctx) - - if err != nil { - return tftypes.NewValue(objectType, tftypes.UnknownValue), err - } - - vals["page"] = val - - val, err = v.Size.ToTerraformValue(ctx) - - if err != nil { - return tftypes.NewValue(objectType, tftypes.UnknownValue), err - } - - vals["size"] = val - - val, err = v.Sort.ToTerraformValue(ctx) - - if err != nil { - return tftypes.NewValue(objectType, tftypes.UnknownValue), err - } - - vals["sort"] = val - - val, err = v.TotalPages.ToTerraformValue(ctx) - - if err != nil { - return tftypes.NewValue(objectType, tftypes.UnknownValue), err - } - - vals["total_pages"] = val - - val, err = v.TotalRows.ToTerraformValue(ctx) - - if err != nil { - return tftypes.NewValue(objectType, tftypes.UnknownValue), err - } - - vals["total_rows"] = val - - if err := tftypes.ValidateValue(objectType, vals); err != nil { - return tftypes.NewValue(objectType, tftypes.UnknownValue), err - } - - return tftypes.NewValue(objectType, vals), nil - case attr.ValueStateNull: - return tftypes.NewValue(objectType, nil), nil - case attr.ValueStateUnknown: - return tftypes.NewValue(objectType, tftypes.UnknownValue), nil - default: - panic(fmt.Sprintf("unhandled Object state in ToTerraformValue: %s", v.state)) - } -} - -func (v PaginationValue) IsNull() bool { - return v.state == attr.ValueStateNull -} - -func (v PaginationValue) IsUnknown() bool { - return v.state == attr.ValueStateUnknown -} - -func (v PaginationValue) String() string { - return "PaginationValue" -} - -func (v PaginationValue) ToObjectValue(ctx context.Context) (basetypes.ObjectValue, diag.Diagnostics) { - var diags diag.Diagnostics - - attributeTypes := map[string]attr.Type{ - "page": basetypes.Int64Type{}, - "size": basetypes.Int64Type{}, - "sort": basetypes.StringType{}, - "total_pages": basetypes.Int64Type{}, - "total_rows": basetypes.Int64Type{}, - } - - if v.IsNull() { - return types.ObjectNull(attributeTypes), diags - } - - if v.IsUnknown() { - return types.ObjectUnknown(attributeTypes), diags - } - - objVal, diags := types.ObjectValue( - attributeTypes, - map[string]attr.Value{ - "page": v.Page, - "size": v.Size, - "sort": v.Sort, - "total_pages": v.TotalPages, - "total_rows": v.TotalRows, - }) - - return objVal, diags -} - -func (v PaginationValue) Equal(o attr.Value) bool { - other, ok := o.(PaginationValue) - - if !ok { - return false - } - - if v.state != other.state { - return false - } - - if v.state != attr.ValueStateKnown { - return true - } - - if !v.Page.Equal(other.Page) { - return false - } - - if !v.Size.Equal(other.Size) { - return false - } - - if !v.Sort.Equal(other.Sort) { - return false - } - - if !v.TotalPages.Equal(other.TotalPages) { - return false - } - - if !v.TotalRows.Equal(other.TotalRows) { - return false - } - - return true -} - -func (v PaginationValue) Type(ctx context.Context) attr.Type { - return PaginationType{ - basetypes.ObjectType{ - AttrTypes: v.AttributeTypes(ctx), - }, - } -} - -func (v PaginationValue) AttributeTypes(ctx context.Context) map[string]attr.Type { - return map[string]attr.Type{ - "page": basetypes.Int64Type{}, - "size": basetypes.Int64Type{}, - "sort": basetypes.StringType{}, - "total_pages": basetypes.Int64Type{}, - "total_rows": basetypes.Int64Type{}, - } -} diff --git a/stackit/internal/services/sqlserverflexbeta/user/datasource.go b/stackit/internal/services/sqlserverflexbeta/user/datasource.go index 985692a6..df1a8033 100644 --- a/stackit/internal/services/sqlserverflexbeta/user/datasource.go +++ b/stackit/internal/services/sqlserverflexbeta/user/datasource.go @@ -7,13 +7,12 @@ import ( "github.com/hashicorp/terraform-plugin-framework/datasource" "github.com/hashicorp/terraform-plugin-log/tflog" - "tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit/internal/conversion" "tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit/internal/core" "tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit/internal/utils" sqlserverflexbetaPkg "tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/pkg_gen/sqlserverflexbeta" - sqlserverflexbetaUtils "tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit/internal/services/sqlserverflexbeta/utils" + // sqlserverflexbetaUtils "tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit/internal/services/sqlserverflexbeta/utils" sqlserverflexbetaGen "tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit/internal/services/sqlserverflexbeta/user/datasources_gen" ) @@ -45,17 +44,17 @@ func (d *userDataSource) Configure( req datasource.ConfigureRequest, resp *datasource.ConfigureResponse, ) { - var ok bool - d.providerData, ok = conversion.ParseProviderData(ctx, req.ProviderData, &resp.Diagnostics) - if !ok { - return - } - - apiClient := sqlserverflexbetaUtils.ConfigureClient(ctx, &d.providerData, &resp.Diagnostics) - if resp.Diagnostics.HasError() { - return - } - d.client = apiClient + //var ok bool + //d.providerData, ok = conversion.ParseProviderData(ctx, req.ProviderData, &resp.Diagnostics) + //if !ok { + // return + //} + // + //apiClient := sqlserverflexbetaUtils.ConfigureClient(ctx, &d.providerData, &resp.Diagnostics) + //if resp.Diagnostics.HasError() { + // return + //} + //d.client = apiClient tflog.Info(ctx, fmt.Sprintf("%s client configured", errorPrefix)) } diff --git a/stackit/internal/testutil/assert.go b/stackit/internal/testutil/assert.go new file mode 100644 index 00000000..80cb2104 --- /dev/null +++ b/stackit/internal/testutil/assert.go @@ -0,0 +1,11 @@ +package testutil + +import "testing" + +func Equal[V comparable](t *testing.T, got, expected V) { + t.Helper() + + if expected != got { + t.Errorf("assert equal failed:\ngot: %v \nexpected: %v", got, expected) + } +} diff --git a/stackit/internal/testutil/testutil.go b/stackit/internal/testutil/testutil.go index e2ab0c59..b678efef 100644 --- a/stackit/internal/testutil/testutil.go +++ b/stackit/internal/testutil/testutil.go @@ -3,7 +3,6 @@ package testutil import ( - "encoding/json" "fmt" "os" "path/filepath" @@ -20,7 +19,8 @@ import ( const ( // Default location of credentials JSON - credentialsFilePath = ".stackit/credentials.json" //nolint:gosec // linter false positive + // credentialsFilePath = ".stackit/credentials.json" //nolint:gosec // linter false positive + serviceAccountFilePath = ".stackit/service_account.json" ) var ( @@ -29,7 +29,7 @@ var ( // CLI command executed to create a provider server to which the CLI can // reattach. TestAccProtoV6ProviderFactories = map[string]func() (tfprotov6.ProviderServer, error){ - "stackit": providerserver.NewProtocol6WithError(stackit.New("test-version")()), + "stackitprivatepreview": providerserver.NewProtocol6WithError(stackit.New("test-version")()), } // TestEphemeralAccProtoV6ProviderFactories is used to instantiate a provider during @@ -40,8 +40,8 @@ var ( // See the Terraform acceptance test documentation on ephemeral resources for more information: // https://developer.hashicorp.com/terraform/plugin/testing/acceptance-tests/ephemeral-resources TestEphemeralAccProtoV6ProviderFactories = map[string]func() (tfprotov6.ProviderServer, error){ - "stackit": providerserver.NewProtocol6WithError(stackit.New("test-version")()), - "echo": echoprovider.NewProviderServer(), + "stackitprivatepreview": providerserver.NewProtocol6WithError(stackit.New("test-version")()), + "echo": echoprovider.NewProviderServer(), } // E2ETestsEnabled checks if end-to-end tests should be run. @@ -52,6 +52,8 @@ var ( // ProjectId is the id of project used for tests ProjectId = os.Getenv("TF_ACC_PROJECT_ID") Region = os.Getenv("TF_ACC_REGION") + // ServiceAccountFile is the json file of the service account + ServiceAccountFile = os.Getenv("TF_ACC_SERVICE_ACCOUNT_FILE") // ServerId is the id of a server used for some tests ServerId = getenv("TF_ACC_SERVER_ID", "") // TestProjectParentContainerID is the container id of the parent resource under which projects are created as part of the resource-manager acceptance tests @@ -97,26 +99,27 @@ var ( func ObservabilityProviderConfig() string { if ObservabilityCustomEndpoint == "" { - return `provider "stackit" { + return `provider "stackitprivatepreview" { default_region = "eu01" }` } return fmt.Sprintf(` - provider "stackit" { + provider "stackitprivatepreview" { observability_custom_endpoint = "%s" }`, ObservabilityCustomEndpoint, ) } + func CdnProviderConfig() string { if CdnCustomEndpoint == "" { return ` - provider "stackit" { + provider "stackitprivatepreview" { enable_beta_resources = true }` } return fmt.Sprintf(` - provider "stackit" { + provider "stackitprivatepreview" { cdn_custom_endpoint = "%s" enable_beta_resources = true }`, @@ -126,10 +129,10 @@ func CdnProviderConfig() string { func DnsProviderConfig() string { if DnsCustomEndpoint == "" { - return `provider "stackit" {}` + return `provider "stackitprivatepreview" {}` } return fmt.Sprintf(` - provider "stackit" { + provider "stackitprivatepreview" { dns_custom_endpoint = "%s" }`, DnsCustomEndpoint, @@ -139,12 +142,12 @@ func DnsProviderConfig() string { func IaaSProviderConfig() string { if IaaSCustomEndpoint == "" { return ` - provider "stackit" { + provider "stackitprivatepreview" { default_region = "eu01" }` } return fmt.Sprintf(` - provider "stackit" { + provider "stackitprivatepreview" { iaas_custom_endpoint = "%s" }`, IaaSCustomEndpoint, @@ -154,13 +157,13 @@ func IaaSProviderConfig() string { func IaaSProviderConfigWithBetaResourcesEnabled() string { if IaaSCustomEndpoint == "" { return ` - provider "stackit" { + provider "stackitprivatepreview" { enable_beta_resources = true default_region = "eu01" }` } return fmt.Sprintf(` - provider "stackit" { + provider "stackitprivatepreview" { enable_beta_resources = true iaas_custom_endpoint = "%s" }`, @@ -171,13 +174,13 @@ func IaaSProviderConfigWithBetaResourcesEnabled() string { func IaaSProviderConfigWithExperiments() string { if IaaSCustomEndpoint == "" { return ` - provider "stackit" { + provider "stackitprivatepreview" { default_region = "eu01" experiments = [ "routing-tables", "network" ] }` } return fmt.Sprintf(` - provider "stackit" { + provider "stackitprivatepreview" { iaas_custom_endpoint = "%s" experiments = [ "routing-tables", "network" ] }`, @@ -188,12 +191,12 @@ func IaaSProviderConfigWithExperiments() string { func KMSProviderConfig() string { if KMSCustomEndpoint == "" { return ` - provider "stackit" { + provider "stackitprivatepreview" { default_region = "eu01" }` } return fmt.Sprintf(` - provider "stackit" { + provider "stackitprivatepreview" { kms_custom_endpoint = "%s" }`, KMSCustomEndpoint, @@ -203,12 +206,12 @@ func KMSProviderConfig() string { func LoadBalancerProviderConfig() string { if LoadBalancerCustomEndpoint == "" { return ` - provider "stackit" { + provider "stackitprivatepreview" { default_region = "eu01" }` } return fmt.Sprintf(` - provider "stackit" { + provider "stackitprivatepreview" { loadbalancer_custom_endpoint = "%s" }`, LoadBalancerCustomEndpoint, @@ -218,12 +221,12 @@ func LoadBalancerProviderConfig() string { func LogMeProviderConfig() string { if LogMeCustomEndpoint == "" { return ` - provider "stackit" { + provider "stackitprivatepreview" { default_region = "eu01" }` } return fmt.Sprintf(` - provider "stackit" { + provider "stackitprivatepreview" { logme_custom_endpoint = "%s" }`, LogMeCustomEndpoint, @@ -233,12 +236,12 @@ func LogMeProviderConfig() string { func MariaDBProviderConfig() string { if MariaDBCustomEndpoint == "" { return ` - provider "stackit" { + provider "stackitprivatepreview" { default_region = "eu01" }` } return fmt.Sprintf(` - provider "stackit" { + provider "stackitprivatepreview" { mariadb_custom_endpoint = "%s" }`, MariaDBCustomEndpoint, @@ -248,13 +251,13 @@ func MariaDBProviderConfig() string { func ModelServingProviderConfig() string { if ModelServingCustomEndpoint == "" { return ` - provider "stackit" { + provider "stackitprivatepreview" { default_region = "eu01" } ` } return fmt.Sprintf(` - provider "stackit" { + provider "stackitprivatepreview" { modelserving_custom_endpoint = "%s" }`, ModelServingCustomEndpoint, @@ -264,12 +267,12 @@ func ModelServingProviderConfig() string { func MongoDBFlexProviderConfig() string { if MongoDBFlexCustomEndpoint == "" { return ` - provider "stackit" { + provider "stackitprivatepreview" { default_region = "eu01" }` } return fmt.Sprintf(` - provider "stackit" { + provider "stackitprivatepreview" { mongodbflex_custom_endpoint = "%s" }`, MongoDBFlexCustomEndpoint, @@ -279,12 +282,12 @@ func MongoDBFlexProviderConfig() string { func ObjectStorageProviderConfig() string { if ObjectStorageCustomEndpoint == "" { return ` - provider "stackit" { + provider "stackitprivatepreview" { default_region = "eu01" }` } return fmt.Sprintf(` - provider "stackit" { + provider "stackitprivatepreview" { objectstorage_custom_endpoint = "%s" }`, ObjectStorageCustomEndpoint, @@ -294,29 +297,32 @@ func ObjectStorageProviderConfig() string { func OpenSearchProviderConfig() string { if OpenSearchCustomEndpoint == "" { return ` - provider "stackit" { + provider "stackitprivatepreview" { default_region = "eu01" }` } return fmt.Sprintf(` - provider "stackit" { + provider "stackitprivatepreview" { opensearch_custom_endpoint = "%s" }`, OpenSearchCustomEndpoint, ) } -func PostgresFlexProviderConfig() string { +func PostgresFlexProviderConfig(saFile string) string { if PostgresFlexCustomEndpoint == "" { - return ` - provider "stackit" { + return fmt.Sprintf(` + provider "stackitprivatepreview" { default_region = "eu01" - }` + service_account_key_path = "%s" + }`, saFile) } return fmt.Sprintf(` - provider "stackit" { + provider "stackitprivatepreview" { + service_account_key_path = "%s" postgresflex_custom_endpoint = "%s" }`, + saFile, PostgresFlexCustomEndpoint, ) } @@ -324,12 +330,12 @@ func PostgresFlexProviderConfig() string { func RabbitMQProviderConfig() string { if RabbitMQCustomEndpoint == "" { return ` - provider "stackit" { + provider "stackitprivatepreview" { default_region = "eu01" }` } return fmt.Sprintf(` - provider "stackit" { + provider "stackitprivatepreview" { rabbitmq_custom_endpoint = "%s" }`, RabbitMQCustomEndpoint, @@ -339,12 +345,12 @@ func RabbitMQProviderConfig() string { func RedisProviderConfig() string { if RedisCustomEndpoint == "" { return ` - provider "stackit" { + provider "stackitprivatepreview" { default_region = "eu01" }` } return fmt.Sprintf(` - provider "stackit" { + provider "stackitprivatepreview" { redis_custom_endpoint = "%s" }`, RedisCustomEndpoint, @@ -352,53 +358,56 @@ func RedisProviderConfig() string { } func ResourceManagerProviderConfig() string { - token := GetTestProjectServiceAccountToken("") + key := GetTestProjectServiceAccountJson("") if ResourceManagerCustomEndpoint == "" || AuthorizationCustomEndpoint == "" { return fmt.Sprintf(` - provider "stackit" { - service_account_token = "%s" + provider "stackitprivatepreview" { + service_account_key = "%s" }`, - token, + key, ) } return fmt.Sprintf(` - provider "stackit" { + provider "stackitprivatepreview" { resourcemanager_custom_endpoint = "%s" authorization_custom_endpoint = "%s" service_account_token = "%s" }`, ResourceManagerCustomEndpoint, AuthorizationCustomEndpoint, - token, + key, ) } func SecretsManagerProviderConfig() string { if SecretsManagerCustomEndpoint == "" { return ` - provider "stackit" { + provider "stackitprivatepreview" { default_region = "eu01" }` } return fmt.Sprintf(` - provider "stackit" { + provider "stackitprivatepreview" { secretsmanager_custom_endpoint = "%s" }`, SecretsManagerCustomEndpoint, ) } -func SQLServerFlexProviderConfig() string { +func SQLServerFlexProviderConfig(saFile string) string { if SQLServerFlexCustomEndpoint == "" { - return ` - provider "stackit" { + return fmt.Sprintf(` + provider "stackitprivatepreview" { default_region = "eu01" - }` + service_account_key_path = "%s" + }`, saFile) } return fmt.Sprintf(` - provider "stackit" { + provider "stackitprivatepreview" { + service_account_key_path = "%s" sqlserverflex_custom_endpoint = "%s" }`, + saFile, SQLServerFlexCustomEndpoint, ) } @@ -406,13 +415,13 @@ func SQLServerFlexProviderConfig() string { func ServerBackupProviderConfig() string { if ServerBackupCustomEndpoint == "" { return ` - provider "stackit" { + provider "stackitprivatepreview" { default_region = "eu01" enable_beta_resources = true }` } return fmt.Sprintf(` - provider "stackit" { + provider "stackitprivatepreview" { server_backup_custom_endpoint = "%s" enable_beta_resources = true }`, @@ -423,13 +432,13 @@ func ServerBackupProviderConfig() string { func ServerUpdateProviderConfig() string { if ServerUpdateCustomEndpoint == "" { return ` - provider "stackit" { + provider "stackitprivatepreview" { default_region = "eu01" enable_beta_resources = true }` } return fmt.Sprintf(` - provider "stackit" { + provider "stackitprivatepreview" { server_update_custom_endpoint = "%s" enable_beta_resources = true }`, @@ -440,12 +449,12 @@ func ServerUpdateProviderConfig() string { func SKEProviderConfig() string { if SKECustomEndpoint == "" { return ` - provider "stackit" { + provider "stackitprivatepreview" { default_region = "eu01" }` } return fmt.Sprintf(` - provider "stackit" { + provider "stackitprivatepreview" { ske_custom_endpoint = "%s" }`, SKECustomEndpoint, @@ -455,13 +464,13 @@ func SKEProviderConfig() string { func AuthorizationProviderConfig() string { if AuthorizationCustomEndpoint == "" { return ` - provider "stackit" { + provider "stackitprivatepreview" { default_region = "eu01" experiments = ["iam"] }` } return fmt.Sprintf(` - provider "stackit" { + provider "stackitprivatepreview" { authorization_custom_endpoint = "%s" experiments = ["iam"] }`, @@ -472,13 +481,13 @@ func AuthorizationProviderConfig() string { func ServiceAccountProviderConfig() string { if ServiceAccountCustomEndpoint == "" { return ` - provider "stackit" { + provider "stackitprivatepreview" { default_region = "eu01" enable_beta_resources = true }` } return fmt.Sprintf(` - provider "stackit" { + provider "stackitprivatepreview" { service_account_custom_endpoint = "%s" enable_beta_resources = true }`, @@ -489,13 +498,13 @@ func ServiceAccountProviderConfig() string { func GitProviderConfig() string { if GitCustomEndpoint == "" { return ` - provider "stackit" { + provider "stackitprivatepreview" { default_region = "eu01" enable_beta_resources = true }` } return fmt.Sprintf(` - provider "stackit" { + provider "stackitprivatepreview" { git_custom_endpoint = "%s" enable_beta_resources = true }`, @@ -506,12 +515,12 @@ func GitProviderConfig() string { func ScfProviderConfig() string { if ScfCustomEndpoint == "" { return ` - provider "stackit" { + provider "stackitprivatepreview" { default_region = "eu01" }` } return fmt.Sprintf(` - provider "stackit" { + provider "stackitprivatepreview" { default_region = "eu01" scf_custom_endpoint = "%s" }`, @@ -526,11 +535,11 @@ func ResourceNameWithDateTime(name string) string { return fmt.Sprintf("tf-acc-%s-%s", name, dateTimeTrimmed) } -func GetTestProjectServiceAccountToken(path string) string { +func GetTestProjectServiceAccountJson(path string) string { var err error - token, tokenSet := os.LookupEnv("TF_ACC_TEST_PROJECT_SERVICE_ACCOUNT_TOKEN") + token, tokenSet := os.LookupEnv("TF_ACC_TEST_PROJECT_SERVICE_ACCOUNT_JSON") if !tokenSet || token == "" { - token, err = readTestTokenFromCredentialsFile(path) + token, err = readTestServiceAccountJsonFromFile(path) if err != nil { return "" } @@ -538,11 +547,53 @@ func GetTestProjectServiceAccountToken(path string) string { return token } -func readTestTokenFromCredentialsFile(path string) (string, error) { +//func GetTestProjectServiceAccountToken(path string) string { +// var err error +// token, tokenSet := os.LookupEnv("TF_ACC_TEST_PROJECT_SERVICE_ACCOUNT_TOKEN") +// if !tokenSet || token == "" { +// token, err = readTestTokenFromCredentialsFile(path) +// if err != nil { +// return "" +// } +// } +// return token +//} +// +//func readTestTokenFromCredentialsFile(path string) (string, error) { +// if path == "" { +// customPath, customPathSet := os.LookupEnv("STACKIT_CREDENTIALS_PATH") +// if !customPathSet || customPath == "" { +// path = credentialsFilePath +// home, err := os.UserHomeDir() +// if err != nil { +// return "", fmt.Errorf("getting home directory: %w", err) +// } +// path = filepath.Join(home, path) +// } else { +// path = customPath +// } +// } +// +// credentialsRaw, err := os.ReadFile(path) +// if err != nil { +// return "", fmt.Errorf("opening file: %w", err) +// } +// +// var credentials struct { +// TF_ACC_TEST_PROJECT_SERVICE_ACCOUNT_TOKEN string `json:"TF_ACC_TEST_PROJECT_SERVICE_ACCOUNT_TOKEN"` +// } +// err = json.Unmarshal(credentialsRaw, &credentials) +// if err != nil { +// return "", fmt.Errorf("unmarshalling credentials: %w", err) +// } +// return credentials.TF_ACC_TEST_PROJECT_SERVICE_ACCOUNT_TOKEN, nil +//} + +func readTestServiceAccountJsonFromFile(path string) (string, error) { if path == "" { - customPath, customPathSet := os.LookupEnv("STACKIT_CREDENTIALS_PATH") + customPath, customPathSet := os.LookupEnv("STACKIT_SERVICE_ACCOUNT_PATH") if !customPathSet || customPath == "" { - path = credentialsFilePath + path = serviceAccountFilePath home, err := os.UserHomeDir() if err != nil { return "", fmt.Errorf("getting home directory: %w", err) @@ -557,15 +608,7 @@ func readTestTokenFromCredentialsFile(path string) (string, error) { if err != nil { return "", fmt.Errorf("opening file: %w", err) } - - var credentials struct { - TF_ACC_TEST_PROJECT_SERVICE_ACCOUNT_TOKEN string `json:"TF_ACC_TEST_PROJECT_SERVICE_ACCOUNT_TOKEN"` - } - err = json.Unmarshal(credentialsRaw, &credentials) - if err != nil { - return "", fmt.Errorf("unmarshalling credentials: %w", err) - } - return credentials.TF_ACC_TEST_PROJECT_SERVICE_ACCOUNT_TOKEN, nil + return string(credentialsRaw), nil } func getenv(key, defaultValue string) string { diff --git a/stackit/provider_acc_test.go b/stackit/provider_acc_test.go index cfd6095f..7045874b 100644 --- a/stackit/provider_acc_test.go +++ b/stackit/provider_acc_test.go @@ -5,12 +5,15 @@ package stackit_test import ( _ "embed" "fmt" + "log/slog" "os" "path" "regexp" "runtime" "testing" + "github.com/joho/godotenv" + "github.com/hashicorp/terraform-plugin-testing/config" "github.com/hashicorp/terraform-plugin-testing/helper/acctest" "github.com/hashicorp/terraform-plugin-testing/helper/resource" @@ -31,6 +34,22 @@ var testConfigProviderCredentials = config.Variables{ "name": config.StringVariable(fmt.Sprintf("tf-acc-prov%s", acctest.RandStringFromCharSet(3, acctest.CharSetAlphaNum))), } +func setup() { + err := godotenv.Load() + if err != nil { + slog.Info("could not find .env file - not loading .env") + return + } + slog.Info("loaded .env file") +} + +func TestMain(m *testing.M) { + setup() + code := m.Run() + // shutdown() + os.Exit(code) +} + // Helper function to obtain the home directory on different systems. // Based on os.UserHomeDir(). func getHomeEnvVariableName() string {