diff --git a/.github/actions/clean_up/README.md b/.github/actions/clean_up/README.md new file mode 100644 index 00000000..c3484cf2 --- /dev/null +++ b/.github/actions/clean_up/README.md @@ -0,0 +1 @@ +# acceptance test action diff --git a/.github/actions/clean_up/action.yaml b/.github/actions/clean_up/action.yaml new file mode 100644 index 00000000..1cea3615 --- /dev/null +++ b/.github/actions/clean_up/action.yaml @@ -0,0 +1,168 @@ +name: CleanUp Project Resources +description: "Acceptance Testing CleanUp" + +inputs: + project_id: + description: "STACKIT project ID for tests" + required: true + + region: + description: "STACKIT region for tests" + default: 'eu01' + required: true + + tf_resource_prefix: + description: "prefix in resource names" + default: 'tf-acc-' + required: true + + service_account_json_content: + description: "STACKIT service account JSON file contents" + required: true + default: '' + + service_account_json_content_b64: + description: "STACKIT service account JSON file contents" + required: true + default: '' + + list_only: + description: "only list resources, DO NOT delete" + required: true + default: 'true' + + log_level: + description: "Log Level" + required: true + default: 'warning' + +outputs: + cli-version: + description: "stackit cli version" + value: ${{ steps.stackit_version.outputs.version }} + +runs: + using: "composite" + steps: + - name: Install needed tools + shell: bash + run: | + echo "::group::apt install" + set -e + apt-get -y -qq update >apt_update.log 2>apt_update_err.log + if [ $? -ne 0 ]; then + cat apt_update.log apt_update_err.log + fi + apt-get -y -qq install curl gnupg jq >apt_get.log 2>apt_get_err.log + if [ $? -ne 0 ]; then + cat apt_get.log apt_get_err.log + fi + echo "::endgroup::" + + echo "::group::apt add source" + curl https://packages.stackit.cloud/keys/key.gpg | gpg --dearmor -o /usr/share/keyrings/stackit.gpg + echo "deb [signed-by=/usr/share/keyrings/stackit.gpg] https://packages.stackit.cloud/apt/cli stackit main" | tee -a /etc/apt/sources.list.d/stackit.list + echo "::endgroup::" + + echo "::group::apt install stackit cli" + apt-get -y -qq update >apt_update.log 2>apt_update_err.log + if [ $? -ne 0 ]; then + cat apt_update.log apt_update_err.log + fi + apt-get -y -qq install stackit >apt_get.log 2>apt_get_err.log + if [ $? -ne 0 ]; then + cat apt_get.log apt_get_err.log + fi + echo "::endgroup::" + + - name: Check stackit cli version + id: stackit_version + run: | + set -e + VERSION=$(stackit --version | grep "Version:" | cut -d " " -f 2) + echo "stackit cli version: ${VERSION}" + echo "version=${VERSION}" >> $GITHUB_OUTPUT + shell: bash + + - name: Creating service_account file from json input + if: inputs.service_account_json_content != '' + shell: bash + run: | + echo "::group::create service account file" + set -e + set -o pipefail + + echo "${{ inputs.service_account_json_content }}" > .svc_acc.json + echo "::endgroup::" + + - name: Creating service_account file from base64 json input + if: inputs.service_account_json_content_b64 != '' + shell: bash + run: | + echo "::group::create service account file" + set -e + set -o pipefail + + echo "${{ inputs.service_account_json_content_b64 }}" | base64 -d > .svc_acc.json + echo "::endgroup::" + + - name: Check service account file exists + shell: bash + run: | + set -e + if [[ ! -s .svc_acc.json ]]; then + echo "ERROR: service account file missing or empty" + exit 1 + fi + + - name: Retrieve resources + run: | + echo "::group::retrieve resources" + set -e + echo "authenticating api" + STACKIT_SERVICE_ACCOUNT_KEY_PATH="${PWD}/.svc_acc.json" + export STACKIT_SERVICE_ACCOUNT_KEY_PATH + stackit auth activate-service-account --service-account-key-path .svc_acc.json + + echo "SQL Server Flex resources:" + stackit --verbosity ${{ inputs.log_level }} --project-id "${{ inputs.project_id }}" beta sqlserverflex instance list --output-format json | jq -r '.[] | select(.name | startswith("${{ inputs.tf_resource_prefix }}"))' + + echo "PostgreSQL Flex resources:" + stackit --verbosity ${{ inputs.log_level }} --project-id "${{ inputs.project_id }}" postgresflex instance list --output-format json | jq -r '.[] | select(.name | startswith("${{ inputs.tf_resource_prefix }}"))' + + echo "::endgroup::" + shell: bash + + - name: Delete SQL Server Flex resources + if: ${{ inputs.list_only != 'true' }} + run: | + echo "::group::delete SQL Server Flex resources" + set -e + stackit --verbosity ${{ inputs.log_level }} auth activate-service-account --service-account-key-path .svc_acc.json + for s in $(stackit --verbosity ${{ inputs.log_level }} --project-id ${{ inputs.project_id }} beta sqlserverflex instance list --output-format json | jq -r '.[] | select(.name | startswith("${{ inputs.tf_resource_prefix }}")) | .id'); do stackit --verbosity ${{ inputs.log_level }} -y --project-id ${{ inputs.project_id }} beta sqlserverflex instance delete $s; done + echo "::endgroup::" + shell: bash + + - name: Skip Delete SQL Server Flex resources + if: ${{ inputs.list_only == 'true' }} + run: | + set -e + echo "Skip deleting: list only mode" + shell: bash + + - name: Delete PostgreSQL Flex resources + if: ${{ inputs.list_only != 'true' }} + run: | + echo "::group::delete PostgreSQL Flex resources" + set -e + stackit auth activate-service-account --service-account-key-path .svc_acc.json + for s in $(stackit --verbosity ${{ inputs.log_level }} --project-id ${{ inputs.project_id }} postgresflex instance list --output-format json | jq -r '.[] | select(.name | startswith("${{ inputs.tf_resource_prefix }}")) | .id'); do stackit --verbosity ${{ inputs.log_level }} -y --project-id ${{ inputs.project_id }} postgresflex instance delete $s; done + echo "::endgroup::" + shell: bash + + - name: Skip Delete PostgreSQL Flex resources + if: ${{ inputs.list_only == 'true' }} + run: | + set -e + echo "Skip deleting: list only mode" + shell: bash diff --git a/.github/workflows/ci_new.yaml b/.github/workflows/ci_new.yaml index 9ff6a379..08239560 100644 --- a/.github/workflows/ci_new.yaml +++ b/.github/workflows/ci_new.yaml @@ -28,7 +28,7 @@ jobs: config: if: ${{ github.event_name != 'schedule' }} name: Check GoReleaser config - runs-on: ubuntu-latest + runs-on: stackit-docker steps: - name: Checkout uses: actions/checkout@v6 @@ -40,7 +40,7 @@ jobs: prepare: name: Prepare GO cache - runs-on: ubuntu-latest + runs-on: stackit-docker permissions: actions: read # Required to identify workflow run. checks: write # Required to add status summary. @@ -102,7 +102,7 @@ jobs: needs: - config - prepare - runs-on: ubuntu-latest + runs-on: stackit-docker permissions: actions: read # Required to identify workflow run. checks: write # Required to add status summary. @@ -185,7 +185,7 @@ jobs: testing: name: CI run tests - runs-on: ubuntu-latest + runs-on: stackit-docker needs: - config - prepare @@ -278,7 +278,7 @@ jobs: main: if: ${{ github.event_name != 'schedule' }} name: CI run build and linting - runs-on: ubuntu-latest + runs-on: stackit-docker needs: - config - prepare @@ -329,7 +329,7 @@ jobs: code_coverage: name: "Code coverage report" if: github.event_name == 'pull_request' # Do not run when workflow is triggered by push to main branch - runs-on: ubuntu-latest + runs-on: stackit-docker needs: - main - prepare diff --git a/.github/workflows/clean_up.yaml b/.github/workflows/clean_up.yaml new file mode 100644 index 00000000..4a5b54be --- /dev/null +++ b/.github/workflows/clean_up.yaml @@ -0,0 +1,45 @@ +name: TF Acceptance Test CleanUp + +on: + workflow_dispatch: + inputs: + list_only: + description: "only list resources" + type: boolean + default: true + required: true + + res_prefix: + description: "resource name prefix" + type: string + default: 'tf-acc-' + required: true + + log_level: + description: 'Log Level' + required: true + default: 'warning' + type: choice + options: + - info + - warning + - debug + - error + +jobs: + clean: + name: Clean up + runs-on: stackit-docker + steps: + - name: Checkout + uses: actions/checkout@v6 + + - name: Clean + uses: ./.github/actions/clean_up + with: + project_id: ${{ vars.TF_ACC_PROJECT_ID }} + region: 'eu01' + tf_resource_prefix: ${{ inputs.res_prefix }} + service_account_json_content_b64: "${{ secrets.TF_ACC_SERVICE_ACCOUNT_JSON_B64 }}" + list_only: ${{ inputs.list_only }} + log_level: ${{ inputs.log_level }} diff --git a/.github/workflows/publish.yaml b/.github/workflows/publish.yaml index 8a277b91..633953f4 100644 --- a/.github/workflows/publish.yaml +++ b/.github/workflows/publish.yaml @@ -4,9 +4,10 @@ run-name: Publish by @${{ github.actor }} on: workflow_dispatch: + push: tags: - - 'v0.*' + - 'v*' env: GO_VERSION: "1.25" @@ -16,7 +17,6 @@ env: jobs: config: name: Check GoReleaser config - if: github.event_name == 'push' && contains(github.ref, 'refs/tags/') runs-on: ubuntu-latest steps: - name: Checkout @@ -29,13 +29,12 @@ jobs: publish: name: "Publish provider" - if: github.event_name == 'push' && contains(github.ref, 'refs/tags/') needs: config runs-on: ubuntu-latest permissions: actions: read # Required to identify workflow run. checks: write # Required to add status summary. - contents: read # Required to checkout repository. + contents: write # Required to checkout repository. pull-requests: write # Required to add PR comment. steps: - name: Install needed tools @@ -45,6 +44,8 @@ jobs: - name: Checkout uses: actions/checkout@v6 + with: + fetch-tags: true - name: Setup Go uses: actions/setup-go@v6 @@ -82,7 +83,7 @@ jobs: gpg --import ~/private.key.pem rm ~/private.key.pem - - name: Run GoReleaser with SNAPSHOT + - name: Run GoReleaser if: github.event_name == 'workflow_dispatch' id: goreleaser env: @@ -90,7 +91,8 @@ jobs: GPG_FINGERPRINT: ${{ secrets.GPG_FINGERPRINT }} uses: goreleaser/goreleaser-action@v7 with: - args: release --skip publish --clean --snapshot +# args: release --skip publish --clean --snapshot + args: release --skip publish --clean - name: Run GoReleaser if: github.event_name != 'workflow_dispatch' @@ -106,9 +108,15 @@ jobs: run: | echo "${{ secrets.PUBLIC_KEY_PEM }}" >public_key.pem + - name: Determine version + id: get_version + run: | + set -e + VERSION=$(jq -r .version < dist/metadata.json) + echo "version=${VERSION}" >> "$GITHUB_OUTPUT" + - name: Prepare provider directory structure run: | - VERSION=$(jq -r .version < dist/metadata.json) go run generator/main.go \ publish \ --namespace=mhenselin \ @@ -117,7 +125,7 @@ jobs: --domain=tfregistry.sysops.stackit.rocks \ --gpgFingerprint="${{ secrets.GPG_FINGERPRINT }}" \ --gpgPubKeyFile=public_key.pem \ - --version=${VERSION} + --version=${{ steps.get_version.outputs.version }} - name: Prepare documentation nav file run: | @@ -142,6 +150,7 @@ jobs: run: | set -e ssh -o StrictHostKeyChecking=no ubuntu@${{ vars.DOCS_SERVER_IP }} 'rm -rf /srv/www/docs' - echo "${{ github.ref_name }}" >docs/_version.txt + echo "${{ steps.get_version.outputs.version }}" >docs/_version.txt + # echo "${{ github.ref_name }}" >docs/_version.txt scp -o StrictHostKeyChecking=no -r docs ubuntu@${{ vars.DOCS_SERVER_IP }}:/srv/www/ scp -o StrictHostKeyChecking=no nav.md ubuntu@${{ vars.DOCS_SERVER_IP }}:/srv/www/ diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 79547c9a..d2dec624 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -16,14 +16,14 @@ permissions: jobs: goreleaser: - runs-on: ubuntu-latest + runs-on: stackit-docker steps: - uses: actions/checkout@v6 with: # Allow goreleaser to access older tag information. fetch-depth: 0 - - uses: https://code.forgejo.org/actions/setup-go@v6 + - uses: actions/setup-go@v6 with: go-version-file: "go.mod" cache: true diff --git a/.github/workflows/renovate.yaml b/.github/workflows/renovate.yaml index c629eab0..67c33d1b 100644 --- a/.github/workflows/renovate.yaml +++ b/.github/workflows/renovate.yaml @@ -8,13 +8,13 @@ on: jobs: renovate: name: Renovate - runs-on: ubuntu-latest + runs-on: stackit-docker steps: - name: Checkout uses: actions/checkout@v6 - name: Self-hosted Renovate - uses: renovatebot/github-action@v46.1.4 + uses: renovatebot/github-action@v46.1.5 with: configurationFile: .github/renovate.json # token: ${{ secrets.RENOVATE_TOKEN }} diff --git a/.github/workflows/stale.yaml b/.github/workflows/stale.yaml index 6198123e..32b39b56 100644 --- a/.github/workflows/stale.yaml +++ b/.github/workflows/stale.yaml @@ -20,7 +20,7 @@ permissions: jobs: stale: name: "Stale" - runs-on: ubuntu-latest + runs-on: stackit-docker timeout-minutes: 10 steps: - name: "Mark old PRs as stale" diff --git a/.github/workflows/tf-acc-test.yaml b/.github/workflows/tf-acc-test.yaml index 75a35382..473ad815 100644 --- a/.github/workflows/tf-acc-test.yaml +++ b/.github/workflows/tf-acc-test.yaml @@ -13,17 +13,19 @@ on: inputs: enable_debug: description: "enable terraform debug logs" - default: 'false' + type: boolean + default: false required: true test_timeout_string: description: "string that determines the timeout (default: 45m)" + type: string default: '90m' required: true jobs: acc_test: name: Acceptance Tests - runs-on: ubuntu-latest + runs-on: stackit-docker steps: - name: Checkout uses: actions/checkout@v6 @@ -57,4 +59,3 @@ jobs: tf_acc_kek_key_ring_id: ${{ vars.TF_ACC_KEK_KEY_RING_ID }} tf_acc_kek_key_version: ${{ vars.TF_ACC_KEK_KEY_VERSION }} tf_acc_kek_service_account: ${{ vars.TF_ACC_KEK_SERVICE_ACCOUNT }} - tf_debug: ${{ inputs.enable_debug }} diff --git a/README.md b/README.md index ab79f28e..b90466b9 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ terraform { required_providers { stackitprivatepreview = { source = "tfregistry.sysops.stackit.rocks/mhenselin/stackitprivatepreview" - version = "= 0.0.5-alpha" + version = ">= 0.1.0" } } } @@ -38,7 +38,6 @@ Check one of the examples in the [examples](examples/) folder. To authenticate, you will need a [service account](https://docs.stackit.cloud/platform/access-and-identity/service-accounts/). Create it in the [STACKIT Portal](https://portal.stackit.cloud/) and assign the necessary permissions to it, e.g. `project.owner`. There are multiple ways to authenticate: - Key flow (recommended) -- Token flow (is scheduled for deprecation and will be removed on December 17, 2025.) When setting up authentication, the provider will always try to use the key flow first and search for credentials in several locations, following a specific order: @@ -52,7 +51,6 @@ When setting up authentication, the provider will always try to use the key flow ```json { - "STACKIT_SERVICE_ACCOUNT_TOKEN": "foo_token", "STACKIT_SERVICE_ACCOUNT_KEY_PATH": "path/to/sa_key.json" } ``` @@ -71,35 +69,41 @@ To configure the key flow, follow this steps: 1. Create a service account key: -- Use the [STACKIT Portal](https://portal.stackit.cloud/): go to the `Service Accounts` tab, choose a `Service Account` and go to `Service Account Keys` to create a key. For more details, see [Create a service account key](https://docs.stackit.cloud/platform/access-and-identity/service-accounts/how-tos/manage-service-account-keys/) + - Use the [STACKIT Portal](https://portal.stackit.cloud/): go to the `Service Accounts` tab, choose a `Service Account` and go to `Service Account Keys` to create a key. For more details, see [Create a service account key](https://docs.stackit.cloud/platform/access-and-identity/service-accounts/how-tos/manage-service-account-keys/) 2. Save the content of the service account key by copying it and saving it in a JSON file. The expected format of the service account key is a **JSON** with the following structure: -```json -{ - "id": "uuid", - "publicKey": "public key", - "createdAt": "2023-08-24T14:15:22Z", - "validUntil": "2023-08-24T14:15:22Z", - "keyType": "USER_MANAGED", - "keyOrigin": "USER_PROVIDED", - "keyAlgorithm": "RSA_2048", - "active": true, - "credentials": { - "kid": "string", - "iss": "my-sa@sa.stackit.cloud", - "sub": "uuid", - "aud": "string", - (optional) "privateKey": "private key when generated by the SA service" - } -} -``` + ```json + { + "id": "uuid", + "publicKey": "public key", + "createdAt": "2023-08-24T14:15:22Z", + "validUntil": "2023-08-24T14:15:22Z", + "keyType": "USER_MANAGED", + "keyOrigin": "USER_PROVIDED", + "keyAlgorithm": "RSA_2048", + "active": true, + "credentials": { + "kid": "string", + "iss": "my-sa@sa.stackit.cloud", + "sub": "uuid", + "aud": "string", + (optional) "privateKey": "private key when generated by the SA service" + } + } + ``` 3. Configure the service account key for authentication in the provider by following one of the alternatives below: - setting the fields in the provider block: `service_account_key` or `service_account_key_path` + ```hcl + provider "stackitprivatepreview" { + default_region = "eu01" + service_account_key_path = "../service_account.json" + } + ``` - setting the environment variable: `STACKIT_SERVICE_ACCOUNT_KEY_PATH` or `STACKIT_SERVICE_ACCOUNT_KEY` - ensure the set the service account key in `STACKIT_SERVICE_ACCOUNT_KEY` is correctly formatted. Use e.g. `$ export STACKIT_SERVICE_ACCOUNT_KEY=$(cat ./service-account-key.json)` @@ -111,16 +115,6 @@ To configure the key flow, follow this steps: > - setting the environment variable: `STACKIT_PRIVATE_KEY_PATH` or `STACKIT_PRIVATE_KEY` > - setting `STACKIT_PRIVATE_KEY_PATH` in the credentials file (see above) -### Token flow - -> Is scheduled for deprecation and will be removed on December 17, 2025. - -Using this flow is less secure since the token is long-lived. You can provide the token in several ways: - -1. Setting the field `service_account_token` in the provider -2. Setting the environment variable `STACKIT_SERVICE_ACCOUNT_TOKEN` -3. Setting it in the credentials file (see above) - ## Backend configuration To keep track of your terraform state, you can configure an [S3 backend](https://developer.hashicorp.com/terraform/language/settings/backends/s3) using [STACKIT Object Storage](https://docs.stackit.cloud/products/storage/object-storage). @@ -150,62 +144,6 @@ terraform { Note: AWS specific checks must be skipped as they do not work on STACKIT. For details on what those validations do, see [here](https://developer.hashicorp.com/terraform/language/settings/backends/s3#configuration). -## Opting into Beta Resources - -To use beta resources in the STACKIT Terraform provider, follow these steps: - -1. **Provider Configuration Option** - - Set the `enable_beta_resources` option in the provider configuration. This is a boolean attribute that can be either `true` or `false`. - - ```hcl - provider "stackit" { - default_region = "eu01" - enable_beta_resources = true - } - ``` - -2. **Environment Variable** - - Set the `STACKIT_TF_ENABLE_BETA_RESOURCES` environment variable to `"true"` or `"false"`. Other values will be ignored and will produce a warning. - - ```sh - export STACKIT_TF_ENABLE_BETA_RESOURCES=true - ``` - -> **Note**: The environment variable takes precedence over the provider configuration option. This means that if the `STACKIT_TF_ENABLE_BETA_RESOURCES` environment variable is set to a valid value (`"true"` or `"false"`), it will override the `enable_beta_resources` option specified in the provider configuration. - -For more details, please refer to the [beta resources configuration guide](https://registry.terraform.io/providers/stackitcloud/stackit/latest/docs/guides/opting_into_beta_resources). - -## Opting into Experiments - -Experiments are features that are even less mature and stable than Beta Resources. While there is some assumed stability in beta resources, will have to expect breaking changes while using experimental resources. Experimental Resources do not come with any support or warranty. - -To enable experiments set the experiments field in the provider definition: - -```hcl -provider "stackit" { - default_region = "eu01" - experiments = ["iam", "routing-tables", "network"] -} -``` - -### Available Experiments - -#### `iam` - -Enables IAM management features in the Terraform provider. The underlying IAM API is expected to undergo a redesign in the future, which leads to it being considered experimental. - -#### `routing-tables` - -This feature enables experimental routing table capabilities in the Terraform Provider, available only to designated SNAs at this time. - -#### `network` - -The `stackit_network` provides the fields `region` and `routing_table_id` when the experiment flag `network` is set. -The underlying API is not stable yet and could change in the future. -If you don't need these fields, don't set the experiment flag `network`, to use the stable api. - ## Acceptance Tests > [!WARNING] diff --git a/sample/alpha-from-registry/key.tf b/sample/alpha-from-registry/key.tf new file mode 100644 index 00000000..8be28ac7 --- /dev/null +++ b/sample/alpha-from-registry/key.tf @@ -0,0 +1,38 @@ +resource "stackit_kms_keyring" "mshalpha-keyring" { + project_id = var.project_id + display_name = "msh-alpha-tests" + description = "This is a test keyring for private endpoints" +} + +resource "stackit_kms_key" "mshalpha-key01" { + project_id = var.project_id + keyring_id = stackit_kms_keyring.mshalpha-keyring.keyring_id + display_name = "mshalpha-key01" + protection = "software" + algorithm = "aes_256_gcm" + purpose = "symmetric_encrypt_decrypt" + access_scope = "SNA" +} + +output "keyid" { + value = stackit_kms_key.mshalpha-key01.key_id +} + +# (because stackit_kms_key.key001 is not in configuration) +resource "stackit_kms_key" "key001" { + access_scope = "SNA" + algorithm = "aes_256_gcm" + display_name = "msh-key-sna01" + keyring_id = stackit_kms_keyring.keyring001.keyring_id + project_id = var.project_id + protection = "software" + purpose = "symmetric_encrypt_decrypt" +} + +# stackit_kms_keyring.keyring001 will be destroyed +# (because stackit_kms_keyring.keyring001 is not in configuration) +resource "stackit_kms_keyring" "keyring001" { + description = "This is a test keyring for private endpoints" + display_name = "msh-keyring-sna01" + project_id = var.project_id +} diff --git a/sample/alpha-from-registry/postresql.tf b/sample/alpha-from-registry/postresql.tf new file mode 100644 index 00000000..0e728f81 --- /dev/null +++ b/sample/alpha-from-registry/postresql.tf @@ -0,0 +1,96 @@ + +data "stackitprivatepreview_postgresflexalpha_flavor" "pgsql_flavor" { + project_id = var.project_id + region = "eu01" + cpu = 2 + ram = 4 + node_type = "Single" + storage_class = "premium-perf2-stackit" +} + +resource "stackitprivatepreview_postgresflexalpha_instance" "msh-alpha-sna-enc" { + project_id = var.project_id + name = "msh-alpha-sna-enc" + backup_schedule = "0 0 * * *" + retention_days = 45 + flavor_id = data.stackitprivatepreview_postgresflexalpha_flavor.pgsql_flavor.flavor_id + replicas = 1 + storage = { + performance_class = "premium-perf2-stackit" + size = 10 + } + encryption = { + kek_key_id = stackit_kms_key.mshalpha-key01.key_id + kek_key_ring_id = stackit_kms_keyring.mshalpha-keyring.keyring_id + kek_key_version = 1 + service_account = var.sa_email + } + network = { + acl = ["0.0.0.0/0", "193.148.160.0/19", "170.85.2.177/32"] + access_scope = "SNA" + } + version = 17 +} + +resource "stackitprivatepreview_postgresflexalpha_instance" "msh-alpha-nosna-noenc" { + project_id = var.project_id + name = "msh-alpha-nosna-enc" + backup_schedule = "0 0 * * *" + retention_days = 45 + flavor_id = data.stackitprivatepreview_postgresflexalpha_flavor.pgsql_flavor.flavor_id + replicas = 1 + storage = { + performance_class = "premium-perf2-stackit" + size = 10 + } + network = { + acl = ["0.0.0.0/0", "193.148.160.0/19", "170.85.2.177/32"] + access_scope = "PUBLIC" + } + version = 16 +} + +resource "stackitprivatepreview_postgresflexalpha_user" "ptlsdbadminuser" { + project_id = var.project_id + instance_id = stackitprivatepreview_postgresflexalpha_instance.msh-alpha-sna-enc.instance_id + name = var.db_admin_username + roles = ["createdb", "login"] + # roles = ["createdb", "login", "createrole"] +} + +resource "stackitprivatepreview_postgresflexalpha_user" "ptlsdbuser" { + project_id = var.project_id + instance_id = stackitprivatepreview_postgresflexalpha_instance.msh-alpha-sna-enc.instance_id + name = var.db_username + roles = ["login"] + # roles = ["createdb", "login", "createrole"] +} + +resource "stackitprivatepreview_postgresflexalpha_database" "example" { + count = 5 + depends_on = [stackitprivatepreview_postgresflexalpha_user.ptlsdbadminuser] + project_id = var.project_id + instance_id = stackitprivatepreview_postgresflexalpha_instance.msh-alpha-sna-enc.instance_id + name = "${var.db_name}${count.index}" + owner = var.db_admin_username +} + +# data "stackitprivatepreview_postgresflexalpha_instance" "datapsql" { +# project_id = var.project_id +# instance_id = var.instance_id +# region = "eu01" +# } + +# output "psql_instance_id" { +# value = data.stackitprivatepreview_postgresflexalpha_instance.datapsql.instance_id +# } + +output "psql_user_password" { + value = stackitprivatepreview_postgresflexalpha_user.ptlsdbuser.password + sensitive = true +} + +# output "psql_user_conn" { +# value = stackitprivatepreview_postgresflexalpha_user.ptlsdbuser.connection_string +# sensitive = true +# } diff --git a/sample/alpha-from-registry/providers.tf b/sample/alpha-from-registry/providers.tf new file mode 100644 index 00000000..66756cd7 --- /dev/null +++ b/sample/alpha-from-registry/providers.tf @@ -0,0 +1,24 @@ + +terraform { + required_providers { + stackit = { + source = "registry.terraform.io/stackitcloud/stackit" + version = "~> 0.70" + } + stackitprivatepreview = { + source = "tfregistry.sysops.stackit.rocks/mhenselin/stackitprivatepreview" + version = ">=0.1.0" + } + } +} + +provider "stackit" { + default_region = "eu01" + enable_beta_resources = true + service_account_key_path = "../service_account.json" +} + +provider "stackitprivatepreview" { + default_region = "eu01" + service_account_key_path = "../service_account.json" +} diff --git a/sample/alpha-from-registry/sqlserver.tf b/sample/alpha-from-registry/sqlserver.tf new file mode 100644 index 00000000..2bf17a9e --- /dev/null +++ b/sample/alpha-from-registry/sqlserver.tf @@ -0,0 +1,101 @@ +# resource "stackit_kms_keyring" "keyring001" { +# project_id = var.project_id +# display_name = "msh-keyring-sna01" +# description = "This is a test keyring for private endpoints" +# } +# +# resource "stackit_kms_key" "key001" { +# project_id = var.project_id +# keyring_id = stackit_kms_keyring.keyring001.keyring_id +# display_name = "msh-key-sna01" +# protection = "software" +# algorithm = "aes_256_gcm" +# purpose = "symmetric_encrypt_decrypt" +# access_scope = "SNA" +# } + +data "stackitprivatepreview_sqlserverflexbeta_flavor" "sqlserver_flavor" { + project_id = var.project_id + region = "eu01" + cpu = 4 + ram = 16 + node_type = "Single" + storage_class = "premium-perf2-stackit" +} + +resource "stackitprivatepreview_sqlserverflexbeta_instance" "msh-sna-001" { + project_id = var.project_id + name = "msh-sna-001" + backup_schedule = "0 3 * * *" + retention_days = 31 + flavor_id = data.stackitprivatepreview_sqlserverflexbeta_flavor.sqlserver_flavor.flavor_id + storage = { + class = "premium-perf2-stackit" + size = 50 + } + version = 2022 + encryption = { + kek_key_version = 1 + kek_key_id = var.key_id + kek_key_ring_id = var.keyring_id + service_account = var.sa_email + } + network = { + acl = ["0.0.0.0/0", "193.148.160.0/19"] + access_scope = "SNA" + } +} + +#resource "stackitprivatepreview_sqlserverflexbeta_instance" "msh-nosna-001" { +# project_id = var.project_id +# name = "msh-nosna-001" +# backup_schedule = "0 3 * * *" +# retention_days = 31 +# flavor_id = data.stackitprivatepreview_sqlserverflexbeta_flavor.sqlserver_flavor.flavor_id +# storage = { +# class = "premium-perf2-stackit" +# size = 50 +# } +# version = 2022 +# # encryption = { +# # #key_id = stackit_kms_key.key.key_id +# # #keyring_id = stackit_kms_keyring.keyring.keyring_id +# # #key_version = 1 +# # #key_id = var.key_id +# # # key with scope public +# # key_id = "fe039bcf-8d7b-431a-801d-9e81371a6b7b" +# # keyring_id = var.keyring_id +# # key_version = var.key_version +# # service_account = var.sa_email +# # } +# network = { +# acl = ["0.0.0.0/0", "193.148.160.0/19"] +# access_scope = "PUBLIC" +# } +#} + +# data "stackitprivatepreview_sqlserverflexbeta_instance" "test" { +# project_id = var.project_id +# instance_id = var.instance_id +# region = "eu01" +# } + +# output "test" { +# value = data.stackitprivatepreview_sqlserverflexbeta_instance.test +# } + +resource "stackitprivatepreview_sqlserverflexbeta_user" "ptlsdbadminuser" { + project_id = var.project_id + instance_id = stackitprivatepreview_sqlserverflexbeta_instance.msh-sna-001.instance_id + username = var.db_admin_username + #roles = ["##STACKIT_LoginManager##", "##STACKIT_DatabaseManager##"] + roles = ["##STACKIT_LoginManager##"] +} + +resource "stackitprivatepreview_sqlserverflexbeta_user" "ptlsdbuser" { + project_id = var.project_id + instance_id = stackitprivatepreview_sqlserverflexbeta_instance.msh-sna-001.instance_id + username = var.db_username + roles = ["##STACKIT_LoginManager##"] +} + diff --git a/sample/kms/kms.tf b/sample/kms/kms.tf new file mode 100644 index 00000000..01b1d46c --- /dev/null +++ b/sample/kms/kms.tf @@ -0,0 +1,57 @@ +resource "stackit_kms_keyring" "keyring001" { + project_id = var.project_id + display_name = "msh-keyring-sna01" + description = "This is a test keyring for private endpoints" +} + +resource "stackit_kms_key" "key001" { + project_id = var.project_id + keyring_id = stackit_kms_keyring.keyring001.keyring_id + display_name = "msh-key-sna01" + protection = "software" + algorithm = "aes_256_gcm" + purpose = "symmetric_encrypt_decrypt" + access_scope = "SNA" +} + + +# data "stackitprivatepreview_sqlserverflexalpha_instance" "test" { +# project_id = var.project_id +# instance_id = var.instance_id +# region = "eu01" +# } + +output "key_ring_id" { + value = stackit_kms_keyring.keyring001.id +} + +resource "stackit_kms_keyring" "keyring001yy" { + project_id = var.project_id + display_name = "msh-kr-sna01" + description = "This is a test keyring for private endpoints" +} + +resource "stackit_kms_key" "key001yy" { + project_id = var.project_id + keyring_id = stackit_kms_keyring.keyring001yy.keyring_id + display_name = "msh-k-001" + protection = "software" + algorithm = "aes_256_gcm" + purpose = "symmetric_encrypt_decrypt" + access_scope = "SNA" +} + + +# data "stackitprivatepreview_sqlserverflexalpha_instance" "test" { +# project_id = var.project_id +# instance_id = var.instance_id +# region = "eu01" +# } + +output "key_ring_idxx" { + value = stackit_kms_keyring.keyring001yy.id +} + +output "key_id" { + value = stackit_kms_key.key001yy.id +} diff --git a/sample/kms/providers.tf b/sample/kms/providers.tf new file mode 100644 index 00000000..1e7fe4f5 --- /dev/null +++ b/sample/kms/providers.tf @@ -0,0 +1,25 @@ + +terraform { + required_providers { + stackit = { + source = "registry.terraform.io/stackitcloud/stackit" + version = "~> 0.70" + } + # stackitprivatepreview = { + # source = "tfregistry.sysops.stackit.rocks/mhenselin/stackitprivatepreview" + # version = "= 0.0.2-alpha" + # } + } +} + +provider "stackit" { + default_region = "eu01" + enable_beta_resources = true + service_account_key_path = "../service_account.json" +} + +# provider "stackitprivatepreview" { +# default_region = "eu01" +# enable_beta_resources = true +# service_account_key_path = "../service_account.json" +# } diff --git a/sample/pg_import/outputs.tf b/sample/pg_import/outputs.tf new file mode 100644 index 00000000..d9edf19a --- /dev/null +++ b/sample/pg_import/outputs.tf @@ -0,0 +1,4 @@ +# +# output "postgres_flavor" { +# value = data.stackitprivatepreview_postgresflexalpha_flavor.pgsql_flavor.flavor_id +# } diff --git a/sample/pg_import/postresql.tf b/sample/pg_import/postresql.tf new file mode 100644 index 00000000..1d8d478d --- /dev/null +++ b/sample/pg_import/postresql.tf @@ -0,0 +1,45 @@ + +data "stackitprivatepreview_postgresflexalpha_flavor" "pgsql_flavor" { + project_id = var.project_id + region = "eu01" + cpu = 2 + ram = 4 + node_type = "Single" + storage_class = "premium-perf2-stackit" +} + +resource "stackitprivatepreview_postgresflexalpha_instance" "import_for_deletion" { + project_id = var.project_id + name = "mshpetest2" + backup_schedule = "0 0 * * *" + retention_days = 45 + flavor_id = data.stackitprivatepreview_postgresflexalpha_flavor.pgsql_flavor.flavor_id + replicas = 1 + storage = { + # class = "premium-perf2-stackit" + performance_class = "premium-perf2-stackit" + size = 10 + } + encryption = { + # key_id = stackit_kms_key.key.key_id + # keyring_id = stackit_kms_keyring.keyring.keyring_id + kek_key_id = var.key_id + kek_key_ring_id = var.keyring_id + kek_key_version = var.key_version + service_account = var.sa_email + } + network = { + acl = ["0.0.0.0/0", "193.148.160.0/19", "170.85.2.177/32"] + access_scope = "PUBLIC" + } + version = 14 +} + +import { + to = stackitprivatepreview_postgresflexalpha_instance.import_for_deletion + identity = { + project_id = var.project_id + region = "eu01" + instance_id = "d52b5d4c-be3f-4c14-a107-330dab99fd2e" + } +} diff --git a/sample/pg_import/providers.tf b/sample/pg_import/providers.tf new file mode 100644 index 00000000..5a54a129 --- /dev/null +++ b/sample/pg_import/providers.tf @@ -0,0 +1,25 @@ + +terraform { + required_providers { + # stackit = { + # source = "registry.terraform.io/stackitcloud/stackit" + # version = "~> 0.70" + # } + stackitprivatepreview = { + source = "tfregistry.sysops.stackit.rocks/mhenselin/stackitprivatepreview" + version = "> 0.0" + } + } +} + +# provider "stackit" { +# default_region = "eu01" +# enable_beta_resources = true +# service_account_key_path = "./service_account.json" +# } + +provider "stackitprivatepreview" { + default_region = "eu01" + enable_beta_resources = true + service_account_key_path = "../service_account.json" +} diff --git a/sample/pg_import/variables.tf.example b/sample/pg_import/variables.tf.example new file mode 100644 index 00000000..51a70be4 --- /dev/null +++ b/sample/pg_import/variables.tf.example @@ -0,0 +1,11 @@ +variable "project_id" { + default = "" +} + +variable "sa_email" { + default = "" +} + +variable "db_username" { + default = "" +} diff --git a/sample/pg_instance/outputs.tf b/sample/pg_instance/outputs.tf new file mode 100644 index 00000000..e69de29b diff --git a/sample/pg_instance/postresql.tf b/sample/pg_instance/postresql.tf new file mode 100644 index 00000000..0f3f73ac --- /dev/null +++ b/sample/pg_instance/postresql.tf @@ -0,0 +1,17 @@ + +data "stackitprivatepreview_postgresflexalpha_flavor" "pgsql_flavor" { + project_id = var.project_id + region = "eu01" + cpu = 2 + ram = 4 + node_type = "Single" + storage_class = "premium-perf2-stackit" +} +data "stackitprivatepreview_postgresflexalpha_flavor" "pgsql_flavor2"{ + project_id = var.project_id + region = "eu01" + cpu = 2 + ram = 4 + node_type = "Single" + storage_class = "premium-perf2-stackit" +} diff --git a/sample/pg_instance/providers.tf b/sample/pg_instance/providers.tf new file mode 100644 index 00000000..f69b01a1 --- /dev/null +++ b/sample/pg_instance/providers.tf @@ -0,0 +1,25 @@ + +terraform { + required_providers { + # stackit = { + # source = "registry.terraform.io/stackitcloud/stackit" + # version = "~> 0.70" + # } + stackitprivatepreview = { + source = "tfregistry.sysops.stackit.rocks/mhenselin/stackitprivatepreview" + version = "> 0.0" + } + } +} + +# provider "stackit" { +# default_region = "eu01" +# enable_beta_resources = true +# service_account_key_path = "./service_account.json" +# } + +provider "stackitprivatepreview" { + default_region = "eu01" + enable_beta_resources = true + service_account_key_path = "/home/henselinm/Development/PTLS/terraform-provider-stackit-MSH/sample/pg_instance/service_account.json" +} diff --git a/sample/pg_instance/variables.tf.example b/sample/pg_instance/variables.tf.example new file mode 100644 index 00000000..51a70be4 --- /dev/null +++ b/sample/pg_instance/variables.tf.example @@ -0,0 +1,11 @@ +variable "project_id" { + default = "" +} + +variable "sa_email" { + default = "" +} + +variable "db_username" { + default = "" +} diff --git a/sample/sqlserver_beta/flavor.tf b/sample/sqlserver_beta/flavor.tf new file mode 100644 index 00000000..df6f3305 --- /dev/null +++ b/sample/sqlserver_beta/flavor.tf @@ -0,0 +1,13 @@ +# +# data "stackitprivatepreview_sqlserverflexalpha_flavor" "sqlserver_flavor" { +# project_id = var.project_id +# region = "eu01" +# cpu = 4 +# ram = 16 +# node_type = "Single" +# storage_class = "premium-perf2-stackit" +# } +# +# output "sqlserver_flavor" { +# value = data.stackitprivatepreview_sqlserverflexalpha_flavor.sqlserver_flavor.flavor_id +# } diff --git a/sample/sqlserver_beta/postgres.tf b/sample/sqlserver_beta/postgres.tf new file mode 100644 index 00000000..0f45ff66 --- /dev/null +++ b/sample/sqlserver_beta/postgres.tf @@ -0,0 +1,9 @@ + +data "stackitprivatepreview_postgresflexalpha_flavor" "pgsql_flavor" { + project_id = var.project_id + region = "eu01" + cpu = 2 + ram = 4 + node_type = "Single" + storage_class = "premium-perf2-stackit" +} diff --git a/sample/sqlserver_beta/providers.tf b/sample/sqlserver_beta/providers.tf new file mode 100644 index 00000000..233d4df2 --- /dev/null +++ b/sample/sqlserver_beta/providers.tf @@ -0,0 +1,25 @@ + +terraform { + required_providers { + # stackit = { + # source = "registry.terraform.io/stackitcloud/stackit" + # version = "~> 0.70" + # } + stackitprivatepreview = { + source = "tfregistry.sysops.stackit.rocks/mhenselin/stackitprivatepreview" + version = "> 0.0" + } + } +} + +# provider "stackit" { +# default_region = "eu01" +# enable_beta_resources = true +# service_account_key_path = "../service_account.json" +# } + +provider "stackitprivatepreview" { + default_region = "eu01" + enable_beta_resources = true + service_account_key_path = "../service_account.json" +} diff --git a/sample/sqlserver_beta/sqlserver.tf b/sample/sqlserver_beta/sqlserver.tf new file mode 100644 index 00000000..21bf7d23 --- /dev/null +++ b/sample/sqlserver_beta/sqlserver.tf @@ -0,0 +1,116 @@ +data "stackitprivatepreview_sqlserverflexbeta_flavor" "sqlserver_flavor" { + project_id = var.project_id + region = "eu01" + cpu = 4 + ram = 16 + node_type = "Single" + storage_class = "premium-perf2-stackit" +} + +data "stackitprivatepreview_sqlserverflexbeta_flavor" "sqlserver_flavor_2" { + project_id = var.project_id + region = "eu01" + cpu = 4 + ram = 32 + node_type = "Replica" + storage_class = "premium-perf2-stackit" +} + +resource "stackitprivatepreview_sqlserverflexbeta_instance" "msh-beta-nosna-001" { + project_id = var.project_id + name = "msh-beta-nosna-001-renamed" + backup_schedule = "0 3 * * *" + retention_days = 31 + flavor_id = data.stackitprivatepreview_sqlserverflexbeta_flavor.sqlserver_flavor.flavor_id + storage = { + class = "premium-perf2-stackit" + size = 50 + } + version = 2022 + network = { + acl = ["0.0.0.0/0", "193.148.160.0/19"] + access_scope = "PUBLIC" + } +} + +resource "stackitprivatepreview_sqlserverflexbeta_instance" "msh-beta-sna-001" { + project_id = var.project_id + name = "msh-beta-sna-001" + backup_schedule = "0 3 * * *" + retention_days = 31 + flavor_id = data.stackitprivatepreview_sqlserverflexbeta_flavor.sqlserver_flavor.flavor_id + storage = { + class = "premium-perf2-stackit" + size = 5 + } + version = 2022 + encryption = { + #key_id = stackit_kms_key.key.key_id + #keyring_id = stackit_kms_keyring.keyring.keyring_id + #key_version = 1 + # key with scope public + kek_key_id = "fe039bcf-8d7b-431a-801d-9e81371a6b7b" + # key_id = var.key_id + kek_key_ring_id = var.keyring_id + kek_key_version = var.key_version + service_account = var.sa_email + } + network = { + acl = ["0.0.0.0/0", "193.148.160.0/19"] + access_scope = "SNA" + } +} + +resource "stackitprivatepreview_sqlserverflexbeta_user" "exampleuseruno" { + project_id = var.project_id + instance_id = stackitprivatepreview_sqlserverflexbeta_instance.msh-beta-nosna-001.instance_id + username = "exampleuserdue" + roles = ["##STACKIT_ProcessManager##", "##STACKIT_LoginManager##", "##STACKIT_ServerManager##"] +} + +resource "stackitprivatepreview_sqlserverflexbeta_user" "exampleuser" { + project_id = var.project_id + instance_id = stackitprivatepreview_sqlserverflexbeta_instance.msh-beta-nosna-001.instance_id + username = "exampleuser" + roles = ["##STACKIT_LoginManager##"] +} + + +resource "stackitprivatepreview_sqlserverflexbeta_database" "mshtest002" { + project_id = var.project_id + instance_id = stackitprivatepreview_sqlserverflexbeta_instance.msh-beta-nosna-001.instance_id + name = "mshtest002" + # owner = "dbuser" + owner = stackitprivatepreview_sqlserverflexbeta_user.exampleuseruno.username +} + + +# data "stackitprivatepreview_sqlserverflexbeta_database" "example" { +# project_id = var.project_id +# region = "eu01" +# instance_id = "b3b63d0c-35bf-4804-84ea-5abec2a8ae58" +# database_name = "mshtest001" +# } + +# output "dbdetails" { +# value = data.stackitprivatepreview_sqlserverflexbeta_database.example +# } +# + + +# resource "stackitprivatepreview_sqlserverflexbeta_database" "mshtest" { +# project_id = var.project_id +# instance_id = "b3b63d0c-35bf-4804-84ea-5abec2a8ae58" +# name = "mshtest" +# owner = "dbuser" +# } +# +# import { +# to = stackitprivatepreview_sqlserverflexbeta_database.mshtest +# identity = { +# project_id = var.project_id +# region = "eu01" +# instance_id = "b3b63d0c-35bf-4804-84ea-5abec2a8ae58" +# database_name = "mshtest" +# } +# } diff --git a/sample/sqlserver_beta/variables.tf.example b/sample/sqlserver_beta/variables.tf.example new file mode 100644 index 00000000..51a70be4 --- /dev/null +++ b/sample/sqlserver_beta/variables.tf.example @@ -0,0 +1,11 @@ +variable "project_id" { + default = "" +} + +variable "sa_email" { + default = "" +} + +variable "db_username" { + default = "" +} diff --git a/stackit/internal/services/sqlserverflexbeta/sqlserverflex_acc_test.go b/stackit/internal/services/sqlserverflexbeta/sqlserverflex_acc_test.go index 0d3d8c99..77955dd5 100644 --- a/stackit/internal/services/sqlserverflexbeta/sqlserverflex_acc_test.go +++ b/stackit/internal/services/sqlserverflexbeta/sqlserverflex_acc_test.go @@ -158,7 +158,8 @@ func TestAccInstance(t *testing.T) { PreConfig: func() { t.Logf("testing: %s - %s", t.Name(), "create and verify") }, - ExpectNonEmptyPlan: true, + // empty refresh plan + ExpectNonEmptyPlan: false, Config: testutils.StringFromTemplateMust( "testdata/instance_template.gompl", exData, diff --git a/stackit/internal/wait/sqlserverflexbeta/wait.go b/stackit/internal/wait/sqlserverflexbeta/wait.go index 18168968..fb94b9dc 100644 --- a/stackit/internal/wait/sqlserverflexbeta/wait.go +++ b/stackit/internal/wait/sqlserverflexbeta/wait.go @@ -89,9 +89,15 @@ func CreateInstanceWaitHandler( return false, nil, fmt.Errorf("could not convert error to oapierror.GenericOpenAPIError: %w", err) } switch oapiErr.StatusCode { + case http.StatusOK: + return false, nil, nil case http.StatusNotFound: return false, nil, nil default: + if strings.Contains(err.Error(), "is not a valid InstanceEdition") { + tflog.Info(ctx, "API WORKAROUND", map[string]interface{}{"err": err}) + return false, nil, nil + } return false, nil, fmt.Errorf("api error: %w", err) } }