Compare commits

..

No commits in common. "main" and "v0.2.2" have entirely different histories.
main ... v0.2.2

79 changed files with 1908 additions and 3108 deletions

View file

@ -14,7 +14,7 @@ inputs:
go-version: go-version:
description: "go version to install" description: "go version to install"
default: '1.26' default: '1.25'
required: true required: true
project_id: project_id:
@ -65,18 +65,20 @@ inputs:
description: "testfile to run" description: "testfile to run"
default: '' default: ''
outputs:
result:
value: ${{ steps.testrun.outputs.result }}
description: "the output of the tests"
status: #outputs:
value: ${{ steps.status.outputs.status }} # random-number:
description: "the status of the tests" # description: "Random number"
# value: ${{ steps.random-number-generator.outputs.random-number }}
runs: runs:
using: "composite" using: "composite"
steps: steps:
# - name: Random Number Generator
# id: random-number-generator
# run: echo "random-number=$(echo $RANDOM)" >> $GITHUB_OUTPUT
# shell: bash
- name: Install needed tools - name: Install needed tools
shell: bash shell: bash
run: | run: |
@ -92,15 +94,6 @@ runs:
fi fi
echo "::endgroup::" echo "::endgroup::"
# Install latest version of Terraform
- uses: hashicorp/setup-terraform@v4
with:
terraform_wrapper: false
- uses: actions/setup-node@v6
with:
node-version: '24.x'
- name: Setup JAVA - name: Setup JAVA
uses: actions/setup-java@v5 uses: actions/setup-java@v5
with: with:
@ -203,11 +196,11 @@ runs:
ls -l stackit/"${{ inputs.service_account_json_file_path }}" ls -l stackit/"${{ inputs.service_account_json_file_path }}"
echo "::endgroup::" echo "::endgroup::"
- name: Run acceptance tests - name: Run acceptance test file
id: testrun if: ${{ inputs.test_file != '' }}
shell: bash shell: bash
run: | run: |
echo "::group::go test" echo "::group::go test file"
set -e set -e
set -o pipefail set -o pipefail
@ -216,22 +209,7 @@ runs:
export TF_LOG export TF_LOG
fi fi
testfile="${{ inputs.test_file }}"
echo "result=no result before run" >> "$GITHUB_OUTPUT"
echo "Running acceptance tests for the terraform provider" echo "Running acceptance tests for the terraform provider"
if [[ -z "$testfile" ]]; then
testfile="./..."
fi
if [[ -z "$testfile" ]]; then
echo "ERROR: No test file provided"
exit 1
fi
set +e
cd stackit || exit 1 cd stackit || exit 1
TF_ACC=1 \ TF_ACC=1 \
TF_ACC_PROJECT_ID=${TF_ACC_PROJECT_ID} \ TF_ACC_PROJECT_ID=${TF_ACC_PROJECT_ID} \
@ -242,21 +220,7 @@ runs:
TF_ACC_KEK_KEY_RING_ID=${TF_ACC_KEK_KEY_RING_ID} \ TF_ACC_KEK_KEY_RING_ID=${TF_ACC_KEK_KEY_RING_ID} \
TF_ACC_KEK_KEY_VERSION=${TF_ACC_KEK_KEY_VERSION} \ TF_ACC_KEK_KEY_VERSION=${TF_ACC_KEK_KEY_VERSION} \
TF_ACC_KEK_SERVICE_ACCOUNT=${TF_ACC_KEK_SERVICE_ACCOUNT} \ TF_ACC_KEK_SERVICE_ACCOUNT=${TF_ACC_KEK_SERVICE_ACCOUNT} \
go test -v ${testfile} -timeout=${{ inputs.test_timeout_string }} | tee -a acc_test_run.log go test -v ${{ inputs.test_file }} -timeout=${{ inputs.test_timeout_string }}
set -e
have_fail=$(cat acc_test_run.log | grep FAIL)
if [[ -n $have_fail ]]; then
echo "::endgroup::"
echo "::group::go test result"
echo "Test failed, see acc_test_run.log for details"
echo "${have_fail}"
echo "result=<b>FAIL:</b> <br />${have_fail}" >> "$GITHUB_OUTPUT"
echo "::endgroup::"
exit 1
fi
echo "result=no FAIL detected" >> "$GITHUB_OUTPUT"
echo "::endgroup::" echo "::endgroup::"
env: env:
TF_ACC_PROJECT_ID: ${{ inputs.project_id }} TF_ACC_PROJECT_ID: ${{ inputs.project_id }}
@ -267,16 +231,55 @@ runs:
TF_ACC_KEK_KEY_VERSION: ${{ inputs.tf_acc_kek_key_version }} TF_ACC_KEK_KEY_VERSION: ${{ inputs.tf_acc_kek_key_version }}
TF_ACC_KEK_SERVICE_ACCOUNT: ${{ inputs.tf_acc_kek_service_account }} TF_ACC_KEK_SERVICE_ACCOUNT: ${{ inputs.tf_acc_kek_service_account }}
- name: Set status output variable # does not work correctly
if: always() # - name: Run test action
id: status # if: ${{ inputs.test_file == '' }}
# env:
# TF_ACC: 1
# TF_ACC_PROJECT_ID: ${{ inputs.project_id }}
# TF_ACC_REGION: ${{ inputs.region }}
# TF_ACC_TEST_PROJECT_USER_EMAIL: ${{ inputs.project_user_email }}
# TF_ACC_KEK_KEY_ID: ${{ inputs.tf_acc_kek_key_id }}
# TF_ACC_KEK_KEY_RING_ID: ${{ inputs.tf_acc_kek_key_ring_id }}
# TF_ACC_KEK_KEY_VERSION: ${{ inputs.tf_acc_kek_key_version }}
# TF_ACC_KEK_SERVICE_ACCOUNT: ${{ inputs.tf_acc_kek_service_account }}
# TF_ACC_SERVICE_ACCOUNT_FILE: ${{ steps.service_account.outputs.safile }}
# uses: robherley/go-test-action@v0
# with:
# testArguments: "./... -timeout ${{ inputs.test_timeout_string }}"
# moduleDirectory: "stackit"
- name: Run acceptance tests
if: ${{ inputs.test_file == '' }}
shell: bash shell: bash
run: | run: |
echo "status=${{ steps.testrun.outcome == 'success' && 'SUCCESS' || 'FAILURE' }}" >> "$GITHUB_OUTPUT" echo "::group::go test all"
set -e
set -o pipefail
- name: Upload test log artifact if [[ "${{ inputs.tf_debug }}" == "true" ]]; then
if: always() TF_LOG=INFO
uses: actions/upload-artifact@v3 export TF_LOG
with: fi
name: acc_test.log
path: "stackit/acc_test_run.log" echo "Running acceptance tests for the terraform provider"
cd stackit || exit 1
TF_ACC=1 \
TF_ACC_PROJECT_ID=${TF_ACC_PROJECT_ID} \
TF_ACC_REGION=${TF_ACC_REGION} \
TF_ACC_TEST_PROJECT_USER_EMAIL=${TF_ACC_TEST_PROJECT_USER_EMAIL} \
TF_ACC_SERVICE_ACCOUNT_FILE="${PWD}/${{ inputs.service_account_json_file_path }}" \
TF_ACC_KEK_KEY_ID=${TF_ACC_KEK_KEY_ID} \
TF_ACC_KEK_KEY_RING_ID=${TF_ACC_KEK_KEY_RING_ID} \
TF_ACC_KEK_KEY_VERSION=${TF_ACC_KEK_KEY_VERSION} \
TF_ACC_KEK_SERVICE_ACCOUNT=${TF_ACC_KEK_SERVICE_ACCOUNT} \
go test -v ./... -timeout=${{ inputs.test_timeout_string }}
echo "::endgroup::"
env:
TF_ACC_PROJECT_ID: ${{ inputs.project_id }}
TF_ACC_REGION: ${{ inputs.region }}
TF_ACC_TEST_PROJECT_USER_EMAIL: ${{ inputs.project_user_email }}
TF_ACC_KEK_KEY_ID: ${{ inputs.tf_acc_kek_key_id }}
TF_ACC_KEK_KEY_RING_ID: ${{ inputs.tf_acc_kek_key_ring_id }}
TF_ACC_KEK_KEY_VERSION: ${{ inputs.tf_acc_kek_key_version }}
TF_ACC_KEK_SERVICE_ACCOUNT: ${{ inputs.tf_acc_kek_service_account }}

View file

@ -3,7 +3,7 @@ description: "Build pipeline"
inputs: inputs:
go-version: go-version:
description: "Go version to install" description: "Go version to install"
default: '1.26' default: '1.25'
required: true required: true
java-distribution: java-distribution:
description: "JAVA distribution to use (default: temurin)" description: "JAVA distribution to use (default: temurin)"

View file

@ -1 +0,0 @@
# acceptance test action

View file

@ -1,227 +0,0 @@
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 }}
pre_count:
description: "number of resources found"
value: ${{ steps.retrieve_pre.outputs.count }}
post_count:
description: "number of resources found"
value: ${{ steps.retrieve_post.outputs.count }}
status:
description: "status of the test"
value: ${{ steps.status.outputs.status }}
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 before
id: retrieve_pre
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:"
sql_res=$(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 }}"))')
sql_count=$(echo "$sql_res" | jq -r '.id' | wc -l)
echo "PostgreSQL Flex resources:"
pg_res=$(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 }}"))')
pg_count=$(echo "$pg_res" | jq -r '.id' | wc -l)
echo "Number of resources found: ${sql_count} SQL Server Flex, ${pg_count} PostgreSQL Flex"
echo "count=$(( ${pg_count} + ${sql_count} ))" >> $GITHUB_OUTPUT
echo "::endgroup::"
shell: bash
- name: Delete SQL Server Flex resources
if: ${{ inputs.list_only != 'true' }}
id: del_sql
run: |
echo "::group::delete SQL Server Flex resources"
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 || echo "status=FAILURE" >> ${GITHUB_OUTPUT};
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' }}
id: del_pg
run: |
echo "::group::delete PostgreSQL Flex resources"
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" --force || echo "status=FAILURE" >> ${GITHUB_OUTPUT};
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
- name: Retrieve resources after
id: retrieve_post
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:"
sql_res=$(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 }}"))')
sql_count=$(echo "$sql_res" | jq -r '.id' | wc -l)
echo "PostgreSQL Flex resources:"
pg_res=$(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 }}"))')
pg_count=$(echo "$pg_res" | jq -r '.id' | wc -l)
echo "Number of resources found: ${sql_count} SQL Server Flex, ${pg_count} PostgreSQL Flex"
echo "count=$(( ${pg_count} + ${sql_count} ))" >> $GITHUB_OUTPUT
echo "::endgroup::"
shell: bash
- name: Set status
if: always()
id: status
run: |
status="SUCCESS"
if [[ "${{ steps.del_pg.outputs.status }}" == "FAILURE" ]]; then
status=FAILURE"
elif [[ "${{ steps.del_sql.outputs.status }}" == "FAILURE" ]]; then
status=FAILURE"
fi
echo "status=$status" >> $GITHUB_OUTPUT
shell: bash

View file

@ -1,148 +0,0 @@
name: Send notification via Google Chat
description: "Sends a notification to a Google Chat room when a pull request is opened."
inputs:
webhook_url:
description: "The URL of the Google Chat webhook."
required: true
title:
description: "The title of the notification."
required: true
subtitle:
description: "The subtitle of the notification."
default: 'no subtitle provided'
image_slug:
description: "The slug of the image to be included in the notification."
default: 'git'
event_author:
description: "The author of the event."
default: 'unknown'
event_title:
description: "The title of the event."
required: true
event_body:
description: "The body of the event."
default: 'no body provided'
event_number:
description: "The number of the event."
default: 'no number provided'
event_url:
description: "The url of the event."
default: 'none'
status:
description: "The status of the event."
default: 'UNKNOWN'
runs:
using: "composite"
steps:
- name: Install prerequisites
shell: bash
run: |
echo "::group::apt install"
set -e
apt update
apt install -y curl jq
echo "::endgroup::"
- name: Determine status color
id: status
shell: bash
run: |
case "${{ inputs.status }}" in
SUCCESS)
STATUS_COLOR="006400/228b22"
ADD='{"decoratedText": {"startIcon": {"materialIcon": {"name": "check_circle"}},"text": "<b style=\"color: green;\">SUCCESS</b>"}},'
;;
FAILURE)
STATUS_COLOR="8b0000/dc143c"
ADD='{"decoratedText": {"startIcon": {"materialIcon": {"name": "stop_circle"}},"text": "<b style=\"color: red;\">FAILURE</b>"}},'
;;
*)
STATUS_COLOR="483d8b/6495ed"
ADD=''
;;
esac
echo "color=${STATUS_COLOR}" >> "$GITHUB_OUTPUT"
echo "status_add=${ADD}" >> "$GITHUB_OUTPUT"
- name: Notify via Google Chat Webhook
shell: bash
env:
WEBHOOK: ${{ inputs.webhook_url }}
run: |
set -e
PAYLOAD=$(jq -n -r \
--arg header "${{ inputs.title }}" \
--arg subtitle "${{ inputs.subtitle }}" \
--arg imgurl "https://cdn.simpleicons.org/${{ inputs.image_slug }}/${{ steps.status.outputs.color }}" \
--arg title "${{ inputs.event_title || 'no event title given' }}" \
--arg body "${{ inputs.event_body || 'no event body given' }}" \
--arg author "${{ inputs.event_author || 'no event author given' }}" \
--arg url "${{ inputs.event_url || github.repositoryUrl || github.server_url }}" \
'{ "cardsV2": [ { "cardId": "notify-${{ github.run_id }}", "card": {
"header": {
"title": "\($header)",
"subtitle": "\($subtitle)",
"imageUrl": "\($imgurl)",
"imageType": "SQUARE"
},
"sections": [
{
"header": "\($title)",
"collapsible": false,
"widgets": [
${{ steps.status.outputs.status_add }}
{
"decoratedText": {
"startIcon": {
"knownIcon": "PERSON"
},
"text": "<b>\($author)</b>"
}
},
{
"textParagraph": {
"text": "\($body)",
"maxLines": 2
}
}
]
},
{
"widgets": [
{
"buttonList": {
"buttons": [
{
"text": "View Source Event",
"type": "FILLED",
"onClick": {
"openLink": {
"url": "\($url)"
}
}
}
]
}
}
]
}
]
}} ] }')
curl \
-X POST \
-H 'Content-Type: application/json' \
"${{ inputs.webhook_url }}&threadKey=run${{ github.run_id }}&messageReplyOption=REPLY_MESSAGE_FALLBACK_TO_NEW_THREAD" \
-d "${PAYLOAD}"

View file

@ -10,7 +10,7 @@ inputs:
go-version: go-version:
description: "go version to install" description: "go version to install"
default: '1.26' default: '1.25'
required: true required: true
runs: runs:

View file

@ -28,24 +28,11 @@ jobs:
config: config:
if: ${{ github.event_name != 'schedule' }} if: ${{ github.event_name != 'schedule' }}
name: Check GoReleaser config name: Check GoReleaser config
runs-on: stackit-docker runs-on: ubuntu-latest
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v6 uses: actions/checkout@v6
- name: Notify
if: always()
uses: ./.github/actions/notify
with:
webhook_url: ${{ secrets.GOOGLE_WEBHOOK_URL }}
title: "[START] CI pipeline (#${{ forgejo.run_number }})"
subtitle: "${{ forgejo.event_name }} on ${{ forgejo.ref_name }}"
event_title: "${{ forgejo.event_name }} for ${{ forgejo.repository }}"
event_author: ${{ forgejo.actor }}
event_body: "${{ forgejo.event_name }} on ${{ forgejo.ref }} for ${{ forgejo.repository }}"
event_number: ${{ forgejo.run_number }}
event_url: "https://tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/actions/runs/${{ forgejo.run_number }}"
- name: Check GoReleaser - name: Check GoReleaser
uses: goreleaser/goreleaser-action@v7 uses: goreleaser/goreleaser-action@v7
with: with:
@ -53,7 +40,7 @@ jobs:
prepare: prepare:
name: Prepare GO cache name: Prepare GO cache
runs-on: stackit-docker runs-on: ubuntu-latest
permissions: permissions:
actions: read # Required to identify workflow run. actions: read # Required to identify workflow run.
checks: write # Required to add status summary. checks: write # Required to add status summary.
@ -115,7 +102,7 @@ jobs:
needs: needs:
- config - config
- prepare - prepare
runs-on: stackit-docker runs-on: ubuntu-latest
permissions: permissions:
actions: read # Required to identify workflow run. actions: read # Required to identify workflow run.
checks: write # Required to add status summary. checks: write # Required to add status summary.
@ -198,7 +185,7 @@ jobs:
testing: testing:
name: CI run tests name: CI run tests
runs-on: stackit-docker runs-on: ubuntu-latest
needs: needs:
- config - config
- prepare - prepare
@ -291,7 +278,7 @@ jobs:
main: main:
if: ${{ github.event_name != 'schedule' }} if: ${{ github.event_name != 'schedule' }}
name: CI run build and linting name: CI run build and linting
runs-on: stackit-docker runs-on: ubuntu-latest
needs: needs:
- config - config
- prepare - prepare
@ -342,7 +329,7 @@ jobs:
code_coverage: code_coverage:
name: "Code coverage report" name: "Code coverage report"
if: github.event_name == 'pull_request' # Do not run when workflow is triggered by push to main branch if: github.event_name == 'pull_request' # Do not run when workflow is triggered by push to main branch
runs-on: stackit-docker runs-on: ubuntu-latest
needs: needs:
- main - main
- prepare - prepare

View file

@ -1,72 +0,0 @@
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: Notify
uses: ./.github/actions/notify
with:
webhook_url: ${{ secrets.GOOGLE_WEBHOOK_URL }}
title: "[START] CLEAN UP pipeline (#${{ forgejo.run_number }})"
subtitle: "${{ forgejo.repository }}"
event_title: ${{ forgejo.event_name }}
event_author: ${{ forgejo.actor }}
event_body: "try to remove all resources with prefix <b>${{ inputs.res_prefix }}</b>"
event_number: ${{ forgejo.run_number }}
event_url: "https://tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/actions/runs/${{ forgejo.run_number }}"
- name: Clean
id: 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 }}
- name: Notify
if: always()
uses: ./.github/actions/notify
with:
webhook_url: ${{ secrets.GOOGLE_WEBHOOK_URL }}
title: "[END] CLEAN UP pipeline (#${{ forgejo.run_number }})"
subtitle: "${{ forgejo.repository }}"
event_title: ${{ forgejo.event_name }}
event_author: ${{ forgejo.actor }}
event_body: "count before cleaning: ${{ steps.clean.outputs.pre_count }} <br /> count after cleaning: ${{ steps.clean.outputs.post_count }}"
event_number: ${{ forgejo.run_number }}
event_url: "https://tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/actions/runs/${{ forgejo.run_number }}"
status: ${{ steps.clean.outcome == 'success' && 'SUCCESS' || 'FAILURE' }}

View file

@ -1,25 +0,0 @@
name: Notify on new PR
on:
pull_request:
types:
- opened
jobs:
notify:
name: Notify via Google Chat
runs-on: stackit-docker
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Notify
uses: ./.github/actions/notify
with:
webhook_url: ${{ secrets.GOOGLE_WEBHOOK_URL }}
title: "New Pull Request"
event_title: "${{ github.event.pull_request.title }}"
event_author: "${{ github.event.pull_request.user.login }}"
event_body: "${{ github.event.pull_request.body || 'No description provided.' }}"
event_number: "${{ github.event.pull_request.number }}"
event_url: "${{ github.event.pull_request.html_url }}"

View file

@ -3,11 +3,11 @@ name: Publish
run-name: Publish by @${{ github.actor }} run-name: Publish by @${{ github.actor }}
on: on:
workflow_dispatch: #workflow_dispatch:
push: push:
tags: tags:
- 'v*' - 'v0.*'
env: env:
GO_VERSION: "1.25" GO_VERSION: "1.25"
@ -21,8 +21,6 @@ jobs:
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v6 uses: actions/checkout@v6
with:
fetch-tags: true
- name: Check GoReleaser - name: Check GoReleaser
uses: goreleaser/goreleaser-action@v7 uses: goreleaser/goreleaser-action@v7
@ -46,20 +44,6 @@ jobs:
- name: Checkout - name: Checkout
uses: actions/checkout@v6 uses: actions/checkout@v6
with:
fetch-tags: true
- name: Notify
uses: ./.github/actions/notify
with:
webhook_url: ${{ secrets.GOOGLE_WEBHOOK_URL }}
title: "[START] Publish (#${{ forgejo.run_number }})"
subtitle: "${{ forgejo.event_name }} on branch ${{ forgejo.ref }}"
event_title: "run started"
event_author: ${{ forgejo.actor }}
event_body: ""
event_number: ${{ forgejo.event.id }}
event_url: "https://tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/actions/runs/${{ forgejo.run_number }}"
- name: Setup Go - name: Setup Go
uses: actions/setup-go@v6 uses: actions/setup-go@v6
@ -148,7 +132,6 @@ jobs:
--outFile nav.md --outFile nav.md
- name: Publish provider to S3 - name: Publish provider to S3
id: publish_to_s3
run: | run: |
set -e set -e
cd release/ cd release/
@ -169,17 +152,3 @@ jobs:
# echo "${{ github.ref_name }}" >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 -r docs ubuntu@${{ vars.DOCS_SERVER_IP }}:/srv/www/
scp -o StrictHostKeyChecking=no nav.md ubuntu@${{ vars.DOCS_SERVER_IP }}:/srv/www/ scp -o StrictHostKeyChecking=no nav.md ubuntu@${{ vars.DOCS_SERVER_IP }}:/srv/www/
- name: Notify
if: always()
uses: ./.github/actions/notify
with:
webhook_url: ${{ secrets.GOOGLE_WEBHOOK_URL }}
title: "[END] Publish (#${{ forgejo.run_number }})"
subtitle: "${{ forgejo.event_name }} on branch ${{ forgejo.ref }}"
event_title: "released: ${{ steps.get_version.outputs.version }}"
event_author: ${{ forgejo.actor }}
event_body: ""
event_number: ${{ forgejo.event.id }}
event_url: "https://tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/actions/runs/${{ forgejo.run_number }}"
status: "${{ steps.publish_to_s3.outcome == 'success' && 'SUCCESS' || 'FAILURE' }}"

View file

@ -16,14 +16,14 @@ permissions:
jobs: jobs:
goreleaser: goreleaser:
runs-on: stackit-docker runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v6 - uses: actions/checkout@v6
with: with:
# Allow goreleaser to access older tag information. # Allow goreleaser to access older tag information.
fetch-depth: 0 fetch-depth: 0
- uses: actions/setup-go@v6 - uses: https://code.forgejo.org/actions/setup-go@v6
with: with:
go-version-file: "go.mod" go-version-file: "go.mod"
cache: true cache: true

View file

@ -8,13 +8,13 @@ on:
jobs: jobs:
renovate: renovate:
name: Renovate name: Renovate
runs-on: stackit-docker runs-on: ubuntu-latest
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v6 uses: actions/checkout@v6
- name: Self-hosted Renovate - name: Self-hosted Renovate
uses: renovatebot/github-action@v46.1.5 uses: renovatebot/github-action@v46.1.4
with: with:
configurationFile: .github/renovate.json configurationFile: .github/renovate.json
# token: ${{ secrets.RENOVATE_TOKEN }} # token: ${{ secrets.RENOVATE_TOKEN }}

View file

@ -20,7 +20,7 @@ permissions:
jobs: jobs:
stale: stale:
name: "Stale" name: "Stale"
runs-on: stackit-docker runs-on: ubuntu-latest
timeout-minutes: 10 timeout-minutes: 10
steps: steps:
- name: "Mark old PRs as stale" - name: "Mark old PRs as stale"

View file

@ -13,59 +13,23 @@ on:
inputs: inputs:
enable_debug: enable_debug:
description: "enable terraform debug logs" description: "enable terraform debug logs"
type: boolean default: 'false'
default: false
required: true required: true
test_timeout_string: test_timeout_string:
description: "string that determines the timeout (default: '120m')" description: "string that determines the timeout (default: 45m)"
type: string default: '90m'
default: '120m'
required: true required: true
test_file:
description: "string that determines the test file to run (default all tests)"
type: choice
options:
- tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit/internal/wait/postgresflexalpha
- tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit/internal/services/postgresflexalpha
- tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit/internal/wait/sqlserverflexbeta
- tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit/internal/services/sqlserverflexbeta
default: ''
jobs: jobs:
acc_test: acc_test:
name: Acceptance Tests name: Acceptance Tests
runs-on: stackit-docker runs-on: ubuntu-latest
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v6 uses: actions/checkout@v6
- name: set start time
id: start_time
continue-on-error: true
run: |
time=$(date --rfc-3339=ns)
echo "start_time=$time" >> ${GITHUB_OUTPUT}
start=$(date +%s%N)
echo "start=$start" >> ${GITHUB_OUTPUT}
- name: Notify
uses: ./.github/actions/notify
with:
webhook_url: ${{ secrets.GOOGLE_WEBHOOK_URL }}
title: "[START] Terraform Acceptance Tests (#${{ forgejo.run_number }})"
subtitle: "${{ forgejo.event_name }} on branch ${{ forgejo.ref }}"
event_title: "started: ${{ steps.start_time.outputs.start_time }}"
event_author: ${{ forgejo.actor }}
event_body: ${{ inputs.test_file }}
event_number: ${{ forgejo.run_number }}
event_url: "https://tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/actions/runs/${{ forgejo.run_number }}"
- name: Run Test (workflow dispatch) - name: Run Test (workflow dispatch)
if: ${{ forgejo.event_name == 'workflow_dispatch' }} if: ${{ github.event_name == 'workflow_dispatch' }}
id: manual_run
continue-on-error: true
uses: ./.github/actions/acc_test uses: ./.github/actions/acc_test
with: with:
go-version: ${{ env.GO_VERSION }} go-version: ${{ env.GO_VERSION }}
@ -79,12 +43,9 @@ jobs:
tf_acc_kek_service_account: ${{ vars.TF_ACC_KEK_SERVICE_ACCOUNT }} tf_acc_kek_service_account: ${{ vars.TF_ACC_KEK_SERVICE_ACCOUNT }}
tf_debug: ${{ inputs.enable_debug }} tf_debug: ${{ inputs.enable_debug }}
test_timeout_string: ${{ inputs.test_timeout_string }} test_timeout_string: ${{ inputs.test_timeout_string }}
test_file: ${{ inputs.test_file }}
- name: Run Test (automatic) - name: Run Test (automatic)
if: ${{ forgejo.event_name != 'workflow_dispatch' }} if: ${{ github.event_name != 'workflow_dispatch' }}
id: automatic_run
continue-on-error: true
uses: ./.github/actions/acc_test uses: ./.github/actions/acc_test
with: with:
go-version: ${{ env.GO_VERSION }} go-version: ${{ env.GO_VERSION }}
@ -96,32 +57,4 @@ jobs:
tf_acc_kek_key_ring_id: ${{ vars.TF_ACC_KEK_KEY_RING_ID }} tf_acc_kek_key_ring_id: ${{ vars.TF_ACC_KEK_KEY_RING_ID }}
tf_acc_kek_key_version: ${{ vars.TF_ACC_KEK_KEY_VERSION }} tf_acc_kek_key_version: ${{ vars.TF_ACC_KEK_KEY_VERSION }}
tf_acc_kek_service_account: ${{ vars.TF_ACC_KEK_SERVICE_ACCOUNT }} tf_acc_kek_service_account: ${{ vars.TF_ACC_KEK_SERVICE_ACCOUNT }}
tf_debug: ${{ inputs.enable_debug }}
- name: set end time
id: end_time
continue-on-error: true
run: |
set -e
echo "auto status: ${{ steps.automatic_run.outputs.status }}"
echo "manual status: ${{ steps.manual_run.outputs.status }}"
echo "status: ${{ forgejo.event_name == 'workflow_dispatch' && steps.manual_run.outputs.status || steps.automatic_run.outputs.status }}"
echo "end_time=$(date --rfc-3339=ns)" >> ${GITHUB_OUTPUT}
end=$(date +%s%N)
echo "end=${end}" >> ${GITHUB_OUTPUT}
start=${{ steps.start_time.outputs.start }}
diff=$((end-start))
duration=$(printf "%s.%s" "${diff:0: -9}" "${diff: -9:3}")
echo "duration=${duration}" >> ${GITHUB_OUTPUT}
- name: Notify
uses: ./.github/actions/notify
with:
webhook_url: ${{ secrets.GOOGLE_WEBHOOK_URL }}
title: "[END] Terraform Acceptance Tests (#${{ forgejo.run_number }})"
subtitle: "${{ forgejo.event_name }} on branch ${{ forgejo.ref }} with status: ${{ forgejo.event_name == 'workflow_dispatch' && steps.manual_run.outputs.status || steps.automatic_run.outputs.status }}"
event_title: "run ended: ${{ steps.end_time.outputs.end_time }}, duration: ${{ steps.end_time.outputs.duration }} seconds"
event_author: ${{ forgejo.actor }}
event_body: "${{ forgejo.event_name == 'workflow_dispatch' && steps.manual_run.outputs.result || steps.automatic_run.outputs.result }}"
event_number: ${{ forgejo.event.id }}
event_url: "https://tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/actions/runs/${{ forgejo.run_number }}"
status: "${{ forgejo.event_name == 'workflow_dispatch' && steps.manual_run.outputs.status || steps.automatic_run.outputs.status }}"

View file

@ -42,16 +42,10 @@ data "stackitprivatepreview_postgresflexalpha_instance" "example" {
- `flavor_id` (String) The id of the instance flavor. - `flavor_id` (String) The id of the instance flavor.
- `id` (String) internal ID - `id` (String) internal ID
- `is_deletable` (Boolean) Whether the instance can be deleted or not. - `is_deletable` (Boolean) Whether the instance can be deleted or not.
- `labels` (Map of String) Key-value pairs, 63 characters max, begin and end with an alphanumerical character,
may contain dashes (-), underscores (_), dots (.), and alphanumerics between. Key MUST be at least 1 character.
Max 64 labels
Regex for keys: ^(?=.{1,63}$)([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9]$
Regex for values: ^(?=.{0,63}$)(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])*$
The stackit- prefix is reserved and cannot be used for Keys.
- `name` (String) The name of the instance. - `name` (String) The name of the instance.
- `network` (Attributes) The access configuration of the instance (see [below for nested schema](#nestedatt--network)) - `network` (Attributes) The access configuration of the instance (see [below for nested schema](#nestedatt--network))
- `replicas` (Number) How many replicas the instance should have. - `replicas` (Number) How many replicas the instance should have.
- `retention_days` (Number) How long backups are retained. The value can only be between 32 and 90 days. - `retention_days` (Number) How long backups are retained. The value can only be between 32 and 365 days.
- `status` (String) The current status of the instance. - `status` (String) The current status of the instance.
- `storage` (Attributes) The object containing information about the storage size and class. (see [below for nested schema](#nestedatt--storage)) - `storage` (Attributes) The object containing information about the storage size and class. (see [below for nested schema](#nestedatt--storage))
- `tf_original_api_id` (String) The ID of the instance. - `tf_original_api_id` (String) The ID of the instance.

View file

@ -0,0 +1,32 @@
---
# generated by https://github.com/hashicorp/terraform-plugin-docs
page_title: "stackitprivatepreview_sqlserverflexalpha_database Data Source - stackitprivatepreview"
subcategory: ""
description: |-
---
# stackitprivatepreview_sqlserverflexalpha_database (Data Source)
<!-- schema generated by tfplugindocs -->
## Schema
### Required
- `database_name` (String) The name of the database.
- `instance_id` (String) The ID of the instance.
- `project_id` (String) The STACKIT project ID.
- `region` (String) The region which should be addressed
### Read-Only
- `collation_name` (String) The collation of the database. This database collation should match the *collation_name* of one of the collations given by the **Get database collation list** endpoint.
- `compatibility_level` (Number) CompatibilityLevel of the Database.
- `id` (String) The terraform internal identifier.
- `name` (String) The name of the database.
- `owner` (String) The owner of the database.
- `tf_original_api_id` (Number) The id of the database.

View file

@ -0,0 +1,77 @@
---
# generated by https://github.com/hashicorp/terraform-plugin-docs
page_title: "stackitprivatepreview_sqlserverflexalpha_instance Data Source - stackitprivatepreview"
subcategory: ""
description: |-
---
# stackitprivatepreview_sqlserverflexalpha_instance (Data Source)
## Example Usage
```terraform
data "stackitprivatepreview_sqlserverflexalpha_instance" "example" {
project_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
instance_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
}
```
<!-- schema generated by tfplugindocs -->
## Schema
### Required
- `instance_id` (String) The ID of the instance.
- `project_id` (String) The STACKIT project ID.
- `region` (String) The region which should be addressed
### Read-Only
- `backup_schedule` (String) The schedule for on what time and how often the database backup will be created. The schedule is written as a cron schedule.
- `edition` (String) Edition of the MSSQL server instance
- `encryption` (Attributes) this defines which key to use for storage encryption (see [below for nested schema](#nestedatt--encryption))
- `flavor_id` (String) The id of the instance flavor.
- `is_deletable` (Boolean) Whether the instance can be deleted or not.
- `name` (String) The name of the instance.
- `network` (Attributes) The access configuration of the instance (see [below for nested schema](#nestedatt--network))
- `replicas` (Number) How many replicas the instance should have.
- `retention_days` (Number) The days for how long the backup files should be stored before cleaned up. 30 to 365
- `status` (String)
- `storage` (Attributes) The object containing information about the storage size and class. (see [below for nested schema](#nestedatt--storage))
- `tf_original_api_id` (String) The ID of the instance.
- `version` (String) The sqlserver version used for the instance.
<a id="nestedatt--encryption"></a>
### Nested Schema for `encryption`
Read-Only:
- `kek_key_id` (String) The key identifier
- `kek_key_ring_id` (String) The keyring identifier
- `kek_key_version` (String) The key version
- `service_account` (String)
<a id="nestedatt--network"></a>
### Nested Schema for `network`
Read-Only:
- `access_scope` (String) The network access scope of the instance
⚠️ **Note:** This feature is in private preview. Supplying this object is only permitted for enabled accounts. If your account does not have access, the request will be rejected.
- `acl` (List of String) List of IPV4 cidr.
- `instance_address` (String)
- `router_address` (String)
<a id="nestedatt--storage"></a>
### Nested Schema for `storage`
Read-Only:
- `class` (String) The storage class for the storage.
- `size` (Number) The storage size in Gigabytes.

View file

@ -0,0 +1,62 @@
---
# generated by https://github.com/hashicorp/terraform-plugin-docs
page_title: "stackitprivatepreview_sqlserverflexalpha_user Data Source - stackitprivatepreview"
subcategory: ""
description: |-
---
# stackitprivatepreview_sqlserverflexalpha_user (Data Source)
## Example Usage
```terraform
data "stackitprivatepreview_sqlserverflexalpha_user" "example" {
project_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
instance_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
user_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
}
```
<!-- schema generated by tfplugindocs -->
## Schema
### Required
- `instance_id` (String) The ID of the instance.
- `project_id` (String) The STACKIT project ID.
- `region` (String) The region which should be addressed
### Optional
- `page` (Number) Number of the page of items list to be returned.
- `size` (Number) Number of items to be returned on each page.
- `sort` (String) Sorting of the users to be returned on each page.
### Read-Only
- `pagination` (Attributes) (see [below for nested schema](#nestedatt--pagination))
- `users` (Attributes List) List of all users inside an instance (see [below for nested schema](#nestedatt--users))
<a id="nestedatt--pagination"></a>
### Nested Schema for `pagination`
Read-Only:
- `page` (Number)
- `size` (Number)
- `sort` (String)
- `total_pages` (Number)
- `total_rows` (Number)
<a id="nestedatt--users"></a>
### Nested Schema for `users`
Read-Only:
- `status` (String) The current status of the user.
- `tf_original_api_id` (Number) The ID of the user.
- `username` (String) The name of the user.

View file

@ -1,54 +0,0 @@
---
# generated by https://github.com/hashicorp/terraform-plugin-docs
page_title: "stackitprivatepreview_sqlserverflexbeta_flavor Data Source - stackitprivatepreview"
subcategory: ""
description: |-
---
# stackitprivatepreview_sqlserverflexbeta_flavor (Data Source)
## Example Usage
```terraform
data "stackitprivatepreview_sqlserverflexbeta_flavor" "flavor" {
project_id = var.project_id
region = var.region
cpu = 4
ram = 16
node_type = "Single"
storage_class = "premium-perf2-stackit"
}
```
<!-- schema generated by tfplugindocs -->
## Schema
### Required
- `cpu` (Number) The cpu count of the instance.
- `node_type` (String) defines the nodeType it can be either single or HA
- `project_id` (String) The project ID of the flavor.
- `ram` (Number) The memory of the instance in Gibibyte.
- `region` (String) The region of the flavor.
- `storage_class` (String) The memory of the instance in Gibibyte.
### Read-Only
- `description` (String) The flavor description.
- `flavor_id` (String) The id of the instance flavor.
- `id` (String) The id of the instance flavor.
- `max_gb` (Number) maximum storage which can be ordered for the flavor in Gigabyte.
- `min_gb` (Number) minimum storage which is required to order in Gigabyte.
- `storage_classes` (Attributes List) maximum storage which can be ordered for the flavor in Gigabyte. (see [below for nested schema](#nestedatt--storage_classes))
<a id="nestedatt--storage_classes"></a>
### Nested Schema for `storage_classes`
Read-Only:
- `class` (String)
- `max_io_per_sec` (Number)
- `max_through_in_mb` (Number)

View file

@ -13,33 +13,6 @@ description: |-
## Example Usage ## Example Usage
```terraform ```terraform
# NOTE: flavor handling will change in future
# V2 compatible flavor usage (example without encryption)
resource "stackitprivatepreview_postgresflexalpha_instance" "example-instance" {
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 = {
cpu = 2
ram = 4
}
replicas = 1
storage = {
performance_class = "premium-perf2-stackit"
size = 10
}
network = {
acl = ["XXX.XXX.XXX.X/XX", "XX.XXX.XX.X/XX"]
access_scope = "PUBLIC"
}
version = 17
}
# future use of flavor (implemented in V3 API)
# first determine flavor and then use the flavor_id
resource "stackitprivatepreview_postgresflexalpha_instance" "example-instance" { resource "stackitprivatepreview_postgresflexalpha_instance" "example-instance" {
project_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" project_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
name = "example-instance" name = "example-instance"
@ -87,10 +60,11 @@ import {
### Required ### Required
- `backup_schedule` (String) The schedule for when the database backup will be created. Currently, ONLY daily schedules are supported (every 24 hours). The schedule is written as a cron schedule. - `backup_schedule` (String) The schedule for when the database backup will be created. Currently, ONLY daily schedules are supported (every 24 hours). The schedule is written as a cron schedule.
- `flavor_id` (String) The id of the instance flavor.
- `name` (String) The name of the instance. - `name` (String) The name of the instance.
- `network` (Attributes) The access configuration of the instance (see [below for nested schema](#nestedatt--network)) - `network` (Attributes) The access configuration of the instance (see [below for nested schema](#nestedatt--network))
- `replicas` (Number) How many replicas the instance should have. - `replicas` (Number) How many replicas the instance should have.
- `retention_days` (Number) How long backups are retained. The value can only be between 32 and 90 days. - `retention_days` (Number) How long backups are retained. The value can only be between 32 and 365 days.
- `storage` (Attributes) The object containing information about the storage size and class. (see [below for nested schema](#nestedatt--storage)) - `storage` (Attributes) The object containing information about the storage size and class. (see [below for nested schema](#nestedatt--storage))
- `version` (String) The Postgres version used for the instance. See [Versions Endpoint](/documentation/postgres-flex-service/version/v3alpha1#tag/Version) for supported version parameters. - `version` (String) The Postgres version used for the instance. See [Versions Endpoint](/documentation/postgres-flex-service/version/v3alpha1#tag/Version) for supported version parameters.
@ -99,8 +73,6 @@ import {
- `encryption` (Attributes) The configuration for instance's volume and backup storage encryption. - `encryption` (Attributes) The configuration for instance's volume and backup storage encryption.
⚠︝ **Note:** This feature is in private preview. Supplying this object is only permitted for enabled accounts. If your account does not have access, the request will be rejected. (see [below for nested schema](#nestedatt--encryption)) ⚠︝ **Note:** This feature is in private preview. Supplying this object is only permitted for enabled accounts. If your account does not have access, the request will be rejected. (see [below for nested schema](#nestedatt--encryption))
- `flavor` (Attributes, Deprecated) (see [below for nested schema](#nestedatt--flavor))
- `flavor_id` (String) The id of the instance flavor.
- `instance_id` (String) The ID of the instance. - `instance_id` (String) The ID of the instance.
- `project_id` (String) The STACKIT project ID. - `project_id` (String) The STACKIT project ID.
- `region` (String) The region which should be addressed - `region` (String) The region which should be addressed
@ -150,20 +122,6 @@ Required:
- `service_account` (String) - `service_account` (String)
<a id="nestedatt--flavor"></a>
### Nested Schema for `flavor`
Optional:
- `cpu` (Number, Deprecated)
- `ram` (Number, Deprecated)
Read-Only:
- `description` (String)
- `id` (String)
<a id="nestedatt--connection_info"></a> <a id="nestedatt--connection_info"></a>
### Nested Schema for `connection_info` ### Nested Schema for `connection_info`

View file

@ -0,0 +1,63 @@
---
# generated by https://github.com/hashicorp/terraform-plugin-docs
page_title: "stackitprivatepreview_sqlserverflexalpha_database Resource - stackitprivatepreview"
subcategory: ""
description: |-
---
# stackitprivatepreview_sqlserverflexalpha_database (Resource)
## Example Usage
```terraform
resource "stackitprivatepreview_sqlserverflexalpha_database" "example" {
project_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
instance_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
collation = ""
compatibility = "160"
name = ""
owner = ""
}
# Only use the import statement, if you want to import a existing sqlserverflex database
import {
to = stackitprivatepreview_sqlserverflexalpha_database.import-example
id = "${var.project_id},${var.region},${var.sql_instance_id},${var.sql_user_id}"
}
import {
to = stackitprivatepreview_sqlserverflexalpha_database.import-example
identity = {
project_id = "project.id"
region = "region"
instance_id = "instance.id"
database_id = "database.id"
}
}
```
<!-- schema generated by tfplugindocs -->
## Schema
### Required
- `name` (String) The name of the database.
- `owner` (String) The owner of the database.
### Optional
- `collation` (String) The collation of the database. This database collation should match the *collation_name* of one of the collations given by the **Get database collation list** endpoint.
- `compatibility` (Number) CompatibilityLevel of the Database.
- `database_name` (String) The name of the database.
- `instance_id` (String) The ID of the instance.
- `project_id` (String) The STACKIT project ID.
- `region` (String) The region which should be addressed
### Read-Only
- `collation_name` (String) The collation of the database. This database collation should match the *collation_name* of one of the collations given by the **Get database collation list** endpoint.
- `compatibility_level` (Number) CompatibilityLevel of the Database.
- `id` (Number) The id of the database.

View file

@ -0,0 +1,103 @@
---
# generated by https://github.com/hashicorp/terraform-plugin-docs
page_title: "stackitprivatepreview_sqlserverflexalpha_instance Resource - stackitprivatepreview"
subcategory: ""
description: |-
---
# stackitprivatepreview_sqlserverflexalpha_instance (Resource)
## Example Usage
```terraform
resource "stackitprivatepreview_sqlserverflexalpha_instance" "example" {
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 = 4
ram = 16
}
storage = {
class = "class"
size = 5
}
version = 2022
}
# Only use the import statement, if you want to import an existing sqlserverflex instance
import {
to = stackitprivatepreview_sqlserverflexalpha_instance.import-example
id = "${var.project_id},${var.region},${var.sql_instance_id}"
}
```
<!-- schema generated by tfplugindocs -->
## Schema
### Required
- `backup_schedule` (String) The schedule for on what time and how often the database backup will be created. The schedule is written as a cron schedule.
- `flavor_id` (String) The id of the instance flavor.
- `name` (String) The name of the instance.
- `network` (Attributes) the network configuration of the instance. (see [below for nested schema](#nestedatt--network))
- `retention_days` (Number) The days for how long the backup files should be stored before cleaned up. 30 to 365
- `storage` (Attributes) The object containing information about the storage size and class. (see [below for nested schema](#nestedatt--storage))
- `version` (String) The sqlserver version used for the instance.
### Optional
- `encryption` (Attributes) this defines which key to use for storage encryption (see [below for nested schema](#nestedatt--encryption))
- `instance_id` (String) The ID of the instance.
- `project_id` (String) The STACKIT project ID.
- `region` (String) The region which should be addressed
### Read-Only
- `edition` (String) Edition of the MSSQL server instance
- `id` (String) The ID of the instance.
- `is_deletable` (Boolean) Whether the instance can be deleted or not.
- `replicas` (Number) How many replicas the instance should have.
- `status` (String)
<a id="nestedatt--network"></a>
### Nested Schema for `network`
Required:
- `acl` (List of String) List of IPV4 cidr.
Optional:
- `access_scope` (String) The network access scope of the instance
⚠️ **Note:** This feature is in private preview. Supplying this object is only permitted for enabled accounts. If your account does not have access, the request will be rejected.
Read-Only:
- `instance_address` (String)
- `router_address` (String)
<a id="nestedatt--storage"></a>
### Nested Schema for `storage`
Required:
- `class` (String) The storage class for the storage.
- `size` (Number) The storage size in Gigabytes.
<a id="nestedatt--encryption"></a>
### Nested Schema for `encryption`
Required:
- `kek_key_id` (String) The key identifier
- `kek_key_ring_id` (String) The keyring identifier
- `kek_key_version` (String) The key version
- `service_account` (String)

View file

@ -0,0 +1,53 @@
---
# generated by https://github.com/hashicorp/terraform-plugin-docs
page_title: "stackitprivatepreview_sqlserverflexalpha_user Resource - stackitprivatepreview"
subcategory: ""
description: |-
---
# stackitprivatepreview_sqlserverflexalpha_user (Resource)
## Example Usage
```terraform
resource "stackitprivatepreview_sqlserverflexalpha_user" "example" {
project_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
instance_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
username = "username"
roles = ["role"]
}
# Only use the import statement, if you want to import an existing sqlserverflex user
import {
to = stackitprivatepreview_sqlserverflexalpha_user.import-example
id = "${var.project_id},${var.region},${var.sql_instance_id},${var.sql_user_id}"
}
```
<!-- schema generated by tfplugindocs -->
## Schema
### Required
- `roles` (List of String) A list containing the user roles for the instance. A list with the valid user roles can be retrieved using the List Roles endpoint.
- `username` (String) The name of the user.
### Optional
- `default_database` (String) The default database for a user of the instance.
- `instance_id` (String) The ID of the instance.
- `project_id` (String) The STACKIT project ID.
- `region` (String) The region which should be addressed
- `user_id` (Number) The ID of the user.
### Read-Only
- `host` (String) The host of the instance in which the user belongs to.
- `id` (Number) The ID of the user.
- `password` (String) The password for the user.
- `port` (Number) The port of the instance in which the user belongs to.
- `status` (String) The current status of the user.
- `uri` (String) The connection string for the user to the instance.

View file

@ -13,31 +13,6 @@ description: |-
## Example Usage ## Example Usage
```terraform ```terraform
# NOTE: flavor handling will change in future
# V2 compatible flavor usage
resource "stackitprivatepreview_sqlserverflexbeta_instance" "instance" {
project_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
name = "example-instance"
backup_schedule = "0 3 * * *"
retention_days = 31
flavor = {
cpu = 2
ram = 4
}
storage = {
class = "premium-perf2-stackit"
size = 50
}
version = 2022
network = {
acl = ["XXX.XXX.XXX.X/XX", "XX.XXX.XX.X/XX"]
access_scope = "SNA"
}
}
# future use of flavor (implemented in V3 API)
# first determine flavor and then use the flavor_id
# without encryption and SNA # without encryption and SNA
resource "stackitprivatepreview_sqlserverflexbeta_instance" "instance" { resource "stackitprivatepreview_sqlserverflexbeta_instance" "instance" {
project_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" project_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
@ -122,6 +97,7 @@ import {
### Required ### Required
- `backup_schedule` (String) The schedule for on what time and how often the database backup will be created. The schedule is written as a cron schedule. - `backup_schedule` (String) The schedule for on what time and how often the database backup will be created. The schedule is written as a cron schedule.
- `flavor_id` (String) The id of the instance flavor.
- `name` (String) The name of the instance. - `name` (String) The name of the instance.
- `network` (Attributes) the network configuration of the instance. (see [below for nested schema](#nestedatt--network)) - `network` (Attributes) the network configuration of the instance. (see [below for nested schema](#nestedatt--network))
- `retention_days` (Number) The days for how long the backup files should be stored before cleaned up. 30 to 365 - `retention_days` (Number) The days for how long the backup files should be stored before cleaned up. 30 to 365
@ -131,8 +107,6 @@ import {
### Optional ### Optional
- `encryption` (Attributes) this defines which key to use for storage encryption (see [below for nested schema](#nestedatt--encryption)) - `encryption` (Attributes) this defines which key to use for storage encryption (see [below for nested schema](#nestedatt--encryption))
- `flavor` (Attributes, Deprecated) (see [below for nested schema](#nestedatt--flavor))
- `flavor_id` (String) The id of the instance flavor.
- `instance_id` (String) The ID of the instance. - `instance_id` (String) The ID of the instance.
- `project_id` (String) The STACKIT project ID. - `project_id` (String) The STACKIT project ID.
- `region` (String) The region which should be addressed - `region` (String) The region which should be addressed
@ -182,17 +156,3 @@ Required:
- `kek_key_ring_id` (String) The keyring identifier - `kek_key_ring_id` (String) The keyring identifier
- `kek_key_version` (String) The key version - `kek_key_version` (String) The key version
- `service_account` (String) - `service_account` (String)
<a id="nestedatt--flavor"></a>
### Nested Schema for `flavor`
Optional:
- `cpu` (Number, Deprecated)
- `ram` (Number, Deprecated)
Read-Only:
- `description` (String)
- `id` (String)

View file

@ -1,30 +1,3 @@
# NOTE: flavor handling will change in future
# V2 compatible flavor usage (example without encryption)
resource "stackitprivatepreview_postgresflexalpha_instance" "example-instance" {
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 = {
cpu = 2
ram = 4
}
replicas = 1
storage = {
performance_class = "premium-perf2-stackit"
size = 10
}
network = {
acl = ["XXX.XXX.XXX.X/XX", "XX.XXX.XX.X/XX"]
access_scope = "PUBLIC"
}
version = 17
}
# future use of flavor (implemented in V3 API)
# first determine flavor and then use the flavor_id
resource "stackitprivatepreview_postgresflexalpha_instance" "example-instance" { resource "stackitprivatepreview_postgresflexalpha_instance" "example-instance" {
project_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" project_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
name = "example-instance" name = "example-instance"

View file

@ -1,28 +1,3 @@
# NOTE: flavor handling will change in future
# V2 compatible flavor usage
resource "stackitprivatepreview_sqlserverflexbeta_instance" "instance" {
project_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
name = "example-instance"
backup_schedule = "0 3 * * *"
retention_days = 31
flavor = {
cpu = 2
ram = 4
}
storage = {
class = "premium-perf2-stackit"
size = 50
}
version = 2022
network = {
acl = ["XXX.XXX.XXX.X/XX", "XX.XXX.XX.X/XX"]
access_scope = "SNA"
}
}
# future use of flavor (implemented in V3 API)
# first determine flavor and then use the flavor_id
# without encryption and SNA # without encryption and SNA
resource "stackitprivatepreview_sqlserverflexbeta_instance" "instance" { resource "stackitprivatepreview_sqlserverflexbeta_instance" "instance" {
project_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" project_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"

View file

@ -172,12 +172,12 @@ func workDocs() error {
case "data-sources": case "data-sources":
dataSources[matches[0][1]] = append(dataSources[matches[0][1]], ResItem{ dataSources[matches[0][1]] = append(dataSources[matches[0][1]], ResItem{
ItemName: matches[0][2], ItemName: matches[0][2],
ItemLink: fmt.Sprintf("/docs/docs/%s/%s", entry.Name(), matches[0][0]), ItemLink: fmt.Sprintf("docs/%s/%s", entry.Name(), matches[0][0]),
}) })
case "resources": case "resources":
resources[matches[0][1]] = append(resources[matches[0][1]], ResItem{ resources[matches[0][1]] = append(resources[matches[0][1]], ResItem{
ItemName: matches[0][2], ItemName: matches[0][2],
ItemLink: fmt.Sprintf("/docs/docs/%s/%s", entry.Name(), matches[0][0]), ItemLink: fmt.Sprintf("docs/%s/%s", entry.Name(), matches[0][0]),
}) })
default: default:
return fmt.Errorf("this should never have happened") return fmt.Errorf("this should never have happened")

253
go.mod
View file

@ -1,25 +1,26 @@
module tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview module tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview
go 1.26.2 go 1.25.6
require ( require (
github.com/SladkyCitron/slogcolor v1.9.0 github.com/SladkyCitron/slogcolor v1.8.0
github.com/golang-jwt/jwt/v5 v5.3.1
github.com/google/go-cmp v0.7.0 github.com/google/go-cmp v0.7.0
github.com/google/uuid v1.6.0 github.com/google/uuid v1.6.0
github.com/hashicorp/terraform-plugin-framework v1.19.0 github.com/hashicorp/terraform-plugin-framework v1.18.0
github.com/hashicorp/terraform-plugin-framework-validators v0.19.0 github.com/hashicorp/terraform-plugin-framework-validators v0.19.0
github.com/hashicorp/terraform-plugin-go v0.31.0 github.com/hashicorp/terraform-plugin-go v0.30.0
github.com/hashicorp/terraform-plugin-log v0.10.0 github.com/hashicorp/terraform-plugin-log v0.10.0
github.com/hashicorp/terraform-plugin-testing v1.16.0 github.com/hashicorp/terraform-plugin-testing v1.14.0
github.com/iancoleman/strcase v0.3.0 github.com/iancoleman/strcase v0.3.0
github.com/ivanpirog/coloredcobra v1.0.1 github.com/ivanpirog/coloredcobra v1.0.1
github.com/jarcoal/httpmock v1.4.1 github.com/jarcoal/httpmock v1.4.1
github.com/joho/godotenv v1.5.1 github.com/joho/godotenv v1.5.1
github.com/ldez/go-git-cmd-wrapper/v2 v2.9.1 github.com/ldez/go-git-cmd-wrapper/v2 v2.9.1
github.com/spf13/cobra v1.10.2 github.com/spf13/cobra v1.10.2
github.com/stackitcloud/stackit-sdk-go/core v0.26.0 github.com/stackitcloud/stackit-sdk-go/core v0.22.0
github.com/stackitcloud/stackit-sdk-go/services/postgresflex v1.8.0 github.com/stackitcloud/stackit-sdk-go/services/postgresflex v1.4.0
github.com/stackitcloud/stackit-sdk-go/services/sqlserverflex v1.10.0 github.com/stackitcloud/stackit-sdk-go/services/sqlserverflex v1.5.0
github.com/teambition/rrule-go v1.8.2 github.com/teambition/rrule-go v1.8.2
gopkg.in/yaml.v3 v3.0.1 gopkg.in/yaml.v3 v3.0.1
) )
@ -27,77 +28,261 @@ require (
require github.com/hashicorp/go-retryablehttp v0.7.8 // indirect require github.com/hashicorp/go-retryablehttp v0.7.8 // indirect
require ( require (
4d63.com/gocheckcompilerdirectives v1.3.0 // indirect
4d63.com/gochecknoglobals v0.2.2 // indirect
codeberg.org/chavacava/garif v0.2.0 // indirect
codeberg.org/polyfloyd/go-errorlint v1.9.0 // indirect
dario.cat/mergo v1.0.1 // indirect dario.cat/mergo v1.0.1 // indirect
github.com/BurntSushi/toml v1.2.1 // indirect dev.gaijin.team/go/exhaustruct/v4 v4.0.0 // indirect
dev.gaijin.team/go/golib v0.6.0 // indirect
github.com/4meepo/tagalign v1.4.3 // indirect
github.com/Abirdcfly/dupword v0.1.7 // indirect
github.com/AdminBenni/iota-mixing v1.0.0 // indirect
github.com/AlwxSin/noinlineerr v1.0.5 // indirect
github.com/Antonboom/errname v1.1.1 // indirect
github.com/Antonboom/nilnil v1.1.1 // indirect
github.com/Antonboom/testifylint v1.6.4 // indirect
github.com/BurntSushi/toml v1.6.0 // indirect
github.com/Djarvur/go-err113 v0.1.1 // indirect
github.com/Kunde21/markdownfmt/v3 v3.1.0 // indirect github.com/Kunde21/markdownfmt/v3 v3.1.0 // indirect
github.com/Masterminds/goutils v1.1.1 // indirect github.com/Masterminds/goutils v1.1.1 // indirect
github.com/Masterminds/semver/v3 v3.2.0 // indirect github.com/Masterminds/semver/v3 v3.4.0 // indirect
github.com/Masterminds/sprig/v3 v3.2.3 // indirect github.com/Masterminds/sprig/v3 v3.2.3 // indirect
github.com/ProtonMail/go-crypto v1.4.1 // indirect github.com/MirrexOne/unqueryvet v1.5.4 // indirect
github.com/OpenPeeDeeP/depguard/v2 v2.2.1 // indirect
github.com/ProtonMail/go-crypto v1.4.0 // indirect
github.com/agext/levenshtein v1.2.3 // indirect github.com/agext/levenshtein v1.2.3 // indirect
github.com/alecthomas/chroma/v2 v2.23.1 // indirect
github.com/alecthomas/go-check-sumtype v0.3.1 // indirect
github.com/alexkohler/nakedret/v2 v2.0.6 // indirect
github.com/alexkohler/prealloc v1.1.0 // indirect
github.com/alfatraining/structtag v1.0.0 // indirect
github.com/alingse/asasalint v0.0.11 // indirect
github.com/alingse/nilnesserr v0.2.0 // indirect
github.com/apparentlymart/go-textseg/v15 v15.0.0 // indirect github.com/apparentlymart/go-textseg/v15 v15.0.0 // indirect
github.com/armon/go-radix v1.0.0 // indirect github.com/armon/go-radix v1.0.0 // indirect
github.com/ashanbrown/forbidigo/v2 v2.3.0 // indirect
github.com/ashanbrown/makezero/v2 v2.1.0 // indirect
github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/bgentry/speakeasy v0.1.0 // indirect github.com/bgentry/speakeasy v0.1.0 // indirect
github.com/bmatcuk/doublestar/v4 v4.10.0 // indirect github.com/bkielbasa/cyclop v1.2.3 // indirect
github.com/blizzy78/varnamelen v0.8.0 // indirect
github.com/bmatcuk/doublestar/v4 v4.9.1 // indirect
github.com/bombsimon/wsl/v4 v4.7.0 // indirect
github.com/bombsimon/wsl/v5 v5.6.0 // indirect
github.com/breml/bidichk v0.3.3 // indirect
github.com/breml/errchkjson v0.4.1 // indirect
github.com/butuzov/ireturn v0.4.0 // indirect
github.com/butuzov/mirror v1.3.0 // indirect
github.com/catenacyber/perfsprint v0.10.1 // indirect
github.com/ccojocar/zxcvbn-go v1.0.4 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/charithe/durationcheck v0.0.11 // indirect
github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc // indirect
github.com/charmbracelet/lipgloss v1.1.0 // indirect
github.com/charmbracelet/x/ansi v0.10.1 // indirect
github.com/charmbracelet/x/cellbuf v0.0.13-0.20250311204145-2c3ea96c31dd // indirect
github.com/charmbracelet/x/term v0.2.1 // indirect
github.com/ckaznocha/intrange v0.3.1 // indirect
github.com/cloudflare/circl v1.6.3 // indirect github.com/cloudflare/circl v1.6.3 // indirect
github.com/fatih/color v1.19.0 // indirect github.com/curioswitch/go-reassign v0.3.0 // indirect
github.com/golang-jwt/jwt/v5 v5.3.1 // indirect github.com/daixiang0/gci v0.13.7 // indirect
github.com/dave/dst v0.27.3 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/denis-tingaikin/go-header v0.5.0 // indirect
github.com/dlclark/regexp2 v1.11.5 // indirect
github.com/ettle/strcase v0.2.0 // indirect
github.com/fatih/color v1.18.0 // indirect
github.com/fatih/structtag v1.2.0 // indirect
github.com/firefart/nonamedreturns v1.0.6 // indirect
github.com/fsnotify/fsnotify v1.5.4 // indirect
github.com/fzipp/gocyclo v0.6.0 // indirect
github.com/ghostiam/protogetter v0.3.20 // indirect
github.com/go-critic/go-critic v0.14.3 // indirect
github.com/go-toolsmith/astcast v1.1.0 // indirect
github.com/go-toolsmith/astcopy v1.1.0 // indirect
github.com/go-toolsmith/astequal v1.2.0 // indirect
github.com/go-toolsmith/astfmt v1.1.0 // indirect
github.com/go-toolsmith/astp v1.1.0 // indirect
github.com/go-toolsmith/strparse v1.1.0 // indirect
github.com/go-toolsmith/typep v1.1.0 // indirect
github.com/go-viper/mapstructure/v2 v2.5.0 // indirect
github.com/go-xmlfmt/xmlfmt v1.1.3 // indirect
github.com/gobwas/glob v0.2.3 // indirect
github.com/godoc-lint/godoc-lint v0.11.2 // indirect
github.com/gofrs/flock v0.13.0 // indirect
github.com/golang/protobuf v1.5.4 // indirect github.com/golang/protobuf v1.5.4 // indirect
github.com/golangci/asciicheck v0.5.0 // indirect
github.com/golangci/dupl v0.0.0-20250308024227-f665c8d69b32 // indirect
github.com/golangci/go-printf-func-name v0.1.1 // indirect
github.com/golangci/gofmt v0.0.0-20250106114630-d62b90e6713d // indirect
github.com/golangci/golangci-lint/v2 v2.11.2 // indirect
github.com/golangci/golines v0.15.0 // indirect
github.com/golangci/misspell v0.8.0 // indirect
github.com/golangci/plugin-module-register v0.1.2 // indirect
github.com/golangci/revgrep v0.8.0 // indirect
github.com/golangci/swaggoswag v0.0.0-20250504205917-77f2aca3143e // indirect
github.com/golangci/unconvert v0.0.0-20250410112200-a129a6e6413e // indirect
github.com/gordonklaus/ineffassign v0.2.0 // indirect
github.com/gostaticanalysis/analysisutil v0.7.1 // indirect
github.com/gostaticanalysis/comment v1.5.0 // indirect
github.com/gostaticanalysis/forcetypeassert v0.2.0 // indirect
github.com/gostaticanalysis/nilerr v0.1.2 // indirect
github.com/hashicorp/cli v1.1.7 // indirect github.com/hashicorp/cli v1.1.7 // indirect
github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect
github.com/hashicorp/go-checkpoint v0.5.0 // indirect github.com/hashicorp/go-checkpoint v0.5.0 // indirect
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
github.com/hashicorp/go-cty v1.5.0 // indirect github.com/hashicorp/go-cty v1.5.0 // indirect
github.com/hashicorp/go-hclog v1.6.3 // indirect github.com/hashicorp/go-hclog v1.6.3 // indirect
github.com/hashicorp/go-immutable-radix/v2 v2.1.0 // indirect
github.com/hashicorp/go-multierror v1.1.1 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect
github.com/hashicorp/go-plugin v1.8.0 // indirect github.com/hashicorp/go-plugin v1.7.0 // indirect
github.com/hashicorp/go-uuid v1.0.3 // indirect github.com/hashicorp/go-uuid v1.0.3 // indirect
github.com/hashicorp/go-version v1.9.0 // indirect github.com/hashicorp/go-version v1.8.0 // indirect
github.com/hashicorp/hc-install v0.9.5 // indirect github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect
github.com/hashicorp/hc-install v0.9.3 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/hashicorp/hcl/v2 v2.24.0 // indirect github.com/hashicorp/hcl/v2 v2.24.0 // indirect
github.com/hashicorp/logutils v1.0.0 // indirect github.com/hashicorp/logutils v1.0.0 // indirect
github.com/hashicorp/terraform-exec v0.25.2 // indirect github.com/hashicorp/terraform-exec v0.25.0 // indirect
github.com/hashicorp/terraform-json v0.27.3-0.20260213134036-298b8f6b673a // indirect github.com/hashicorp/terraform-json v0.27.2 // indirect
github.com/hashicorp/terraform-plugin-docs v0.25.0 // indirect github.com/hashicorp/terraform-plugin-docs v0.24.0 // indirect
github.com/hashicorp/terraform-plugin-sdk/v2 v2.40.1 // indirect github.com/hashicorp/terraform-plugin-sdk/v2 v2.39.0 // indirect
github.com/hashicorp/terraform-registry-address v0.4.0 // indirect github.com/hashicorp/terraform-registry-address v0.4.0 // indirect
github.com/hashicorp/terraform-svchost v0.2.1 // indirect github.com/hashicorp/terraform-svchost v0.2.1 // indirect
github.com/hashicorp/yamux v0.1.2 // indirect github.com/hashicorp/yamux v0.1.2 // indirect
github.com/hexops/gotextdiff v1.0.3 // indirect
github.com/huandu/xstrings v1.3.3 // indirect github.com/huandu/xstrings v1.3.3 // indirect
github.com/imdario/mergo v0.3.15 // indirect github.com/imdario/mergo v0.3.15 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/jgautheron/goconst v1.8.2 // indirect
github.com/jingyugao/rowserrcheck v1.1.1 // indirect
github.com/jjti/go-spancheck v0.6.5 // indirect
github.com/julz/importas v0.2.0 // indirect
github.com/karamaru-alpha/copyloopvar v1.2.2 // indirect
github.com/kisielk/errcheck v1.10.0 // indirect
github.com/kkHAIKE/contextcheck v1.1.6 // indirect
github.com/kr/text v0.2.0 // indirect
github.com/kulti/thelper v0.7.1 // indirect
github.com/kunwardeep/paralleltest v1.0.15 // indirect
github.com/lasiar/canonicalheader v1.1.2 // indirect
github.com/ldez/exptostd v0.4.5 // indirect
github.com/ldez/gomoddirectives v0.8.0 // indirect
github.com/ldez/grignotin v0.10.1 // indirect
github.com/ldez/structtags v0.6.1 // indirect
github.com/ldez/tagliatelle v0.7.2 // indirect
github.com/ldez/usetesting v0.5.0 // indirect
github.com/leonklingele/grouper v1.1.2 // indirect
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
github.com/macabu/inamedparam v0.2.0 // indirect
github.com/magiconair/properties v1.8.6 // indirect
github.com/manuelarte/embeddedstructfieldcheck v0.4.0 // indirect
github.com/manuelarte/funcorder v0.5.0 // indirect
github.com/maratori/testableexamples v1.0.1 // indirect
github.com/maratori/testpackage v1.1.2 // indirect
github.com/matoous/godox v1.1.0 // indirect
github.com/mattn/go-colorable v0.1.14 // indirect github.com/mattn/go-colorable v0.1.14 // indirect
github.com/mattn/go-isatty v0.0.22 // indirect github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mattn/go-runewidth v0.0.9 // indirect github.com/mattn/go-runewidth v0.0.16 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect
github.com/mgechev/revive v1.15.0 // indirect
github.com/mitchellh/copystructure v1.2.0 // indirect github.com/mitchellh/copystructure v1.2.0 // indirect
github.com/mitchellh/go-homedir v1.1.0 // indirect
github.com/mitchellh/go-testing-interface v1.14.1 // indirect github.com/mitchellh/go-testing-interface v1.14.1 // indirect
github.com/mitchellh/go-wordwrap v1.0.1 // indirect github.com/mitchellh/go-wordwrap v1.0.1 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/mitchellh/reflectwalk v1.0.2 // indirect github.com/mitchellh/reflectwalk v1.0.2 // indirect
github.com/moricho/tparallel v0.3.2 // indirect
github.com/muesli/termenv v0.16.0 // indirect
github.com/nakabonne/nestif v0.3.1 // indirect
github.com/nishanths/exhaustive v0.12.0 // indirect
github.com/nishanths/predeclared v0.2.2 // indirect
github.com/nunnatsa/ginkgolinter v0.23.0 // indirect
github.com/oklog/run v1.2.0 // indirect github.com/oklog/run v1.2.0 // indirect
github.com/pelletier/go-toml v1.9.5 // indirect
github.com/pelletier/go-toml/v2 v2.2.4 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/posener/complete v1.2.3 // indirect github.com/posener/complete v1.2.3 // indirect
github.com/prometheus/client_golang v1.12.1 // indirect
github.com/prometheus/client_model v0.2.0 // indirect
github.com/prometheus/common v0.32.1 // indirect
github.com/prometheus/procfs v0.7.3 // indirect
github.com/quasilyte/go-ruleguard v0.4.5 // indirect
github.com/quasilyte/go-ruleguard/dsl v0.3.23 // indirect
github.com/quasilyte/gogrep v0.5.0 // indirect
github.com/quasilyte/regex/syntax v0.0.0-20210819130434-b3f0c404a727 // indirect
github.com/quasilyte/stdinfo v0.0.0-20220114132959-f7386bf02567 // indirect
github.com/raeperd/recvcheck v0.2.0 // indirect
github.com/rivo/uniseg v0.4.7 // indirect
github.com/rogpeppe/go-internal v1.14.1 // indirect
github.com/ryancurrah/gomodguard v1.4.1 // indirect
github.com/ryanrolds/sqlclosecheck v0.5.1 // indirect
github.com/sanposhiho/wastedassign/v2 v2.1.0 // indirect
github.com/santhosh-tekuri/jsonschema/v6 v6.0.2 // indirect
github.com/sashamelentyev/interfacebloat v1.1.0 // indirect
github.com/sashamelentyev/usestdlibvars v1.29.0 // indirect
github.com/securego/gosec/v2 v2.24.7 // indirect
github.com/shopspring/decimal v1.3.1 // indirect github.com/shopspring/decimal v1.3.1 // indirect
github.com/sirupsen/logrus v1.9.4 // indirect
github.com/sivchari/containedctx v1.0.3 // indirect
github.com/sonatard/noctx v0.5.0 // indirect
github.com/sourcegraph/go-diff v0.7.0 // indirect
github.com/spf13/afero v1.15.0 // indirect
github.com/spf13/cast v1.5.0 // indirect github.com/spf13/cast v1.5.0 // indirect
github.com/spf13/jwalterweatherman v1.1.0 // indirect
github.com/spf13/pflag v1.0.10 // indirect github.com/spf13/pflag v1.0.10 // indirect
github.com/spf13/viper v1.12.0 // indirect
github.com/ssgreg/nlreturn/v2 v2.2.1 // indirect
github.com/stbenjam/no-sprintf-host-port v0.3.1 // indirect
github.com/stretchr/objx v0.5.2 // indirect
github.com/stretchr/testify v1.11.1 // indirect github.com/stretchr/testify v1.11.1 // indirect
github.com/subosito/gotenv v1.4.1 // indirect
github.com/tetafro/godot v1.5.4 // indirect
github.com/timakin/bodyclose v0.0.0-20241222091800-1db5c5ca4d67 // indirect
github.com/timonwong/loggercheck v0.11.0 // indirect
github.com/tomarrell/wrapcheck/v2 v2.12.0 // indirect
github.com/tommy-muehle/go-mnd/v2 v2.5.1 // indirect
github.com/ultraware/funlen v0.2.0 // indirect
github.com/ultraware/whitespace v0.2.0 // indirect
github.com/uudashr/gocognit v1.2.1 // indirect
github.com/uudashr/iface v1.4.1 // indirect
github.com/vmihailenco/msgpack v4.0.4+incompatible // indirect github.com/vmihailenco/msgpack v4.0.4+incompatible // indirect
github.com/vmihailenco/msgpack/v5 v5.4.1 // indirect github.com/vmihailenco/msgpack/v5 v5.4.1 // indirect
github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect
github.com/xen0n/gosmopolitan v1.3.0 // indirect
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
github.com/yagipy/maintidx v1.0.0 // indirect
github.com/yeya24/promlinter v0.3.0 // indirect
github.com/ykadowak/zerologlint v0.1.5 // indirect
github.com/yuin/goldmark v1.7.7 // indirect github.com/yuin/goldmark v1.7.7 // indirect
github.com/yuin/goldmark-meta v1.1.0 // indirect github.com/yuin/goldmark-meta v1.1.0 // indirect
github.com/zclconf/go-cty v1.18.1 // indirect github.com/zclconf/go-cty v1.18.0 // indirect
gitlab.com/bosi/decorder v0.4.2 // indirect
go-simpler.org/musttag v0.14.0 // indirect
go-simpler.org/sloglint v0.11.1 // indirect
go.abhg.dev/goldmark/frontmatter v0.2.0 // indirect go.abhg.dev/goldmark/frontmatter v0.2.0 // indirect
golang.org/x/crypto v0.50.0 // indirect go.augendre.info/arangolint v0.4.0 // indirect
golang.org/x/exp v0.0.0-20230626212559-97b1e661b5df // indirect go.augendre.info/fatcontext v0.9.0 // indirect
golang.org/x/mod v0.35.0 // indirect go.uber.org/multierr v1.10.0 // indirect
golang.org/x/net v0.53.0 // indirect go.uber.org/zap v1.27.0 // indirect
golang.org/x/sync v0.20.0 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect
golang.org/x/sys v0.43.0 // indirect golang.org/x/crypto v0.48.0 // indirect
golang.org/x/text v0.36.0 // indirect golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b // indirect
golang.org/x/tools v0.44.0 // indirect golang.org/x/exp/typeparams v0.0.0-20260209203927-2842357ff358 // indirect
golang.org/x/mod v0.33.0 // indirect
golang.org/x/net v0.51.0 // indirect
golang.org/x/sync v0.19.0 // indirect
golang.org/x/sys v0.41.0 // indirect
golang.org/x/text v0.34.0 // indirect
golang.org/x/tools v0.42.0 // indirect
google.golang.org/appengine v1.6.8 // indirect google.golang.org/appengine v1.6.8 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20260504160031-60b97b32f348 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20260226221140-a57be14db171 // indirect
google.golang.org/grpc v1.81.0 // indirect google.golang.org/grpc v1.79.2 // indirect
google.golang.org/protobuf v1.36.11 // indirect google.golang.org/protobuf v1.36.11 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect
honnef.co/go/tools v0.7.0 // indirect
mvdan.cc/gofumpt v0.9.2 // indirect
mvdan.cc/unparam v0.0.0-20251027182757-5beb8c8f8f15 // indirect
) )

997
go.sum

File diff suppressed because it is too large Load diff

View file

@ -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##"]
}

View file

@ -13,11 +13,7 @@ resource "stackitprivatepreview_postgresflexalpha_instance" "msh-sna-pe-example"
name = "mshpetest2" name = "mshpetest2"
backup_schedule = "0 0 * * *" backup_schedule = "0 0 * * *"
retention_days = 45 retention_days = 45
# flavor_id = data.stackitprivatepreview_postgresflexalpha_flavor.pgsql_flavor.flavor_id flavor_id = data.stackitprivatepreview_postgresflexalpha_flavor.pgsql_flavor.flavor_id
flavor = {
cpu = 2
ram = 4
}
replicas = 1 replicas = 1
storage = { storage = {
# class = "premium-perf2-stackit" # class = "premium-perf2-stackit"
@ -70,8 +66,7 @@ resource "stackitprivatepreview_postgresflexalpha_user" "ptlsdbadminuser" {
project_id = var.project_id project_id = var.project_id
instance_id = stackitprivatepreview_postgresflexalpha_instance.msh-sna-pe-example.instance_id instance_id = stackitprivatepreview_postgresflexalpha_instance.msh-sna-pe-example.instance_id
name = var.db_admin_username name = var.db_admin_username
roles = ["createdb", "login"] roles = ["createdb", "login", "login"]
# roles = ["createdb", "login", "login"]
# roles = ["createdb", "login", "createrole"] # roles = ["createdb", "login", "createrole"]
} }
@ -115,11 +110,7 @@ output "psql_user_password" {
sensitive = true sensitive = true
} }
# output "psql_user_conn" { output "psql_user_conn" {
# value = stackitprivatepreview_postgresflexalpha_user.ptlsdbuser.connection.host value = stackitprivatepreview_postgresflexalpha_user.ptlsdbuser.connection_string
# sensitive = true sensitive = true
# }
output "determined_flavor_id" {
value = stackitprivatepreview_postgresflexalpha_instance.msh-sna-pe-example.flavor_id
} }

View file

@ -1,5 +1,7 @@
#!/usr/bin/env bash #!/usr/bin/env bash
# ./tf.sh apply > >(tee -a stdout.log) 2> >(tee -a stderr.log >&2) # ./tf.sh apply > >(tee -a stdout.log) 2> >(tee -a stderr.log >&2)
usage() { usage() {
@ -10,8 +12,7 @@ usage() {
[ $# -eq 0 ] && usage [ $# -eq 0 ] && usage
CONFIG_FOLDER=$(dirname "$0") CONFIG_FOLDER=$(dirname "$0")
# BINARY=terraform BINARY=terraform
BINARY=tofu
ADD="" ADD=""

View file

@ -2,7 +2,7 @@ provider:
name: stackitprivatepreview name: stackitprivatepreview
data_sources: data_sources:
collations: collation:
read: read:
path: /v3beta1/projects/{projectId}/regions/{region}/instances/{instanceId}/collations path: /v3beta1/projects/{projectId}/regions/{region}/instances/{instanceId}/collations
method: GET method: GET

View file

@ -3,7 +3,7 @@ provider:
name: stackitprivatepreview name: stackitprivatepreview
data_sources: data_sources:
versions: version:
read: read:
path: /v3beta1/projects/{projectId}/regions/{region}/versions path: /v3beta1/projects/{projectId}/regions/{region}/versions
method: GET method: GET

View file

@ -209,8 +209,8 @@ func (r *databaseResource) Create(
) )
database, err := postgresflexalphaWait.GetDatabaseByIdWaitHandler(ctx, r.client.DefaultAPI, projectID, instanceID, region, databaseID). database, err := postgresflexalphaWait.GetDatabaseByIdWaitHandler(ctx, r.client.DefaultAPI, projectID, instanceID, region, databaseID).
SetTimeout(30 * time.Minute). SetTimeout(15 * time.Minute).
SetSleepBeforeWait(10 * time.Second). SetSleepBeforeWait(15 * time.Second).
WaitWithContext(ctx) WaitWithContext(ctx)
if err != nil { if err != nil {
core.LogAndAddError( core.LogAndAddError(
@ -279,8 +279,8 @@ func (r *databaseResource) Read(
) )
databaseResp, err := postgresflexalphaWait.GetDatabaseByIdWaitHandler(ctx, r.client.DefaultAPI, projectID, instanceID, region, databaseID). databaseResp, err := postgresflexalphaWait.GetDatabaseByIdWaitHandler(ctx, r.client.DefaultAPI, projectID, instanceID, region, databaseID).
SetTimeout(30 * time.Minute). SetTimeout(15 * time.Minute).
SetSleepBeforeWait(10 * time.Second). SetSleepBeforeWait(15 * time.Second).
WaitWithContext(ctx) WaitWithContext(ctx)
if err != nil { if err != nil {
core.LogAndAddError( core.LogAndAddError(
@ -386,8 +386,8 @@ func (r *databaseResource) Update(
ctx = core.LogResponse(ctx) ctx = core.LogResponse(ctx)
databaseResp, err := postgresflexalphaWait.GetDatabaseByIdWaitHandler(ctx, r.client.DefaultAPI, projectId, instanceId, region, databaseId). databaseResp, err := postgresflexalphaWait.GetDatabaseByIdWaitHandler(ctx, r.client.DefaultAPI, projectId, instanceId, region, databaseId).
SetTimeout(30 * time.Minute). SetTimeout(15 * time.Minute).
SetSleepBeforeWait(10 * time.Second). SetSleepBeforeWait(15 * time.Second).
WaitWithContext(ctx) WaitWithContext(ctx)
if err != nil { if err != nil {
core.LogAndAddError(ctx, &resp.Diagnostics, "error updating database", err.Error()) core.LogAndAddError(ctx, &resp.Diagnostics, "error updating database", err.Error())

View file

@ -11,7 +11,7 @@ import (
"github.com/stackitcloud/stackit-sdk-go/services/postgresflex/v3alpha1api" "github.com/stackitcloud/stackit-sdk-go/services/postgresflex/v3alpha1api"
"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/conversion"
postgresflexalphaGen "tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit/internal/services/postgresflexalpha/flavor/datasources_gen" postgresflexalphaGen "tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit/internal/services/postgresflexalpha/flavors/datasources_gen"
postgresflexUtils "tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit/internal/services/postgresflexalpha/utils" postgresflexUtils "tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit/internal/services/postgresflexalpha/utils"
"tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit/internal/utils" "tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit/internal/utils"
@ -220,24 +220,14 @@ func (r *flavorDataSource) Read(ctx context.Context, req datasource.ReadRequest,
} else { } else {
var scList []attr.Value var scList []attr.Value
for _, sc := range f.StorageClasses { for _, sc := range f.StorageClasses {
mIop := types.Int32Null()
if val, ok := sc.GetMaxIoPerSecOk(); ok {
mIop = types.Int32Value(*val)
}
mThrough := types.Int32Null()
if val, ok := sc.GetMaxThroughInMbOk(); ok {
mThrough = types.Int32Value(*val)
}
scList = append( scList = append(
scList, scList,
postgresflexalphaGen.NewStorageClassesValueMust( postgresflexalphaGen.NewStorageClassesValueMust(
postgresflexalphaGen.StorageClassesValue{}.AttributeTypes(ctx), postgresflexalphaGen.StorageClassesValue{}.AttributeTypes(ctx),
map[string]attr.Value{ map[string]attr.Value{
"class": types.StringValue(sc.Class), "class": types.StringValue(sc.Class),
"max_io_per_sec": mIop, "max_io_per_sec": types.Int32Value(sc.MaxIoPerSec),
"max_through_in_mb": mThrough, "max_through_in_mb": types.Int32Value(sc.MaxThroughInMb),
}, },
), ),
) )

View file

@ -1,4 +1,4 @@
package postgresflexalphaflavors package postgresflexalpha
import ( import (
"context" "context"

View file

@ -1,65 +0,0 @@
package postgresflexalphaflavors
import (
"context"
"fmt"
"github.com/stackitcloud/stackit-sdk-go/services/postgresflex/v3alpha1api"
)
type flavorsClientReader interface {
GetFlavorsRequest(
ctx context.Context,
projectId, region string,
) v3alpha1api.ApiGetFlavorsRequestRequest
}
func getAllFlavors(ctx context.Context, client flavorsClientReader, projectId, region string) (
[]v3alpha1api.ListFlavors,
error,
) {
getAllFilter := func(_ v3alpha1api.ListFlavors) bool { return true }
flavorList, err := getFlavorsByFilter(ctx, client, projectId, region, getAllFilter)
if err != nil {
return nil, err
}
return flavorList, nil
}
// getFlavorsByFilter is a helper function to retrieve flavors using a filtern function.
// Hint: The API does not have a GetFlavors endpoint, only ListFlavors
func getFlavorsByFilter(
ctx context.Context,
client flavorsClientReader,
projectId, region string,
filter func(db v3alpha1api.ListFlavors) bool,
) ([]v3alpha1api.ListFlavors, error) {
if projectId == "" || region == "" {
return nil, fmt.Errorf("listing postgresflex flavors: projectId and region are required")
}
const pageSize = 25
var result = make([]v3alpha1api.ListFlavors, 0)
for page := int32(1); ; page++ {
res, err := client.GetFlavorsRequest(ctx, projectId, region).
Page(page).Size(pageSize).Sort(v3alpha1api.FLAVORSORT_ID_ASC).Execute()
if err != nil {
return nil, fmt.Errorf("requesting flavors list (page %d): %w", page, err)
}
// If the API returns no flavors, we have reached the end of the list.
if len(res.Flavors) == 0 {
break
}
for _, flavor := range res.Flavors {
if filter(flavor) {
result = append(result, flavor)
}
}
}
return result, nil
}

View file

@ -1,135 +0,0 @@
package postgresflexalphaflavors
/*
import (
"context"
"testing"
postgresflex "github.com/stackitcloud/stackit-sdk-go/services/postgresflex/v3alpha1api"
)
type mockRequest struct {
executeFunc func() (*postgresflex.GetFlavorsResponse, error)
}
func (m *mockRequest) Page(_ int32) postgresflex.ApiGetFlavorsRequestRequest { return m }
func (m *mockRequest) Size(_ int32) postgresflex.ApiGetFlavorsRequestRequest { return m }
func (m *mockRequest) Sort(_ postgresflex.FlavorSort) postgresflex.ApiGetFlavorsRequestRequest {
return m
}
func (m *mockRequest) Execute() (*postgresflex.GetFlavorsResponse, error) {
return m.executeFunc()
}
type mockFlavorsClient struct {
executeRequest func() postgresflex.ApiGetFlavorsRequestRequest
}
func (m *mockFlavorsClient) GetFlavorsRequest(_ context.Context, _, _ string) postgresflex.ApiGetFlavorsRequestRequest {
return m.executeRequest()
}
var mockResp = func(page int32) (*postgresflex.GetFlavorsResponse, error) {
if page == 1 {
return &postgresflex.GetFlavorsResponse{
Flavors: []postgresflex.ListFlavors{
{Id: "flavor-1", Description: "first"},
{Id: "flavor-2", Description: "second"},
},
}, nil
}
if page == 2 {
return &postgresflex.GetFlavorsResponse{
Flavors: []postgresflex.ListFlavors{
{Id: "flavor-3", Description: "three"},
},
}, nil
}
return &postgresflex.GetFlavorsResponse{
Flavors: []postgresflex.ListFlavors{},
}, nil
}
func TestGetFlavorsByFilter(t *testing.T) {
tests := []struct {
description string
projectId string
region string
mockErr error
filter func(postgresflex.ListFlavors) bool
wantCount int
wantErr bool
}{
{
description: "Success - Get all flavors (2 pages)",
projectId: "pid", region: "reg",
filter: func(_ postgresflex.ListFlavors) bool { return true },
wantCount: 3,
wantErr: false,
},
{
description: "Success - Filter flavors by description",
projectId: "pid", region: "reg",
filter: func(f postgresflex.ListFlavors) bool { return f.Description == "first" },
wantCount: 1,
wantErr: false,
},
{
description: "Error - Missing parameters",
projectId: "", region: "reg",
wantErr: true,
},
}
for _, tt := range tests {
t.Run(
tt.description, func(t *testing.T) {
var currentPage int32
client := &mockFlavorsClient{
executeRequest: func() postgresflex.ApiGetFlavorsRequestRequest {
return mockRequest{
executeFunc: func() (*postgresflex.GetFlavorsResponse, error) {
currentPage++
return mockResp(currentPage)
},
}
},
}
actual, err := getFlavorsByFilter(context.Background(), client, tt.projectId, tt.region, tt.filter)
if (err != nil) != tt.wantErr {
t.Errorf("getFlavorsByFilter() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !tt.wantErr && len(actual) != tt.wantCount {
t.Errorf("getFlavorsByFilter() got %d flavors, want %d", len(actual), tt.wantCount)
}
},
)
}
}
func TestGetAllFlavors(t *testing.T) {
var currentPage int32
client := &mockFlavorsClient{
executeRequest: func() postgresflex.ApiGetFlavorsRequestRequest {
return mockRequest{
executeFunc: func() (*postgresflex.GetFlavorsResponse, error) {
currentPage++
return mockResp(currentPage)
},
}
},
}
res, err := getAllFlavors(context.Background(), client, "pid", "reg")
if err != nil {
t.Errorf("getAllFlavors() unexpected error: %v", err)
}
if len(res) != 3 {
t.Errorf("getAllFlavors() expected 3 flavor, got %d", len(res))
}
}
*/

View file

@ -115,12 +115,6 @@ func InstanceDataSourceSchema(ctx context.Context) schema.Schema {
Description: "Whether the instance can be deleted or not.", Description: "Whether the instance can be deleted or not.",
MarkdownDescription: "Whether the instance can be deleted or not.", MarkdownDescription: "Whether the instance can be deleted or not.",
}, },
"labels": schema.MapAttribute{
ElementType: types.StringType,
Computed: true,
Description: "Key-value pairs, 63 characters max, begin and end with an alphanumerical character,\nmay contain dashes (-), underscores (_), dots (.), and alphanumerics between. Key MUST be at least 1 character.\nMax 64 labels\nRegex for keys: ^(?=.{1,63}$)([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9]$\nRegex for values: ^(?=.{0,63}$)(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])*$\nThe stackit- prefix is reserved and cannot be used for Keys.\n",
MarkdownDescription: "Key-value pairs, 63 characters max, begin and end with an alphanumerical character,\nmay contain dashes (-), underscores (_), dots (.), and alphanumerics between. Key MUST be at least 1 character.\nMax 64 labels\nRegex for keys: ^(?=.{1,63}$)([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9]$\nRegex for values: ^(?=.{0,63}$)(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])*$\nThe stackit- prefix is reserved and cannot be used for Keys.\n",
},
"name": schema.StringAttribute{ "name": schema.StringAttribute{
Computed: true, Computed: true,
Description: "The name of the instance.", Description: "The name of the instance.",
@ -177,8 +171,8 @@ func InstanceDataSourceSchema(ctx context.Context) schema.Schema {
}, },
"retention_days": schema.Int64Attribute{ "retention_days": schema.Int64Attribute{
Computed: true, Computed: true,
Description: "How long backups are retained. The value can only be between 32 and 90 days.", Description: "How long backups are retained. The value can only be between 32 and 365 days.",
MarkdownDescription: "How long backups are retained. The value can only be between 32 and 90 days.", MarkdownDescription: "How long backups are retained. The value can only be between 32 and 365 days.",
}, },
"status": schema.StringAttribute{ "status": schema.StringAttribute{
Computed: true, Computed: true,
@ -225,7 +219,6 @@ type InstanceModel struct {
Id types.String `tfsdk:"tf_original_api_id"` Id types.String `tfsdk:"tf_original_api_id"`
InstanceId types.String `tfsdk:"instance_id"` InstanceId types.String `tfsdk:"instance_id"`
IsDeletable types.Bool `tfsdk:"is_deletable"` IsDeletable types.Bool `tfsdk:"is_deletable"`
Labels types.Map `tfsdk:"labels"`
Name types.String `tfsdk:"name"` Name types.String `tfsdk:"name"`
Network NetworkValue `tfsdk:"network"` Network NetworkValue `tfsdk:"network"`
ProjectId types.String `tfsdk:"project_id"` ProjectId types.String `tfsdk:"project_id"`

View file

@ -1,65 +0,0 @@
package postgresflexalpha
import (
"context"
"fmt"
"github.com/stackitcloud/stackit-sdk-go/services/postgresflex/v3alpha1api"
)
type flavorsClientReader interface {
GetFlavorsRequest(
ctx context.Context,
projectId, region string,
) v3alpha1api.ApiGetFlavorsRequestRequest
}
func getAllFlavors(ctx context.Context, client flavorsClientReader, projectId, region string) (
[]v3alpha1api.ListFlavors,
error,
) {
getAllFilter := func(_ v3alpha1api.ListFlavors) bool { return true }
flavorList, err := getFlavorsByFilter(ctx, client, projectId, region, getAllFilter)
if err != nil {
return nil, err
}
return flavorList, nil
}
// getFlavorsByFilter is a helper function to retrieve flavors using a filtern function.
// Hint: The API does not have a GetFlavors endpoint, only ListFlavors
func getFlavorsByFilter(
ctx context.Context,
client flavorsClientReader,
projectId, region string,
filter func(db v3alpha1api.ListFlavors) bool,
) ([]v3alpha1api.ListFlavors, error) {
if projectId == "" || region == "" {
return nil, fmt.Errorf("listing postgresflex flavors: projectId and region are required")
}
const pageSize = 25
var result = make([]v3alpha1api.ListFlavors, 0)
for page := int32(1); ; page++ {
res, err := client.GetFlavorsRequest(ctx, projectId, region).
Page(page).Size(pageSize).Sort(v3alpha1api.FLAVORSORT_ID_ASC).Execute()
if err != nil {
return nil, fmt.Errorf("requesting flavors list (page %d): %w", page, err)
}
// If the API returns no flavors, we have reached the end of the list.
if len(res.Flavors) == 0 {
break
}
for _, flavor := range res.Flavors {
if filter(flavor) {
result = append(result, flavor)
}
}
}
return result, nil
}

View file

@ -1,135 +0,0 @@
package postgresflexalpha
/*
import (
"context"
"testing"
postgresflex "github.com/stackitcloud/stackit-sdk-go/services/postgresflex/v3alpha1api"
)
type mockRequest struct {
executeFunc func() (*postgresflex.GetFlavorsResponse, error)
}
func (m *mockRequest) Page(_ int32) postgresflex.ApiGetFlavorsRequestRequest { return m }
func (m *mockRequest) Size(_ int32) postgresflex.ApiGetFlavorsRequestRequest { return m }
func (m *mockRequest) Sort(_ postgresflex.FlavorSort) postgresflex.ApiGetFlavorsRequestRequest {
return m
}
func (m *mockRequest) Execute() (*postgresflex.GetFlavorsResponse, error) {
return m.executeFunc()
}
type mockFlavorsClient struct {
executeRequest func() postgresflex.ApiGetFlavorsRequestRequest
}
func (m *mockFlavorsClient) GetFlavorsRequest(_ context.Context, _, _ string) postgresflex.ApiGetFlavorsRequestRequest {
return m.executeRequest()
}
var mockResp = func(page int32) (*postgresflex.GetFlavorsResponse, error) {
if page == 1 {
return &postgresflex.GetFlavorsResponse{
Flavors: []postgresflex.ListFlavors{
{Id: "flavor-1", Description: "first"},
{Id: "flavor-2", Description: "second"},
},
}, nil
}
if page == 2 {
return &postgresflex.GetFlavorsResponse{
Flavors: []postgresflex.ListFlavors{
{Id: "flavor-3", Description: "three"},
},
}, nil
}
return &postgresflex.GetFlavorsResponse{
Flavors: []postgresflex.ListFlavors{},
}, nil
}
func TestGetFlavorsByFilter(t *testing.T) {
tests := []struct {
description string
projectId string
region string
mockErr error
filter func(postgresflex.ListFlavors) bool
wantCount int
wantErr bool
}{
{
description: "Success - Get all flavors (2 pages)",
projectId: "pid", region: "reg",
filter: func(_ postgresflex.ListFlavors) bool { return true },
wantCount: 3,
wantErr: false,
},
{
description: "Success - Filter flavors by description",
projectId: "pid", region: "reg",
filter: func(f postgresflex.ListFlavors) bool { return f.Description == "first" },
wantCount: 1,
wantErr: false,
},
{
description: "Error - Missing parameters",
projectId: "", region: "reg",
wantErr: true,
},
}
for _, tt := range tests {
t.Run(
tt.description, func(t *testing.T) {
var currentPage int32
client := &mockFlavorsClient{
executeRequest: func() postgresflex.ApiGetFlavorsRequestRequest {
return mockRequest{
executeFunc: func() (*postgresflex.GetFlavorsResponse, error) {
currentPage++
return mockResp(currentPage)
},
}
},
}
actual, err := getFlavorsByFilter(context.Background(), client, tt.projectId, tt.region, tt.filter)
if (err != nil) != tt.wantErr {
t.Errorf("getFlavorsByFilter() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !tt.wantErr && len(actual) != tt.wantCount {
t.Errorf("getFlavorsByFilter() got %d flavors, want %d", len(actual), tt.wantCount)
}
},
)
}
}
func TestGetAllFlavors(t *testing.T) {
var currentPage int32
client := &mockFlavorsClient{
executeRequest: func() postgresflex.ApiGetFlavorsRequestRequest {
return mockRequest{
executeFunc: func() (*postgresflex.GetFlavorsResponse, error) {
currentPage++
return mockResp(currentPage)
},
}
},
}
res, err := getAllFlavors(context.Background(), client, "pid", "reg")
if err != nil {
t.Errorf("getAllFlavors() unexpected error: %v", err)
}
if len(res) != 3 {
t.Errorf("getAllFlavors() expected 3 flavor, got %d", len(res))
}
}
*/

View file

@ -16,7 +16,7 @@ import (
func mapGetInstanceResponseToModel( func mapGetInstanceResponseToModel(
ctx context.Context, ctx context.Context,
m *LocalInstanceModel, m *postgresflexalpharesource.InstanceModel,
resp *postgresflex.GetInstanceResponse, resp *postgresflex.GetInstanceResponse,
) error { ) error {
m.BackupSchedule = types.StringValue(resp.GetBackupSchedule()) m.BackupSchedule = types.StringValue(resp.GetBackupSchedule())
@ -71,8 +71,6 @@ func mapGetInstanceResponseToModel(
m.Acl = netACL m.Acl = netACL
// m.Labels = resp.GetLabels()
netInstAdd := types.StringValue("") netInstAdd := types.StringValue("")
if instAdd, ok := resp.Network.GetInstanceAddressOk(); ok { if instAdd, ok := resp.Network.GetInstanceAddressOk(); ok {
netInstAdd = types.StringValue(*instAdd) netInstAdd = types.StringValue(*instAdd)

View file

@ -8,6 +8,7 @@ import (
postgresflex "github.com/stackitcloud/stackit-sdk-go/services/postgresflex/v3alpha1api" postgresflex "github.com/stackitcloud/stackit-sdk-go/services/postgresflex/v3alpha1api"
postgresflexalpharesource "tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit/internal/services/postgresflexalpha/instance/resources_gen"
utils2 "tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit/internal/utils" utils2 "tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit/internal/utils"
) )
@ -170,7 +171,7 @@ func Test_mapGetInstanceResponseToModel(t *testing.T) {
t.Skipf("please implement") t.Skipf("please implement")
type args struct { type args struct {
ctx context.Context ctx context.Context
m *LocalInstanceModel m *postgresflexalpharesource.InstanceModel
resp *postgresflex.GetInstanceResponse resp *postgresflex.GetInstanceResponse
} }
tests := []struct { tests := []struct {

View file

@ -11,14 +11,11 @@ import (
"github.com/hashicorp/terraform-plugin-framework/path" "github.com/hashicorp/terraform-plugin-framework/path"
"github.com/hashicorp/terraform-plugin-framework/resource" "github.com/hashicorp/terraform-plugin-framework/resource"
"github.com/hashicorp/terraform-plugin-framework/resource/schema"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
"github.com/hashicorp/terraform-plugin-framework/types"
"github.com/hashicorp/terraform-plugin-framework/types/basetypes"
"github.com/hashicorp/terraform-plugin-log/tflog" "github.com/hashicorp/terraform-plugin-log/tflog"
"github.com/stackitcloud/stackit-sdk-go/core/oapierror" "github.com/stackitcloud/stackit-sdk-go/core/oapierror"
coreUtils "github.com/stackitcloud/stackit-sdk-go/core/utils" coreUtils "github.com/stackitcloud/stackit-sdk-go/core/utils"
"github.com/stackitcloud/stackit-sdk-go/services/postgresflex/v3alpha1api" "github.com/stackitcloud/stackit-sdk-go/services/postgresflex/v3alpha1api"
"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/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/core"
postgresflexalpha "tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit/internal/services/postgresflexalpha/instance/resources_gen" postgresflexalpha "tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit/internal/services/postgresflexalpha/instance/resources_gen"
@ -47,25 +44,12 @@ type instanceResource struct {
providerData core.ProviderData providerData core.ProviderData
} }
type LocalInstanceModel struct {
postgresflexalpha.InstanceModel
Flavor types.Object `tfsdk:"flavor"`
}
// Struct corresponding to Model.Flavor
type flavorModel struct {
Id types.String `tfsdk:"id"`
Description types.String `tfsdk:"description"`
CPU types.Int64 `tfsdk:"cpu"`
RAM types.Int64 `tfsdk:"ram"`
}
func (r *instanceResource) ValidateConfig( func (r *instanceResource) ValidateConfig(
ctx context.Context, ctx context.Context,
req resource.ValidateConfigRequest, req resource.ValidateConfigRequest,
resp *resource.ValidateConfigResponse, resp *resource.ValidateConfigResponse,
) { ) {
var data LocalInstanceModel var data postgresflexalpha.InstanceModel
resp.Diagnostics.Append(req.Config.Get(ctx, &data)...) resp.Diagnostics.Append(req.Config.Get(ctx, &data)...)
if resp.Diagnostics.HasError() { if resp.Diagnostics.HasError() {
@ -80,23 +64,6 @@ func (r *instanceResource) ValidateConfig(
"The resource may return unexpected results.", "The resource may return unexpected results.",
) )
} }
if data.FlavorId.IsNull() {
if data.Flavor.IsUnknown() || data.Flavor.IsNull() {
resp.Diagnostics.AddAttributeError(
path.Root("flavor"),
"Missing Attribute Configuration",
"Expected flavor to be configured. "+
"The resource may return unexpected results.",
)
}
resp.Diagnostics.AddAttributeWarning(
path.Root("flavor"),
"Attribute Configuration Deprecation",
"Using flavor is deprecated, "+
"please use flavor_id instead.",
)
}
} }
// ModifyPlan implements resource.ResourceWithModifyPlan. // ModifyPlan implements resource.ResourceWithModifyPlan.
@ -106,7 +73,7 @@ func (r *instanceResource) ModifyPlan(
req resource.ModifyPlanRequest, req resource.ModifyPlanRequest,
resp *resource.ModifyPlanResponse, resp *resource.ModifyPlanResponse,
) { // nolint:gocritic // function signature required by Terraform ) { // nolint:gocritic // function signature required by Terraform
var configModel LocalInstanceModel var configModel postgresflexalpha.InstanceModel
// skip initial empty configuration to avoid follow-up errors // skip initial empty configuration to avoid follow-up errors
if req.Config.Raw.IsNull() { if req.Config.Raw.IsNull() {
return return
@ -116,7 +83,7 @@ func (r *instanceResource) ModifyPlan(
return return
} }
var planModel LocalInstanceModel var planModel postgresflexalpha.InstanceModel
resp.Diagnostics.Append(req.Plan.Get(ctx, &planModel)...) resp.Diagnostics.Append(req.Plan.Get(ctx, &planModel)...)
if resp.Diagnostics.HasError() { if resp.Diagnostics.HasError() {
return return
@ -166,53 +133,20 @@ func (r *instanceResource) Configure(
var modifiersFileByte []byte var modifiersFileByte []byte
// Schema defines the schema for the resource. // Schema defines the schema for the resource.
func (r *instanceResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) { func (r *instanceResource) Schema(ctx context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) {
schemaVar := postgresflexalpha.InstanceResourceSchema(ctx) schema := postgresflexalpha.InstanceResourceSchema(ctx)
schemaVar.Attributes["flavor"] = schema.SingleNestedAttribute{
Optional: true,
DeprecationMessage: "Please use flavor_id instead.",
Attributes: map[string]schema.Attribute{
"id": schema.StringAttribute{
Computed: true,
PlanModifiers: []planmodifier.String{
UseStateForUnknownIfFlavorUnchanged(req),
},
},
"description": schema.StringAttribute{
Computed: true,
PlanModifiers: []planmodifier.String{
UseStateForUnknownIfFlavorUnchanged(req),
},
},
"cpu": schema.Int64Attribute{
DeprecationMessage: "Please use flavor_id instead.",
Optional: true,
},
"ram": schema.Int64Attribute{
DeprecationMessage: "Please use flavor_id instead.",
Optional: true,
},
},
}
schemaVar.Attributes["flavor_id"] = schema.StringAttribute{
Optional: true,
Description: "The id of the instance flavor.",
MarkdownDescription: "The id of the instance flavor.",
}
fields, err := utils.ReadModifiersConfig(modifiersFileByte) fields, err := utils.ReadModifiersConfig(modifiersFileByte)
if err != nil { if err != nil {
resp.Diagnostics.AddError("error during read modifiers config file", err.Error()) resp.Diagnostics.AddError("error during read modifiers config file", err.Error())
return return
} }
err = utils.AddPlanModifiersToResourceSchema(fields, &schemaVar) err = utils.AddPlanModifiersToResourceSchema(fields, &schema)
if err != nil { if err != nil {
resp.Diagnostics.AddError("error adding plan modifiers", err.Error()) resp.Diagnostics.AddError("error adding plan modifiers", err.Error())
return return
} }
resp.Schema = schemaVar resp.Schema = schema
} }
// Create creates the resource and sets the initial Terraform state. // Create creates the resource and sets the initial Terraform state.
@ -221,7 +155,7 @@ func (r *instanceResource) Create(
req resource.CreateRequest, req resource.CreateRequest,
resp *resource.CreateResponse, resp *resource.CreateResponse,
) { // nolint:gocritic // function signature required by Terraform ) { // nolint:gocritic // function signature required by Terraform
var model LocalInstanceModel var model postgresflexalpha.InstanceModel
diags := req.Plan.Get(ctx, &model) diags := req.Plan.Get(ctx, &model)
resp.Diagnostics.Append(diags...) resp.Diagnostics.Append(diags...)
@ -243,73 +177,6 @@ func (r *instanceResource) Create(
return return
} }
// determine flavor ID
var flModel = &flavorModel{}
if !(model.Flavor.IsNull() || model.Flavor.IsUnknown()) {
diags = model.Flavor.As(ctx, flModel, basetypes.ObjectAsOptions{})
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
flavors, err := getAllFlavors(ctx, r.client.DefaultAPI, projectID, region)
if err != nil {
core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading flavors", fmt.Sprintf("getAllFlavors: %v", err))
return
}
tflog.Debug(ctx, fmt.Sprintf("loaded flavors: %d", len(flavors)))
var foundFlavors []v3alpha1api.ListFlavors
for _, flavor := range flavors {
if flModel.CPU.ValueInt64() != int64(flavor.Cpu) {
// tflog.Debug(ctx, fmt.Sprintf("flavor - cpu did not match (%d - %d)", flModel.CPU.ValueInt64(), flavor.Cpu))
continue
}
if flModel.RAM.ValueInt64() != int64(flavor.Memory) {
// tflog.Debug(ctx, fmt.Sprintf("flavor - ram did not match (%d - %d)", flModel.RAM.ValueInt64(), flavor.Memory))
continue
}
tmpNodeType := "Single"
if model.Replicas.ValueInt64() > 1 {
tmpNodeType = "Replica"
}
if strings.ToLower(tmpNodeType) != strings.ToLower(flavor.NodeType) {
//tflog.Debug(
// ctx,
// fmt.Sprintf(
// "flavor - nodeType did not match ('%s' - '%s')",
// strings.ToLower(tmpNodeType),
// strings.ToLower(flavor.NodeType),
// ),
//)
continue
}
tflog.Debug(ctx, fmt.Sprintf("found flavor %s, checking storage classes", flavor.Id))
for _, sc := range flavor.StorageClasses {
if model.Storage.PerformanceClass.ValueString() != sc.Class {
continue
}
tflog.Debug(ctx, fmt.Sprintf("found storage class '%s' for flavor '%s', checking storage classes", sc.Class, flavor.Id))
foundFlavors = append(foundFlavors, flavor)
}
}
if len(foundFlavors) == 0 {
resp.Diagnostics.AddError("get flavor", "could not find requested flavor")
return
}
if len(foundFlavors) > 1 {
resp.Diagnostics.AddError("get flavor", "found too many matching flavors")
return
}
f := foundFlavors[0]
flModel.Description = types.StringValue(f.Description)
flModel.Id = utils.BuildInternalTerraformId(model.ProjectId.ValueString(), region, f.Id)
model.FlavorId = types.StringValue(f.Id)
//flModel. .MaxGb = types.Int32Value(f.MaxGB)
//flModel.MinGb = types.Int32Value(f.MinGB)
}
replVal := model.Replicas.ValueInt64() // nolint:gosec // check is performed above replVal := model.Replicas.ValueInt64() // nolint:gosec // check is performed above
payload := modelToCreateInstancePayload(netACL, model, replVal) payload := modelToCreateInstancePayload(netACL, model, replVal)
@ -341,7 +208,7 @@ func (r *instanceResource) Create(
) )
waitResp, err := wait.CreateInstanceWaitHandler(ctx, r.client.DefaultAPI, projectID, region, *instanceID). waitResp, err := wait.CreateInstanceWaitHandler(ctx, r.client.DefaultAPI, projectID, region, *instanceID).
SetTimeout(90 * time.Minute). SetTimeout(30 * time.Minute).
SetSleepBeforeWait(10 * time.Second). SetSleepBeforeWait(10 * time.Second).
WaitWithContext(ctx) WaitWithContext(ctx)
if err != nil { if err != nil {
@ -376,7 +243,7 @@ func (r *instanceResource) Create(
func modelToCreateInstancePayload( func modelToCreateInstancePayload(
netACL []string, netACL []string,
model LocalInstanceModel, model postgresflexalpha.InstanceModel,
replVal int64, replVal int64,
) v3alpha1api.CreateInstanceRequestPayload { ) v3alpha1api.CreateInstanceRequestPayload {
var enc *v3alpha1api.InstanceEncryption var enc *v3alpha1api.InstanceEncryption
@ -416,7 +283,7 @@ func (r *instanceResource) Read(
) { // nolint:gocritic // function signature required by Terraform ) { // nolint:gocritic // function signature required by Terraform
functionErrorSummary := "read instance failed" functionErrorSummary := "read instance failed"
var model LocalInstanceModel var model postgresflexalpha.InstanceModel
diags := req.State.Get(ctx, &model) diags := req.State.Get(ctx, &model)
resp.Diagnostics.Append(diags...) resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() { if resp.Diagnostics.HasError() {
@ -504,7 +371,7 @@ func (r *instanceResource) Update(
req resource.UpdateRequest, req resource.UpdateRequest,
resp *resource.UpdateResponse, resp *resource.UpdateResponse,
) { // nolint:gocritic // function signature required by Terraform ) { // nolint:gocritic // function signature required by Terraform
var model LocalInstanceModel var model postgresflexalpha.InstanceModel
diags := req.Plan.Get(ctx, &model) diags := req.Plan.Get(ctx, &model)
resp.Diagnostics.Append(diags...) resp.Diagnostics.Append(diags...)
@ -579,7 +446,7 @@ func (r *instanceResource) Update(
region, region,
instanceID, instanceID,
). ).
SetTimeout(90 * time.Minute). SetTimeout(30 * time.Minute).
SetSleepBeforeWait(10 * time.Second). SetSleepBeforeWait(10 * time.Second).
WaitWithContext(ctx) WaitWithContext(ctx)
if err != nil { if err != nil {
@ -617,7 +484,7 @@ func (r *instanceResource) Delete(
req resource.DeleteRequest, req resource.DeleteRequest,
resp *resource.DeleteResponse, resp *resource.DeleteResponse,
) { // nolint:gocritic // function signature required by Terraform ) { // nolint:gocritic // function signature required by Terraform
var model LocalInstanceModel var model postgresflexalpha.InstanceModel
diags := req.State.Get(ctx, &model) diags := req.State.Get(ctx, &model)
resp.Diagnostics.Append(diags...) resp.Diagnostics.Append(diags...)

View file

@ -119,13 +119,6 @@ func InstanceResourceSchema(ctx context.Context) schema.Schema {
Description: "Whether the instance can be deleted or not.", Description: "Whether the instance can be deleted or not.",
MarkdownDescription: "Whether the instance can be deleted or not.", MarkdownDescription: "Whether the instance can be deleted or not.",
}, },
//"labels": schema.MapAttribute{
// ElementType: types.StringType,
// Optional: true,
// Computed: true,
// Description: "Key-value pairs, 63 characters max, begin and end with an alphanumerical character,\nmay contain dashes (-), underscores (_), dots (.), and alphanumerics between. Key MUST be at least 1 character.\nMax 64 labels\nRegex for keys: ^(?=.{1,63}$)([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9]$\nRegex for values: ^(?=.{0,63}$)(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])*$\nThe stackit- prefix is reserved and cannot be used for Keys.\n",
// MarkdownDescription: "Key-value pairs, 63 characters max, begin and end with an alphanumerical character,\nmay contain dashes (-), underscores (_), dots (.), and alphanumerics between. Key MUST be at least 1 character.\nMax 64 labels\nRegex for keys: ^(?=.{1,63}$)([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9]$\nRegex for values: ^(?=.{0,63}$)(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])*$\nThe stackit- prefix is reserved and cannot be used for Keys.\n",
//},
"name": schema.StringAttribute{ "name": schema.StringAttribute{
Required: true, Required: true,
Description: "The name of the instance.", Description: "The name of the instance.",
@ -198,8 +191,8 @@ func InstanceResourceSchema(ctx context.Context) schema.Schema {
}, },
"retention_days": schema.Int64Attribute{ "retention_days": schema.Int64Attribute{
Required: true, Required: true,
Description: "How long backups are retained. The value can only be between 32 and 90 days.", Description: "How long backups are retained. The value can only be between 32 and 365 days.",
MarkdownDescription: "How long backups are retained. The value can only be between 32 and 90 days.", MarkdownDescription: "How long backups are retained. The value can only be between 32 and 365 days.",
}, },
"status": schema.StringAttribute{ "status": schema.StringAttribute{
Computed: true, Computed: true,
@ -246,16 +239,15 @@ type InstanceModel struct {
Id types.String `tfsdk:"id"` Id types.String `tfsdk:"id"`
InstanceId types.String `tfsdk:"instance_id"` InstanceId types.String `tfsdk:"instance_id"`
IsDeletable types.Bool `tfsdk:"is_deletable"` IsDeletable types.Bool `tfsdk:"is_deletable"`
//Labels types.Map `tfsdk:"labels"` Name types.String `tfsdk:"name"`
Name types.String `tfsdk:"name"` Network NetworkValue `tfsdk:"network"`
Network NetworkValue `tfsdk:"network"` ProjectId types.String `tfsdk:"project_id"`
ProjectId types.String `tfsdk:"project_id"` Region types.String `tfsdk:"region"`
Region types.String `tfsdk:"region"` Replicas types.Int64 `tfsdk:"replicas"`
Replicas types.Int64 `tfsdk:"replicas"` RetentionDays types.Int64 `tfsdk:"retention_days"`
RetentionDays types.Int64 `tfsdk:"retention_days"` Status types.String `tfsdk:"status"`
Status types.String `tfsdk:"status"` Storage StorageValue `tfsdk:"storage"`
Storage StorageValue `tfsdk:"storage"` Version types.String `tfsdk:"version"`
Version types.String `tfsdk:"version"`
} }
var _ basetypes.ObjectTypable = ConnectionInfoType{} var _ basetypes.ObjectTypable = ConnectionInfoType{}

View file

@ -1,85 +0,0 @@
package postgresflexalpha
import (
"context"
"github.com/hashicorp/terraform-plugin-framework/resource"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
"github.com/hashicorp/terraform-plugin-framework/types/basetypes"
)
type useStateForUnknownIfFlavorUnchangedModifier struct {
Req resource.SchemaRequest
}
// UseStateForUnknownIfFlavorUnchanged returns a plan modifier similar to UseStateForUnknown
// if the RAM and CPU values are not changed in the plan. Otherwise, the plan modifier does nothing.
func UseStateForUnknownIfFlavorUnchanged(req resource.SchemaRequest) planmodifier.String {
return useStateForUnknownIfFlavorUnchangedModifier{
Req: req,
}
}
func (m useStateForUnknownIfFlavorUnchangedModifier) Description(context.Context) string {
return "UseStateForUnknownIfFlavorUnchanged returns a plan modifier similar to UseStateForUnknown if the RAM and CPU values are not changed in the plan. Otherwise, the plan modifier does nothing."
}
func (m useStateForUnknownIfFlavorUnchangedModifier) MarkdownDescription(ctx context.Context) string {
return m.Description(ctx)
}
func (m useStateForUnknownIfFlavorUnchangedModifier) PlanModifyString(ctx context.Context, req planmodifier.StringRequest, resp *planmodifier.StringResponse) { // nolint:gocritic // function signature required by Terraform
// Do nothing if there is no state value.
if req.StateValue.IsNull() {
return
}
// Do nothing if there is a known planned value.
if !req.PlanValue.IsUnknown() {
return
}
// Do nothing if there is an unknown configuration value, otherwise interpolation gets messed up.
if req.ConfigValue.IsUnknown() {
return
}
// The above checks are taken from the UseStateForUnknown plan modifier implementation
// (https://github.com/hashicorp/terraform-plugin-framework/blob/main/resource/schema/stringplanmodifier/use_state_for_unknown.go#L38)
var stateModel LocalInstanceModel
diags := req.State.Get(ctx, &stateModel)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
var stateFlavor = &flavorModel{}
if !(stateModel.Flavor.IsNull() || stateModel.Flavor.IsUnknown()) {
diags = stateModel.Flavor.As(ctx, stateFlavor, basetypes.ObjectAsOptions{})
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
}
var planModel LocalInstanceModel
diags = req.Plan.Get(ctx, &planModel)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
var planFlavor = &flavorModel{}
if !(planModel.Flavor.IsNull() || planModel.Flavor.IsUnknown()) {
diags = planModel.Flavor.As(ctx, planFlavor, basetypes.ObjectAsOptions{})
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
}
if planFlavor.CPU == stateFlavor.CPU && planFlavor.RAM == stateFlavor.RAM {
resp.PlanValue = req.StateValue
}
}

View file

@ -799,7 +799,7 @@ func testAccCheckPostgresFlexDestroy(s *terraform.State) error {
testutils.ProjectId, testutils.ProjectId,
testutils.Region, testutils.Region,
items[i].Id, items[i].Id,
30*time.Minute, 15*time.Minute,
10*time.Second, 10*time.Second,
) )
if err != nil { if err != nil {

View file

@ -1,101 +0,0 @@
provider "stackitprivatepreview" {
default_region = "{{ .Region }}"
service_account_key_path = "{{ .ServiceAccountFilePath }}"
}
data "stackitprivatepreview_postgresflexalpha_flavor" "flavor" {
project_id = "{{ .ProjectID }}"
region = "{{ .Region }}"
cpu = 4
ram = 16
node_type = "Single"
storage_class = "premium-perf2-stackit"
}
resource "stackitprivatepreview_postgresflexalpha_instance" "{{ .TfName }}" {
project_id = "{{ .ProjectID }}"
name = "{{ .Name }}"
backup_schedule = "{{ .BackupSchedule }}"
retention_days = {{ .RetentionDays }}
flavor_id = "{{ .FlavorID }}"
replicas = {{ .Replicas }}
storage = {
performance_class = "{{ .PerformanceClass }}"
size = {{ .Size }}
}
{{ if .UseEncryption }}
encryption = {
kek_key_id = "{{ .KekKeyID }}"
kek_key_ring_id = "{{ .KekKeyRingID }}"
kek_key_version = {{ .KekKeyVersion }}
service_account = "{{ .KekServiceAccount }}"
}
{{ end }}
network = {
acl = [{{ range $i, $v := .ACLStrings }}{{if $i}},{{end}}"{{$v}}"{{end}}]
access_scope = "{{ .AccessScope }}"
}
{{ if .Version }}
version = "{{ .Version }}"
{{ end }}
}
{{ if .Users }}
{{ $tfName := .TfName }}
{{ range $user := .Users }}
resource "stackitprivatepreview_postgresflexalpha_user" "{{ $user.Name }}" {
depends_on = [
stackitprivatepreview_postgresflexalpha_instance.{{ $tfName }}
]
project_id = "{{ $user.ProjectID }}"
instance_id = stackitprivatepreview_postgresflexalpha_instance.{{ $tfName }}.instance_id
name = "{{ $user.Name }}"
roles = [{{ range $i, $v := $user.Roles }}{{if $i}},{{end}}"{{$v}}"{{end}}]
}
{{ end }}
{{ end }}
{{ if .Databases }}
{{ $tfName := .TfName }}
{{ range $db := .Databases }}
resource "stackitprivatepreview_postgresflexalpha_database" "{{ $db.Name }}" {
depends_on = [
stackitprivatepreview_postgresflexalpha_instance.{{ $tfName }},
stackitprivatepreview_postgresflexalpha_user.{{ $db.Owner }}
]
project_id = "{{ $db.ProjectID }}"
instance_id = stackitprivatepreview_postgresflexalpha_instance.{{ $tfName }}.instance_id
name = "{{ $db.Name }}"
owner = stackitprivatepreview_postgresflexalpha_user.{{ $db.Owner }}.name
}
{{ end }}
{{ end }}
{{ if .DataSourceTest }}
data "stackitprivatepreview_postgresflexalpha_instance" "{{ .TfName }}" {
project_id = stackitprivatepreview_postgresflexalpha_instance.{{ .TfName }}.project_id
instance_id = stackitprivatepreview_postgresflexalpha_instance.{{ .TfName }}.instance_id
}
{{ if .Users }}
{{ $tfName := .TfName }}
{{ range $user := .Users }}
data "stackitprivatepreview_postgresflexalpha_user" "{{ $user.Name }}" {
project_id = stackitprivatepreview_postgresflexalpha_instance.{{ $tfName }}.project_id
instance_id = stackitprivatepreview_postgresflexalpha_instance.{{ $tfName }}.instance_id
user_id = stackitprivatepreview_postgresflexalpha_user.{{ $user.Name }}.user_id
}
{{ end }}
{{ end }}
{{ if .Databases }}
{{ $tfName := .TfName }}
{{ range $db := .Databases }}
data "stackitprivatepreview_postgresflexalpha_database" "{{ $db.Name }}" {
project_id = stackitprivatepreview_postgresflexalpha_instance.{{ $tfName }}.project_id
instance_id = stackitprivatepreview_postgresflexalpha_instance.{{ $tfName }}.instance_id
database_id = stackitprivatepreview_postgresflexalpha_database.{{ $db.Name }}.database_id
}
{{ end }}
{{ end }}
{{ end }}

View file

@ -241,7 +241,7 @@ func (r *userResource) Create(
).SetSleepBeforeWait( ).SetSleepBeforeWait(
10 * time.Second, 10 * time.Second,
).SetTimeout( ).SetTimeout(
30 * time.Minute, 15 * time.Minute,
).WaitWithContext(ctx) ).WaitWithContext(ctx)
if err != nil { if err != nil {
@ -322,7 +322,7 @@ func (r *userResource) Read(
).SetSleepBeforeWait( ).SetSleepBeforeWait(
10 * time.Second, 10 * time.Second,
).SetTimeout( ).SetTimeout(
30 * time.Minute, 15 * time.Minute,
).WaitWithContext(ctx) ).WaitWithContext(ctx)
if err != nil { if err != nil {
@ -445,7 +445,7 @@ func (r *userResource) Update(
).SetSleepBeforeWait( ).SetSleepBeforeWait(
10 * time.Second, 10 * time.Second,
).SetTimeout( ).SetTimeout(
30 * time.Minute, 15 * time.Minute,
).WaitWithContext(ctx) ).WaitWithContext(ctx)
if err != nil { if err != nil {

View file

@ -1,451 +0,0 @@
// Code generated by terraform-plugin-framework-generator DO NOT EDIT.
package sqlserverflexalpha
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 CollationsDataSourceSchema(ctx context.Context) schema.Schema {
return schema.Schema{
Attributes: map[string]schema.Attribute{
"collations": schema.ListNestedAttribute{
NestedObject: schema.NestedAttributeObject{
Attributes: map[string]schema.Attribute{
"collation_name": schema.StringAttribute{
Computed: true,
},
"description": schema.StringAttribute{
Computed: true,
},
},
CustomType: CollationsType{
ObjectType: types.ObjectType{
AttrTypes: CollationsValue{}.AttributeTypes(ctx),
},
},
},
Computed: true,
Description: "List of collations available for the instance.",
MarkdownDescription: "List of collations available for the instance.",
},
"instance_id": schema.StringAttribute{
Required: true,
Description: "The ID of the instance.",
MarkdownDescription: "The ID of the instance.",
},
"project_id": schema.StringAttribute{
Required: true,
Description: "The STACKIT project ID.",
MarkdownDescription: "The STACKIT project ID.",
},
"region": schema.StringAttribute{
Optional: true,
Description: "The region which should be addressed",
MarkdownDescription: "The region which should be addressed",
Validators: []validator.String{
stringvalidator.OneOf(
"eu01",
),
},
},
},
}
}
type CollationsModel struct {
Collations types.List `tfsdk:"collations"`
InstanceId types.String `tfsdk:"instance_id"`
ProjectId types.String `tfsdk:"project_id"`
Region types.String `tfsdk:"region"`
}
var _ basetypes.ObjectTypable = CollationsType{}
type CollationsType struct {
basetypes.ObjectType
}
func (t CollationsType) Equal(o attr.Type) bool {
other, ok := o.(CollationsType)
if !ok {
return false
}
return t.ObjectType.Equal(other.ObjectType)
}
func (t CollationsType) String() string {
return "CollationsType"
}
func (t CollationsType) ValueFromObject(ctx context.Context, in basetypes.ObjectValue) (basetypes.ObjectValuable, diag.Diagnostics) {
var diags diag.Diagnostics
attributes := in.Attributes()
collationNameAttribute, ok := attributes["collation_name"]
if !ok {
diags.AddError(
"Attribute Missing",
`collation_name is missing from object`)
return nil, diags
}
collationNameVal, ok := collationNameAttribute.(basetypes.StringValue)
if !ok {
diags.AddError(
"Attribute Wrong Type",
fmt.Sprintf(`collation_name expected to be basetypes.StringValue, was: %T`, collationNameAttribute))
}
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))
}
if diags.HasError() {
return nil, diags
}
return CollationsValue{
CollationName: collationNameVal,
Description: descriptionVal,
state: attr.ValueStateKnown,
}, diags
}
func NewCollationsValueNull() CollationsValue {
return CollationsValue{
state: attr.ValueStateNull,
}
}
func NewCollationsValueUnknown() CollationsValue {
return CollationsValue{
state: attr.ValueStateUnknown,
}
}
func NewCollationsValue(attributeTypes map[string]attr.Type, attributes map[string]attr.Value) (CollationsValue, 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 CollationsValue Attribute Value",
"While creating a CollationsValue value, a missing attribute value was detected. "+
"A CollationsValue 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("CollationsValue Attribute Name (%s) Expected Type: %s", name, attributeType.String()),
)
continue
}
if !attributeType.Equal(attribute.Type(ctx)) {
diags.AddError(
"Invalid CollationsValue Attribute Type",
"While creating a CollationsValue value, an invalid attribute value was detected. "+
"A CollationsValue 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("CollationsValue Attribute Name (%s) Expected Type: %s\n", name, attributeType.String())+
fmt.Sprintf("CollationsValue Attribute Name (%s) Given Type: %s", name, attribute.Type(ctx)),
)
}
}
for name := range attributes {
_, ok := attributeTypes[name]
if !ok {
diags.AddError(
"Extra CollationsValue Attribute Value",
"While creating a CollationsValue value, an extra attribute value was detected. "+
"A CollationsValue 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 CollationsValue Attribute Name: %s", name),
)
}
}
if diags.HasError() {
return NewCollationsValueUnknown(), diags
}
collationNameAttribute, ok := attributes["collation_name"]
if !ok {
diags.AddError(
"Attribute Missing",
`collation_name is missing from object`)
return NewCollationsValueUnknown(), diags
}
collationNameVal, ok := collationNameAttribute.(basetypes.StringValue)
if !ok {
diags.AddError(
"Attribute Wrong Type",
fmt.Sprintf(`collation_name expected to be basetypes.StringValue, was: %T`, collationNameAttribute))
}
descriptionAttribute, ok := attributes["description"]
if !ok {
diags.AddError(
"Attribute Missing",
`description is missing from object`)
return NewCollationsValueUnknown(), diags
}
descriptionVal, ok := descriptionAttribute.(basetypes.StringValue)
if !ok {
diags.AddError(
"Attribute Wrong Type",
fmt.Sprintf(`description expected to be basetypes.StringValue, was: %T`, descriptionAttribute))
}
if diags.HasError() {
return NewCollationsValueUnknown(), diags
}
return CollationsValue{
CollationName: collationNameVal,
Description: descriptionVal,
state: attr.ValueStateKnown,
}, diags
}
func NewCollationsValueMust(attributeTypes map[string]attr.Type, attributes map[string]attr.Value) CollationsValue {
object, diags := NewCollationsValue(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("NewCollationsValueMust received error(s): " + strings.Join(diagsStrings, "\n"))
}
return object
}
func (t CollationsType) ValueFromTerraform(ctx context.Context, in tftypes.Value) (attr.Value, error) {
if in.Type() == nil {
return NewCollationsValueNull(), 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 NewCollationsValueUnknown(), nil
}
if in.IsNull() {
return NewCollationsValueNull(), 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 NewCollationsValueMust(CollationsValue{}.AttributeTypes(ctx), attributes), nil
}
func (t CollationsType) ValueType(ctx context.Context) attr.Value {
return CollationsValue{}
}
var _ basetypes.ObjectValuable = CollationsValue{}
type CollationsValue struct {
CollationName basetypes.StringValue `tfsdk:"collation_name"`
Description basetypes.StringValue `tfsdk:"description"`
state attr.ValueState
}
func (v CollationsValue) ToTerraformValue(ctx context.Context) (tftypes.Value, error) {
attrTypes := make(map[string]tftypes.Type, 2)
var val tftypes.Value
var err error
attrTypes["collation_name"] = basetypes.StringType{}.TerraformType(ctx)
attrTypes["description"] = basetypes.StringType{}.TerraformType(ctx)
objectType := tftypes.Object{AttributeTypes: attrTypes}
switch v.state {
case attr.ValueStateKnown:
vals := make(map[string]tftypes.Value, 2)
val, err = v.CollationName.ToTerraformValue(ctx)
if err != nil {
return tftypes.NewValue(objectType, tftypes.UnknownValue), err
}
vals["collation_name"] = val
val, err = v.Description.ToTerraformValue(ctx)
if err != nil {
return tftypes.NewValue(objectType, tftypes.UnknownValue), err
}
vals["description"] = 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 CollationsValue) IsNull() bool {
return v.state == attr.ValueStateNull
}
func (v CollationsValue) IsUnknown() bool {
return v.state == attr.ValueStateUnknown
}
func (v CollationsValue) String() string {
return "CollationsValue"
}
func (v CollationsValue) ToObjectValue(ctx context.Context) (basetypes.ObjectValue, diag.Diagnostics) {
var diags diag.Diagnostics
attributeTypes := map[string]attr.Type{
"collation_name": basetypes.StringType{},
"description": basetypes.StringType{},
}
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{
"collation_name": v.CollationName,
"description": v.Description,
})
return objVal, diags
}
func (v CollationsValue) Equal(o attr.Value) bool {
other, ok := o.(CollationsValue)
if !ok {
return false
}
if v.state != other.state {
return false
}
if v.state != attr.ValueStateKnown {
return true
}
if !v.CollationName.Equal(other.CollationName) {
return false
}
if !v.Description.Equal(other.Description) {
return false
}
return true
}
func (v CollationsValue) Type(ctx context.Context) attr.Type {
return CollationsType{
basetypes.ObjectType{
AttrTypes: v.AttributeTypes(ctx),
},
}
}
func (v CollationsValue) AttributeTypes(ctx context.Context) map[string]attr.Type {
return map[string]attr.Type{
"collation_name": basetypes.StringType{},
"description": basetypes.StringType{},
}
}

View file

@ -17,7 +17,7 @@ import (
"github.com/hashicorp/terraform-plugin-framework/datasource/schema" "github.com/hashicorp/terraform-plugin-framework/datasource/schema"
) )
func VersionsDataSourceSchema(ctx context.Context) schema.Schema { func VersionDataSourceSchema(ctx context.Context) schema.Schema {
return schema.Schema{ return schema.Schema{
Attributes: map[string]schema.Attribute{ Attributes: map[string]schema.Attribute{
"project_id": schema.StringAttribute{ "project_id": schema.StringAttribute{
@ -26,7 +26,7 @@ func VersionsDataSourceSchema(ctx context.Context) schema.Schema {
MarkdownDescription: "The STACKIT project ID.", MarkdownDescription: "The STACKIT project ID.",
}, },
"region": schema.StringAttribute{ "region": schema.StringAttribute{
Optional: true, Required: true,
Description: "The region which should be addressed", Description: "The region which should be addressed",
MarkdownDescription: "The region which should be addressed", MarkdownDescription: "The region which should be addressed",
Validators: []validator.String{ Validators: []validator.String{
@ -73,7 +73,7 @@ func VersionsDataSourceSchema(ctx context.Context) schema.Schema {
} }
} }
type VersionsModel struct { type VersionModel struct {
ProjectId types.String `tfsdk:"project_id"` ProjectId types.String `tfsdk:"project_id"`
Region types.String `tfsdk:"region"` Region types.String `tfsdk:"region"`
Versions types.List `tfsdk:"versions"` Versions types.List `tfsdk:"versions"`

View file

@ -1,452 +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 CollationsDataSourceSchema(ctx context.Context) schema.Schema {
return schema.Schema{
Attributes: map[string]schema.Attribute{
"collations": schema.ListNestedAttribute{
NestedObject: schema.NestedAttributeObject{
Attributes: map[string]schema.Attribute{
"collation_name": schema.StringAttribute{
Computed: true,
},
"description": schema.StringAttribute{
Computed: true,
},
},
CustomType: CollationsType{
ObjectType: types.ObjectType{
AttrTypes: CollationsValue{}.AttributeTypes(ctx),
},
},
},
Computed: true,
Description: "List of collations available for the instance.",
MarkdownDescription: "List of collations available for the instance.",
},
"instance_id": schema.StringAttribute{
Required: true,
Description: "The ID of the instance.",
MarkdownDescription: "The ID of the instance.",
},
"project_id": schema.StringAttribute{
Required: true,
Description: "The STACKIT project ID.",
MarkdownDescription: "The STACKIT project ID.",
},
"region": schema.StringAttribute{
Optional: true,
Description: "The region which should be addressed",
MarkdownDescription: "The region which should be addressed",
Validators: []validator.String{
stringvalidator.OneOf(
"eu01",
"eu02",
),
},
},
},
}
}
type CollationsModel struct {
Collations types.List `tfsdk:"collations"`
InstanceId types.String `tfsdk:"instance_id"`
ProjectId types.String `tfsdk:"project_id"`
Region types.String `tfsdk:"region"`
}
var _ basetypes.ObjectTypable = CollationsType{}
type CollationsType struct {
basetypes.ObjectType
}
func (t CollationsType) Equal(o attr.Type) bool {
other, ok := o.(CollationsType)
if !ok {
return false
}
return t.ObjectType.Equal(other.ObjectType)
}
func (t CollationsType) String() string {
return "CollationsType"
}
func (t CollationsType) ValueFromObject(ctx context.Context, in basetypes.ObjectValue) (basetypes.ObjectValuable, diag.Diagnostics) {
var diags diag.Diagnostics
attributes := in.Attributes()
collationNameAttribute, ok := attributes["collation_name"]
if !ok {
diags.AddError(
"Attribute Missing",
`collation_name is missing from object`)
return nil, diags
}
collationNameVal, ok := collationNameAttribute.(basetypes.StringValue)
if !ok {
diags.AddError(
"Attribute Wrong Type",
fmt.Sprintf(`collation_name expected to be basetypes.StringValue, was: %T`, collationNameAttribute))
}
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))
}
if diags.HasError() {
return nil, diags
}
return CollationsValue{
CollationName: collationNameVal,
Description: descriptionVal,
state: attr.ValueStateKnown,
}, diags
}
func NewCollationsValueNull() CollationsValue {
return CollationsValue{
state: attr.ValueStateNull,
}
}
func NewCollationsValueUnknown() CollationsValue {
return CollationsValue{
state: attr.ValueStateUnknown,
}
}
func NewCollationsValue(attributeTypes map[string]attr.Type, attributes map[string]attr.Value) (CollationsValue, 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 CollationsValue Attribute Value",
"While creating a CollationsValue value, a missing attribute value was detected. "+
"A CollationsValue 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("CollationsValue Attribute Name (%s) Expected Type: %s", name, attributeType.String()),
)
continue
}
if !attributeType.Equal(attribute.Type(ctx)) {
diags.AddError(
"Invalid CollationsValue Attribute Type",
"While creating a CollationsValue value, an invalid attribute value was detected. "+
"A CollationsValue 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("CollationsValue Attribute Name (%s) Expected Type: %s\n", name, attributeType.String())+
fmt.Sprintf("CollationsValue Attribute Name (%s) Given Type: %s", name, attribute.Type(ctx)),
)
}
}
for name := range attributes {
_, ok := attributeTypes[name]
if !ok {
diags.AddError(
"Extra CollationsValue Attribute Value",
"While creating a CollationsValue value, an extra attribute value was detected. "+
"A CollationsValue 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 CollationsValue Attribute Name: %s", name),
)
}
}
if diags.HasError() {
return NewCollationsValueUnknown(), diags
}
collationNameAttribute, ok := attributes["collation_name"]
if !ok {
diags.AddError(
"Attribute Missing",
`collation_name is missing from object`)
return NewCollationsValueUnknown(), diags
}
collationNameVal, ok := collationNameAttribute.(basetypes.StringValue)
if !ok {
diags.AddError(
"Attribute Wrong Type",
fmt.Sprintf(`collation_name expected to be basetypes.StringValue, was: %T`, collationNameAttribute))
}
descriptionAttribute, ok := attributes["description"]
if !ok {
diags.AddError(
"Attribute Missing",
`description is missing from object`)
return NewCollationsValueUnknown(), diags
}
descriptionVal, ok := descriptionAttribute.(basetypes.StringValue)
if !ok {
diags.AddError(
"Attribute Wrong Type",
fmt.Sprintf(`description expected to be basetypes.StringValue, was: %T`, descriptionAttribute))
}
if diags.HasError() {
return NewCollationsValueUnknown(), diags
}
return CollationsValue{
CollationName: collationNameVal,
Description: descriptionVal,
state: attr.ValueStateKnown,
}, diags
}
func NewCollationsValueMust(attributeTypes map[string]attr.Type, attributes map[string]attr.Value) CollationsValue {
object, diags := NewCollationsValue(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("NewCollationsValueMust received error(s): " + strings.Join(diagsStrings, "\n"))
}
return object
}
func (t CollationsType) ValueFromTerraform(ctx context.Context, in tftypes.Value) (attr.Value, error) {
if in.Type() == nil {
return NewCollationsValueNull(), 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 NewCollationsValueUnknown(), nil
}
if in.IsNull() {
return NewCollationsValueNull(), 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 NewCollationsValueMust(CollationsValue{}.AttributeTypes(ctx), attributes), nil
}
func (t CollationsType) ValueType(ctx context.Context) attr.Value {
return CollationsValue{}
}
var _ basetypes.ObjectValuable = CollationsValue{}
type CollationsValue struct {
CollationName basetypes.StringValue `tfsdk:"collation_name"`
Description basetypes.StringValue `tfsdk:"description"`
state attr.ValueState
}
func (v CollationsValue) ToTerraformValue(ctx context.Context) (tftypes.Value, error) {
attrTypes := make(map[string]tftypes.Type, 2)
var val tftypes.Value
var err error
attrTypes["collation_name"] = basetypes.StringType{}.TerraformType(ctx)
attrTypes["description"] = basetypes.StringType{}.TerraformType(ctx)
objectType := tftypes.Object{AttributeTypes: attrTypes}
switch v.state {
case attr.ValueStateKnown:
vals := make(map[string]tftypes.Value, 2)
val, err = v.CollationName.ToTerraformValue(ctx)
if err != nil {
return tftypes.NewValue(objectType, tftypes.UnknownValue), err
}
vals["collation_name"] = val
val, err = v.Description.ToTerraformValue(ctx)
if err != nil {
return tftypes.NewValue(objectType, tftypes.UnknownValue), err
}
vals["description"] = 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 CollationsValue) IsNull() bool {
return v.state == attr.ValueStateNull
}
func (v CollationsValue) IsUnknown() bool {
return v.state == attr.ValueStateUnknown
}
func (v CollationsValue) String() string {
return "CollationsValue"
}
func (v CollationsValue) ToObjectValue(ctx context.Context) (basetypes.ObjectValue, diag.Diagnostics) {
var diags diag.Diagnostics
attributeTypes := map[string]attr.Type{
"collation_name": basetypes.StringType{},
"description": basetypes.StringType{},
}
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{
"collation_name": v.CollationName,
"description": v.Description,
})
return objVal, diags
}
func (v CollationsValue) Equal(o attr.Value) bool {
other, ok := o.(CollationsValue)
if !ok {
return false
}
if v.state != other.state {
return false
}
if v.state != attr.ValueStateKnown {
return true
}
if !v.CollationName.Equal(other.CollationName) {
return false
}
if !v.Description.Equal(other.Description) {
return false
}
return true
}
func (v CollationsValue) Type(ctx context.Context) attr.Type {
return CollationsType{
basetypes.ObjectType{
AttrTypes: v.AttributeTypes(ctx),
},
}
}
func (v CollationsValue) AttributeTypes(ctx context.Context) map[string]attr.Type {
return map[string]attr.Type{
"collation_name": basetypes.StringType{},
"description": basetypes.StringType{},
}
}

View file

@ -61,7 +61,6 @@ func DatabaseDataSourceSchema(ctx context.Context) schema.Schema {
Validators: []validator.String{ Validators: []validator.String{
stringvalidator.OneOf( stringvalidator.OneOf(
"eu01", "eu01",
"eu02",
), ),
}, },
}, },

View file

@ -102,7 +102,6 @@ func DatabasesDataSourceSchema(ctx context.Context) schema.Schema {
Validators: []validator.String{ Validators: []validator.String{
stringvalidator.OneOf( stringvalidator.OneOf(
"eu01", "eu01",
"eu02",
), ),
}, },
}, },

View file

@ -193,7 +193,6 @@ func (r *databaseResource) Create(ctx context.Context, req resource.CreateReques
data.Owner.ValueString(), data.Owner.ValueString(),
). ).
SetSleepBeforeWait(10 * time.Second). SetSleepBeforeWait(10 * time.Second).
SetTimeout(90 * time.Minute).
WaitWithContext(ctx) WaitWithContext(ctx)
if err != nil { if err != nil {
core.LogAndAddError( core.LogAndAddError(
@ -254,9 +253,9 @@ func (r *databaseResource) Create(ctx context.Context, req resource.CreateReques
region, region,
databaseName, databaseName,
).SetSleepBeforeWait( ).SetSleepBeforeWait(
10 * time.Second, 30 * time.Second,
).SetTimeout( ).SetTimeout(
90 * time.Minute, 15 * time.Minute,
).WaitWithContext(ctx) ).WaitWithContext(ctx)
if err != nil { if err != nil {
core.LogAndAddError( core.LogAndAddError(

View file

@ -77,7 +77,6 @@ func DatabaseResourceSchema(ctx context.Context) schema.Schema {
Validators: []validator.String{ Validators: []validator.String{
stringvalidator.OneOf( stringvalidator.OneOf(
"eu01", "eu01",
"eu02",
), ),
}, },
}, },

View file

@ -135,7 +135,6 @@ func FlavorsDataSourceSchema(ctx context.Context) schema.Schema {
Validators: []validator.String{ Validators: []validator.String{
stringvalidator.OneOf( stringvalidator.OneOf(
"eu01", "eu01",
"eu02",
), ),
}, },
}, },

View file

@ -126,7 +126,6 @@ func InstanceDataSourceSchema(ctx context.Context) schema.Schema {
Validators: []validator.String{ Validators: []validator.String{
stringvalidator.OneOf( stringvalidator.OneOf(
"eu01", "eu01",
"eu02",
), ),
}, },
}, },

View file

@ -95,7 +95,6 @@ func InstancesDataSourceSchema(ctx context.Context) schema.Schema {
Validators: []validator.String{ Validators: []validator.String{
stringvalidator.OneOf( stringvalidator.OneOf(
"eu01", "eu01",
"eu02",
), ),
}, },
}, },

View file

@ -1,65 +0,0 @@
package sqlserverflexbeta
import (
"context"
"fmt"
"github.com/stackitcloud/stackit-sdk-go/services/sqlserverflex/v3beta1api"
)
type flavorsClientReader interface {
GetFlavorsRequest(
ctx context.Context,
projectId, region string,
) v3beta1api.ApiGetFlavorsRequestRequest
}
func getAllFlavors(ctx context.Context, client flavorsClientReader, projectId, region string) (
[]v3beta1api.ListFlavors,
error,
) {
getAllFilter := func(_ v3beta1api.ListFlavors) bool { return true }
flavorList, err := getFlavorsByFilter(ctx, client, projectId, region, getAllFilter)
if err != nil {
return nil, err
}
return flavorList, nil
}
// getFlavorsByFilter is a helper function to retrieve flavors using a filtern function.
// Hint: The API does not have a GetFlavors endpoint, only ListFlavors
func getFlavorsByFilter(
ctx context.Context,
client flavorsClientReader,
projectId, region string,
filter func(db v3beta1api.ListFlavors) bool,
) ([]v3beta1api.ListFlavors, error) {
if projectId == "" || region == "" {
return nil, fmt.Errorf("listing v3beta1api flavors: projectId and region are required")
}
const pageSize = 25
var result = make([]v3beta1api.ListFlavors, 0)
for page := int64(1); ; page++ {
res, err := client.GetFlavorsRequest(ctx, projectId, region).
Page(page).Size(pageSize).Sort(v3beta1api.FLAVORSORT_INDEX_ASC).Execute()
if err != nil {
return nil, fmt.Errorf("requesting flavors list (page %d): %w", page, err)
}
// If the API returns no flavors, we have reached the end of the list.
if len(res.Flavors) == 0 {
break
}
for _, flavor := range res.Flavors {
if filter(flavor) {
result = append(result, flavor)
}
}
}
return result, nil
}

View file

@ -22,7 +22,7 @@ import (
func mapResponseToModel( func mapResponseToModel(
ctx context.Context, ctx context.Context,
resp *v3beta1api.GetInstanceResponse, resp *v3beta1api.GetInstanceResponse,
m *LocalInstanceModel, m *sqlserverflexbetaResGen.InstanceModel,
tfDiags diag.Diagnostics, tfDiags diag.Diagnostics,
) error { ) error {
m.BackupSchedule = types.StringValue(resp.GetBackupSchedule()) m.BackupSchedule = types.StringValue(resp.GetBackupSchedule())
@ -133,7 +133,7 @@ func mapDataResponseToModel(
func handleEncryption( func handleEncryption(
ctx context.Context, ctx context.Context,
m *LocalInstanceModel, m *sqlserverflexbetaResGen.InstanceModel,
resp *v3beta1api.GetInstanceResponse, resp *v3beta1api.GetInstanceResponse,
) sqlserverflexbetaResGen.EncryptionValue { ) sqlserverflexbetaResGen.EncryptionValue {
if !resp.HasEncryption() || if !resp.HasEncryption() ||
@ -191,7 +191,7 @@ func handleDSEncryption(
func toCreatePayload( func toCreatePayload(
ctx context.Context, ctx context.Context,
model *LocalInstanceModel, model *sqlserverflexbetaResGen.InstanceModel,
) (*v3beta1api.CreateInstanceRequestPayload, error) { ) (*v3beta1api.CreateInstanceRequestPayload, error) {
if model == nil { if model == nil {
return nil, fmt.Errorf("nil model") return nil, fmt.Errorf("nil model")
@ -241,7 +241,7 @@ func toCreatePayload(
func toUpdatePayload( func toUpdatePayload(
ctx context.Context, ctx context.Context,
m *LocalInstanceModel, m *sqlserverflexbetaResGen.InstanceModel,
resp *resource.UpdateResponse, resp *resource.UpdateResponse,
) (*v3beta1api.UpdateInstanceRequestPayload, error) { ) (*v3beta1api.UpdateInstanceRequestPayload, error) {
if m == nil { if m == nil {

View file

@ -40,7 +40,7 @@ func Test_handleDSEncryption(t *testing.T) {
func Test_handleEncryption(t *testing.T) { func Test_handleEncryption(t *testing.T) {
type args struct { type args struct {
m *LocalInstanceModel m *sqlserverflexbetaRs.InstanceModel
resp *sqlserverflexbetaPkgGen.GetInstanceResponse resp *sqlserverflexbetaPkgGen.GetInstanceResponse
} }
tests := []struct { tests := []struct {
@ -51,7 +51,7 @@ func Test_handleEncryption(t *testing.T) {
{ {
name: "nil response", name: "nil response",
args: args{ args: args{
m: &LocalInstanceModel{}, m: &sqlserverflexbetaRs.InstanceModel{},
resp: &sqlserverflexbetaPkgGen.GetInstanceResponse{}, resp: &sqlserverflexbetaPkgGen.GetInstanceResponse{},
}, },
want: sqlserverflexbetaRs.EncryptionValue{}, want: sqlserverflexbetaRs.EncryptionValue{},
@ -59,7 +59,7 @@ func Test_handleEncryption(t *testing.T) {
{ {
name: "nil response", name: "nil response",
args: args{ args: args{
m: &LocalInstanceModel{}, m: &sqlserverflexbetaRs.InstanceModel{},
resp: &sqlserverflexbetaPkgGen.GetInstanceResponse{ resp: &sqlserverflexbetaPkgGen.GetInstanceResponse{
Encryption: &sqlserverflexbetaPkgGen.InstanceEncryption{}, Encryption: &sqlserverflexbetaPkgGen.InstanceEncryption{},
}, },
@ -69,7 +69,7 @@ func Test_handleEncryption(t *testing.T) {
{ {
name: "response with values", name: "response with values",
args: args{ args: args{
m: &LocalInstanceModel{}, m: &sqlserverflexbetaRs.InstanceModel{},
resp: &sqlserverflexbetaPkgGen.GetInstanceResponse{ resp: &sqlserverflexbetaPkgGen.GetInstanceResponse{
Encryption: &sqlserverflexbetaPkgGen.InstanceEncryption{ Encryption: &sqlserverflexbetaPkgGen.InstanceEncryption{
KekKeyId: ("kek_key_id"), KekKeyId: ("kek_key_id"),
@ -138,7 +138,7 @@ func Test_mapResponseToModel(t *testing.T) {
type args struct { type args struct {
ctx context.Context ctx context.Context
resp *sqlserverflexbetaPkgGen.GetInstanceResponse resp *sqlserverflexbetaPkgGen.GetInstanceResponse
m *LocalInstanceModel m *sqlserverflexbetaRs.InstanceModel
tfDiags diag.Diagnostics tfDiags diag.Diagnostics
} }
tests := []struct { tests := []struct {
@ -167,7 +167,7 @@ func Test_mapResponseToModel(t *testing.T) {
func Test_toCreatePayload(t *testing.T) { func Test_toCreatePayload(t *testing.T) {
type args struct { type args struct {
ctx context.Context ctx context.Context
model *LocalInstanceModel model *sqlserverflexbetaRs.InstanceModel
} }
tests := []struct { tests := []struct {
name string name string
@ -175,61 +175,61 @@ func Test_toCreatePayload(t *testing.T) {
want *sqlserverflexbetaPkgGen.CreateInstanceRequestPayload want *sqlserverflexbetaPkgGen.CreateInstanceRequestPayload
wantErr bool wantErr bool
}{ }{
//{ {
// name: "simple", name: "simple",
// args: args{ args: args{
// ctx: context.Background(), ctx: context.Background(),
// model: &LocalInstanceModel{ model: &sqlserverflexbetaRs.InstanceModel{
// Encryption: sqlserverflexbetaRs.NewEncryptionValueMust( Encryption: sqlserverflexbetaRs.NewEncryptionValueMust(
// sqlserverflexbetaRs.EncryptionValue{}.AttributeTypes(context.Background()), sqlserverflexbetaRs.EncryptionValue{}.AttributeTypes(context.Background()),
// map[string]attr.Value{ map[string]attr.Value{
// "kek_key_id": types.StringValue("kek_key_id"), "kek_key_id": types.StringValue("kek_key_id"),
// "kek_key_ring_id": types.StringValue("kek_key_ring_id"), "kek_key_ring_id": types.StringValue("kek_key_ring_id"),
// "kek_key_version": types.StringValue("kek_key_version"), "kek_key_version": types.StringValue("kek_key_version"),
// "service_account": types.StringValue("sacc"), "service_account": types.StringValue("sacc"),
// }, },
// ), ),
// Storage: sqlserverflexbetaRs.StorageValue{}, Storage: sqlserverflexbetaRs.StorageValue{},
// }, },
// }, },
// want: &sqlserverflexbetaPkgGen.CreateInstanceRequestPayload{ want: &sqlserverflexbetaPkgGen.CreateInstanceRequestPayload{
// BackupSchedule: "", BackupSchedule: "",
// Encryption: &sqlserverflexbetaPkgGen.InstanceEncryption{ Encryption: &sqlserverflexbetaPkgGen.InstanceEncryption{
// KekKeyId: ("kek_key_id"), KekKeyId: ("kek_key_id"),
// KekKeyRingId: ("kek_key_ring_id"), KekKeyRingId: ("kek_key_ring_id"),
// KekKeyVersion: ("kek_key_version"), KekKeyVersion: ("kek_key_version"),
// ServiceAccount: ("sacc"), ServiceAccount: ("sacc"),
// }, },
// FlavorId: "", FlavorId: "",
// Name: "", Name: "",
// Network: sqlserverflexbetaPkgGen.CreateInstanceRequestPayloadNetwork{}, Network: sqlserverflexbetaPkgGen.CreateInstanceRequestPayloadNetwork{},
// RetentionDays: 0, RetentionDays: 0,
// Storage: sqlserverflexbetaPkgGen.StorageCreate{}, Storage: sqlserverflexbetaPkgGen.StorageCreate{},
// Version: "", Version: "",
// }, },
// wantErr: false, wantErr: false,
//}, },
//{ {
// name: "nil object", name: "nil object",
// args: args{ args: args{
// ctx: context.Background(), ctx: context.Background(),
// model: &LocalInstanceModel{ model: &sqlserverflexbetaRs.InstanceModel{
// Encryption: sqlserverflexbetaRs.NewEncryptionValueNull(), Encryption: sqlserverflexbetaRs.NewEncryptionValueNull(),
// Storage: sqlserverflexbetaRs.StorageValue{}, Storage: sqlserverflexbetaRs.StorageValue{},
// }, },
// }, },
// want: &sqlserverflexbetaPkgGen.CreateInstanceRequestPayload{ want: &sqlserverflexbetaPkgGen.CreateInstanceRequestPayload{
// BackupSchedule: "", BackupSchedule: "",
// Encryption: nil, Encryption: nil,
// FlavorId: "", FlavorId: "",
// Name: "", Name: "",
// Network: sqlserverflexbetaPkgGen.CreateInstanceRequestPayloadNetwork{}, Network: sqlserverflexbetaPkgGen.CreateInstanceRequestPayloadNetwork{},
// RetentionDays: 0, RetentionDays: 0,
// Storage: sqlserverflexbetaPkgGen.StorageCreate{}, Storage: sqlserverflexbetaPkgGen.StorageCreate{},
// Version: "", Version: "",
// }, },
// wantErr: false, wantErr: false,
//}, },
} }
for _, tt := range tests { for _, tt := range tests {
t.Run( t.Run(
@ -250,7 +250,7 @@ func Test_toCreatePayload(t *testing.T) {
func Test_toUpdatePayload(t *testing.T) { func Test_toUpdatePayload(t *testing.T) {
type args struct { type args struct {
ctx context.Context ctx context.Context
m *LocalInstanceModel m *sqlserverflexbetaRs.InstanceModel
resp *resource.UpdateResponse resp *resource.UpdateResponse
} }
tests := []struct { tests := []struct {

View file

@ -10,10 +10,7 @@ import (
"github.com/hashicorp/terraform-plugin-framework/path" "github.com/hashicorp/terraform-plugin-framework/path"
"github.com/hashicorp/terraform-plugin-framework/resource" "github.com/hashicorp/terraform-plugin-framework/resource"
"github.com/hashicorp/terraform-plugin-framework/resource/schema"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
"github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-plugin-framework/types"
"github.com/hashicorp/terraform-plugin-framework/types/basetypes"
"github.com/hashicorp/terraform-plugin-log/tflog" "github.com/hashicorp/terraform-plugin-log/tflog"
"github.com/stackitcloud/stackit-sdk-go/core/config" "github.com/stackitcloud/stackit-sdk-go/core/config"
"github.com/stackitcloud/stackit-sdk-go/core/oapierror" "github.com/stackitcloud/stackit-sdk-go/core/oapierror"
@ -45,19 +42,8 @@ type instanceResource struct {
providerData core.ProviderData providerData core.ProviderData
} }
// LocalInstanceModel describes the resource data model. // resourceModel describes the resource data model.
type LocalInstanceModel struct { type resourceModel = sqlserverflexbetaResGen.InstanceModel
sqlserverflexbetaResGen.InstanceModel
Flavor types.Object `tfsdk:"flavor"`
}
// LocalFlavorModel Struct corresponding to Model.Flavor
type LocalFlavorModel struct {
Id types.String `tfsdk:"id"`
Description types.String `tfsdk:"description"`
CPU types.Int64 `tfsdk:"cpu"`
RAM types.Int64 `tfsdk:"ram"`
}
func (r *instanceResource) Metadata( func (r *instanceResource) Metadata(
_ context.Context, _ context.Context,
@ -70,40 +56,8 @@ func (r *instanceResource) Metadata(
//go:embed planModifiers.yaml //go:embed planModifiers.yaml
var modifiersFileByte []byte var modifiersFileByte []byte
func (r *instanceResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) { func (r *instanceResource) Schema(ctx context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) {
s := sqlserverflexbetaResGen.InstanceResourceSchema(ctx) s := sqlserverflexbetaResGen.InstanceResourceSchema(ctx)
s.Attributes["flavor"] = schema.SingleNestedAttribute{
Optional: true,
DeprecationMessage: "Please use flavor_id instead.",
Attributes: map[string]schema.Attribute{
"id": schema.StringAttribute{
Computed: true,
PlanModifiers: []planmodifier.String{
UseStateForUnknownIfFlavorUnchanged(req),
},
},
"description": schema.StringAttribute{
Computed: true,
PlanModifiers: []planmodifier.String{
UseStateForUnknownIfFlavorUnchanged(req),
},
},
"cpu": schema.Int64Attribute{
DeprecationMessage: "Please use flavor_id instead.",
Optional: true,
},
"ram": schema.Int64Attribute{
DeprecationMessage: "Please use flavor_id instead.",
Optional: true,
},
},
}
s.Attributes["flavor_id"] = schema.StringAttribute{
Optional: true,
Description: "The id of the instance flavor.",
MarkdownDescription: "The id of the instance flavor.",
}
fields, err := utils.ReadModifiersConfig(modifiersFileByte) fields, err := utils.ReadModifiersConfig(modifiersFileByte)
if err != nil { if err != nil {
@ -169,7 +123,7 @@ func (r *instanceResource) ModifyPlan(
if req.Config.Raw.IsNull() { if req.Config.Raw.IsNull() {
return return
} }
var configModel LocalInstanceModel var configModel resourceModel
resp.Diagnostics.Append(req.Config.Get(ctx, &configModel)...) resp.Diagnostics.Append(req.Config.Get(ctx, &configModel)...)
if resp.Diagnostics.HasError() { if resp.Diagnostics.HasError() {
return return
@ -178,7 +132,7 @@ func (r *instanceResource) ModifyPlan(
if req.Plan.Raw.IsNull() { if req.Plan.Raw.IsNull() {
return return
} }
var planModel LocalInstanceModel var planModel resourceModel
resp.Diagnostics.Append(req.Plan.Get(ctx, &planModel)...) resp.Diagnostics.Append(req.Plan.Get(ctx, &planModel)...)
if resp.Diagnostics.HasError() { if resp.Diagnostics.HasError() {
return return
@ -196,7 +150,7 @@ func (r *instanceResource) ModifyPlan(
} }
func (r *instanceResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { func (r *instanceResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
var data LocalInstanceModel var data resourceModel
crateErr := "[SQL Server Flex BETA - Create] error" crateErr := "[SQL Server Flex BETA - Create] error"
// Read Terraform plan data into the model // Read Terraform plan data into the model
@ -213,73 +167,6 @@ func (r *instanceResource) Create(ctx context.Context, req resource.CreateReques
ctx = tflog.SetField(ctx, "project_id", projectID) ctx = tflog.SetField(ctx, "project_id", projectID)
ctx = tflog.SetField(ctx, "region", region) ctx = tflog.SetField(ctx, "region", region)
// determine flavor ID
var flModel = &LocalFlavorModel{}
if !(data.Flavor.IsNull() || data.Flavor.IsUnknown()) {
diags := data.Flavor.As(ctx, flModel, basetypes.ObjectAsOptions{})
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
flavors, err := getAllFlavors(ctx, r.client.DefaultAPI, projectID, region)
if err != nil {
core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading flavors", fmt.Sprintf("getAllFlavors: %v", err))
return
}
tflog.Debug(ctx, fmt.Sprintf("loaded flavors: %d", len(flavors)))
var foundFlavors []v3beta1api.ListFlavors
for _, flavor := range flavors {
if flModel.CPU.ValueInt64() != int64(flavor.Cpu) {
// tflog.Debug(ctx, fmt.Sprintf("flavor - cpu did not match (%d - %d)", flModel.CPU.ValueInt64(), flavor.Cpu))
continue
}
if flModel.RAM.ValueInt64() != int64(flavor.Memory) {
// tflog.Debug(ctx, fmt.Sprintf("flavor - ram did not match (%d - %d)", flModel.RAM.ValueInt64(), flavor.Memory))
continue
}
tmpNodeType := "Single"
if data.Replicas.ValueInt64() > 1 {
tmpNodeType = "Replica"
}
if strings.ToLower(tmpNodeType) != strings.ToLower(flavor.NodeType) {
//tflog.Debug(
// ctx,
// fmt.Sprintf(
// "flavor - nodeType did not match ('%s' - '%s')",
// strings.ToLower(tmpNodeType),
// strings.ToLower(flavor.NodeType),
// ),
//)
continue
}
tflog.Debug(ctx, fmt.Sprintf("found flavor %s, checking storage classes", flavor.Id))
for _, sc := range flavor.StorageClasses {
if data.Storage.Class.ValueString() != sc.Class {
continue
}
tflog.Debug(ctx, fmt.Sprintf("found storage class '%s' for flavor '%s', checking storage classes", sc.Class, flavor.Id))
foundFlavors = append(foundFlavors, flavor)
}
}
if len(foundFlavors) == 0 {
resp.Diagnostics.AddError("get flavor", "could not find requested flavor")
return
}
if len(foundFlavors) > 1 {
resp.Diagnostics.AddError("get flavor", "found too many matching flavors")
return
}
f := foundFlavors[0]
flModel.Description = types.StringValue(f.Description)
flModel.Id = utils.BuildInternalTerraformId(data.ProjectId.ValueString(), region, f.Id)
data.FlavorId = types.StringValue(f.Id)
//flModel. .MaxGb = types.Int32Value(f.MaxGB)
//flModel.MinGb = types.Int32Value(f.MinGB)
}
// Generate API request body from model // Generate API request body from model
payload, err := toCreatePayload(ctx, &data) payload, err := toCreatePayload(ctx, &data)
if err != nil { if err != nil {
@ -369,7 +256,7 @@ func (r *instanceResource) Create(ctx context.Context, req resource.CreateReques
} }
func (r *instanceResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { func (r *instanceResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
var data LocalInstanceModel var data resourceModel
// Read Terraform prior state data into the model // Read Terraform prior state data into the model
resp.Diagnostics.Append(req.State.Get(ctx, &data)...) resp.Diagnostics.Append(req.State.Get(ctx, &data)...)
@ -422,7 +309,7 @@ func (r *instanceResource) Read(ctx context.Context, req resource.ReadRequest, r
} }
func (r *instanceResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { func (r *instanceResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
var data LocalInstanceModel var data resourceModel
updateInstanceError := "Error updating instance" updateInstanceError := "Error updating instance"
resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...) resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...)
@ -467,8 +354,8 @@ func (r *instanceResource) Update(ctx context.Context, req resource.UpdateReques
waitResp, err := wait. waitResp, err := wait.
UpdateInstanceWaitHandler(ctx, r.client.DefaultAPI, projectID, instanceID, region). UpdateInstanceWaitHandler(ctx, r.client.DefaultAPI, projectID, instanceID, region).
SetSleepBeforeWait(10 * time.Second). SetSleepBeforeWait(15 * time.Second).
SetTimeout(90 * time.Minute). SetTimeout(45 * time.Minute).
WaitWithContext(ctx) WaitWithContext(ctx)
if err != nil { if err != nil {
core.LogAndAddError( core.LogAndAddError(
@ -502,7 +389,7 @@ func (r *instanceResource) Update(ctx context.Context, req resource.UpdateReques
} }
func (r *instanceResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { func (r *instanceResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
var data LocalInstanceModel var data resourceModel
// Read Terraform prior state data into the model // Read Terraform prior state data into the model
resp.Diagnostics.Append(req.State.Get(ctx, &data)...) resp.Diagnostics.Append(req.State.Get(ctx, &data)...)
@ -529,10 +416,7 @@ func (r *instanceResource) Delete(ctx context.Context, req resource.DeleteReques
ctx = core.LogResponse(ctx) ctx = core.LogResponse(ctx)
delResp, err := wait.DeleteInstanceWaitHandler(ctx, r.client.DefaultAPI, projectID, instanceID, region). delResp, err := wait.DeleteInstanceWaitHandler(ctx, r.client.DefaultAPI, projectID, instanceID, region).WaitWithContext(ctx)
SetSleepBeforeWait(10 * time.Second).
SetTimeout(90 * time.Minute).
WaitWithContext(ctx)
if err != nil { if err != nil {
core.LogAndAddError( core.LogAndAddError(
ctx, ctx,

View file

@ -139,7 +139,6 @@ func InstanceResourceSchema(ctx context.Context) schema.Schema {
Validators: []validator.String{ Validators: []validator.String{
stringvalidator.OneOf( stringvalidator.OneOf(
"eu01", "eu01",
"eu02",
), ),
}, },
}, },

View file

@ -1,85 +0,0 @@
package sqlserverflexbeta
import (
"context"
"github.com/hashicorp/terraform-plugin-framework/resource"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
"github.com/hashicorp/terraform-plugin-framework/types/basetypes"
)
type useStateForUnknownIfFlavorUnchangedModifier struct {
Req resource.SchemaRequest
}
// UseStateForUnknownIfFlavorUnchanged returns a plan modifier similar to UseStateForUnknown
// if the RAM and CPU values are not changed in the plan. Otherwise, the plan modifier does nothing.
func UseStateForUnknownIfFlavorUnchanged(req resource.SchemaRequest) planmodifier.String {
return useStateForUnknownIfFlavorUnchangedModifier{
Req: req,
}
}
func (m useStateForUnknownIfFlavorUnchangedModifier) Description(context.Context) string {
return "UseStateForUnknownIfFlavorUnchanged returns a plan modifier similar to UseStateForUnknown if the RAM and CPU values are not changed in the plan. Otherwise, the plan modifier does nothing."
}
func (m useStateForUnknownIfFlavorUnchangedModifier) MarkdownDescription(ctx context.Context) string {
return m.Description(ctx)
}
func (m useStateForUnknownIfFlavorUnchangedModifier) PlanModifyString(ctx context.Context, req planmodifier.StringRequest, resp *planmodifier.StringResponse) { // nolint:gocritic // function signature required by Terraform
// Do nothing if there is no state value.
if req.StateValue.IsNull() {
return
}
// Do nothing if there is a known planned value.
if !req.PlanValue.IsUnknown() {
return
}
// Do nothing if there is an unknown configuration value, otherwise interpolation gets messed up.
if req.ConfigValue.IsUnknown() {
return
}
// The above checks are taken from the UseStateForUnknown plan modifier implementation
// (https://github.com/hashicorp/terraform-plugin-framework/blob/main/resource/schema/stringplanmodifier/use_state_for_unknown.go#L38)
var stateModel LocalInstanceModel
diags := req.State.Get(ctx, &stateModel)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
var stateFlavor = &LocalFlavorModel{}
if !(stateModel.Flavor.IsNull() || stateModel.Flavor.IsUnknown()) {
diags = stateModel.Flavor.As(ctx, stateFlavor, basetypes.ObjectAsOptions{})
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
}
var planModel LocalInstanceModel
diags = req.Plan.Get(ctx, &planModel)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
var planFlavor = &LocalFlavorModel{}
if !(planModel.Flavor.IsNull() || planModel.Flavor.IsUnknown()) {
diags = planModel.Flavor.As(ctx, planFlavor, basetypes.ObjectAsOptions{})
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
}
if planFlavor.CPU == stateFlavor.CPU && planFlavor.RAM == stateFlavor.RAM {
resp.PlanValue = req.StateValue
}
}

View file

@ -158,8 +158,7 @@ func TestAccInstance(t *testing.T) {
PreConfig: func() { PreConfig: func() {
t.Logf("testing: %s - %s", t.Name(), "create and verify") t.Logf("testing: %s - %s", t.Name(), "create and verify")
}, },
// empty refresh plan ExpectNonEmptyPlan: true,
ExpectNonEmptyPlan: false,
Config: testutils.StringFromTemplateMust( Config: testutils.StringFromTemplateMust(
"testdata/instance_template.gompl", "testdata/instance_template.gompl",
exData, exData,
@ -182,7 +181,7 @@ func TestAccInstance(t *testing.T) {
PreConfig: func() { PreConfig: func() {
t.Logf("testing: %s - %s", t.Name(), "update name and verify") t.Logf("testing: %s - %s", t.Name(), "update name and verify")
}, },
ExpectNonEmptyPlan: false, ExpectNonEmptyPlan: true,
Config: testutils.StringFromTemplateMust( Config: testutils.StringFromTemplateMust(
"testdata/instance_template.gompl", "testdata/instance_template.gompl",
updNameData, updNameData,
@ -196,23 +195,12 @@ func TestAccInstance(t *testing.T) {
defaultNoEncInstanceTestChecks(testInstanceID, updNameData), defaultNoEncInstanceTestChecks(testInstanceID, updNameData),
), ),
}, },
// Expect empty plan after update
{
PreConfig: func() {
t.Logf("testing: %s - %s", t.Name(), "expect empty plan")
},
ExpectNonEmptyPlan: false,
Config: testutils.StringFromTemplateMust(
"testdata/instance_template.gompl",
updNameData,
),
},
// Update size and verify // Update size and verify
{ {
PreConfig: func() { PreConfig: func() {
t.Logf("testing: %s - %s", t.Name(), "update storage.size and verify") t.Logf("testing: %s - %s", t.Name(), "update storage.size and verify")
}, },
ExpectNonEmptyPlan: false, ExpectNonEmptyPlan: true,
Config: testutils.StringFromTemplateMust( Config: testutils.StringFromTemplateMust(
"testdata/instance_template.gompl", "testdata/instance_template.gompl",
updSizeData, updSizeData,

View file

@ -68,7 +68,6 @@ func UserDataSourceSchema(ctx context.Context) schema.Schema {
Validators: []validator.String{ Validators: []validator.String{
stringvalidator.OneOf( stringvalidator.OneOf(
"eu01", "eu01",
"eu02",
), ),
}, },
}, },

View file

@ -308,7 +308,7 @@ func (r *userResource) Create(
region, region,
userId, userId,
).SetSleepBeforeWait( ).SetSleepBeforeWait(
10 * time.Second, 90 * time.Second,
).SetTimeout( ).SetTimeout(
90 * time.Minute, 90 * time.Minute,
).WaitWithContext(ctx) ).WaitWithContext(ctx)
@ -459,23 +459,23 @@ func (r *userResource) Delete(
ctx = core.InitProviderContext(ctx) ctx = core.InitProviderContext(ctx)
projectID := model.ProjectId.ValueString() projectId := model.ProjectId.ValueString()
instanceID := model.InstanceId.ValueString() instanceId := model.InstanceId.ValueString()
userID := model.UserId.ValueInt64() userId := model.UserId.ValueInt64()
region := model.Region.ValueString() region := model.Region.ValueString()
ctx = tflog.SetField(ctx, "project_id", projectID) ctx = tflog.SetField(ctx, "project_id", projectId)
ctx = tflog.SetField(ctx, "instance_id", instanceID) ctx = tflog.SetField(ctx, "instance_id", instanceId)
ctx = tflog.SetField(ctx, "user_id", userID) ctx = tflog.SetField(ctx, "user_id", userId)
ctx = tflog.SetField(ctx, "region", region) ctx = tflog.SetField(ctx, "region", region)
// Delete existing record set // Delete existing record set
// err := r.client.DeleteUserRequest(ctx, projectId, region, instanceId, userId).Execute() // err := r.client.DeleteUserRequest(ctx, projectId, region, instanceId, userId).Execute()
err := r.client.DefaultAPI.DeleteUserRequest(ctx, projectID, region, instanceID, userID).Execute() err := r.client.DefaultAPI.DeleteUserRequest(ctx, projectId, region, instanceId, userId).Execute()
if err != nil { if err != nil {
var oapiErr *oapierror.GenericOpenAPIError var oapiErr *oapierror.GenericOpenAPIError
ok := errors.As(err, &oapiErr) ok := errors.As(err, &oapiErr)
if !ok { if !ok {
core.LogAndAddError(ctx, &resp.Diagnostics, "User Delete Error", fmt.Sprintf("error is no oapi error: %v", err)) // TODO err handling
return return
} }
@ -487,14 +487,12 @@ func (r *userResource) Delete(
// tflog.Warn(ctx, "[delete user] Wait handler got error 500") // tflog.Warn(ctx, "[delete user] Wait handler got error 500")
// return false, nil, nil // return false, nil, nil
default: default:
core.LogAndAddError(ctx, &resp.Diagnostics, "User Delete Error", fmt.Sprintf("Unexpected API error: %v", err)) // TODO err handling
return return
} }
} }
// Delete existing record set // Delete existing record set
_, err = sqlserverflexbetaWait.DeleteUserWaitHandler(ctx, r.client.DefaultAPI, projectID, region, instanceID, userID). _, err = sqlserverflexbetaWait.DeleteUserWaitHandler(ctx, r.client.DefaultAPI, projectId, region, instanceId, userId).
SetTimeout(90 * time.Minute).
SetSleepBeforeWait(10 * time.Second).
WaitWithContext(ctx) WaitWithContext(ctx)
if err != nil { if err != nil {
core.LogAndAddError(ctx, &resp.Diagnostics, "User Delete Error", fmt.Sprintf("Calling API: %v", err)) core.LogAndAddError(ctx, &resp.Diagnostics, "User Delete Error", fmt.Sprintf("Calling API: %v", err))

View file

@ -60,7 +60,6 @@ func UserResourceSchema(ctx context.Context) schema.Schema {
Validators: []validator.String{ Validators: []validator.String{
stringvalidator.OneOf( stringvalidator.OneOf(
"eu01", "eu01",
"eu02",
), ),
}, },
}, },

View file

@ -17,7 +17,7 @@ import (
"github.com/hashicorp/terraform-plugin-framework/datasource/schema" "github.com/hashicorp/terraform-plugin-framework/datasource/schema"
) )
func VersionsDataSourceSchema(ctx context.Context) schema.Schema { func VersionDataSourceSchema(ctx context.Context) schema.Schema {
return schema.Schema{ return schema.Schema{
Attributes: map[string]schema.Attribute{ Attributes: map[string]schema.Attribute{
"project_id": schema.StringAttribute{ "project_id": schema.StringAttribute{
@ -26,13 +26,12 @@ func VersionsDataSourceSchema(ctx context.Context) schema.Schema {
MarkdownDescription: "The STACKIT project ID.", MarkdownDescription: "The STACKIT project ID.",
}, },
"region": schema.StringAttribute{ "region": schema.StringAttribute{
Optional: true, Required: true,
Description: "The region which should be addressed", Description: "The region which should be addressed",
MarkdownDescription: "The region which should be addressed", MarkdownDescription: "The region which should be addressed",
Validators: []validator.String{ Validators: []validator.String{
stringvalidator.OneOf( stringvalidator.OneOf(
"eu01", "eu01",
"eu02",
), ),
}, },
}, },
@ -74,7 +73,7 @@ func VersionsDataSourceSchema(ctx context.Context) schema.Schema {
} }
} }
type VersionsModel struct { type VersionModel struct {
ProjectId types.String `tfsdk:"project_id"` ProjectId types.String `tfsdk:"project_id"`
Region types.String `tfsdk:"region"` Region types.String `tfsdk:"region"`
Versions types.List `tfsdk:"versions"` Versions types.List `tfsdk:"versions"`

View file

@ -58,10 +58,10 @@ func CreateInstanceWaitHandler(
) *wait.AsyncActionHandler[v3alpha1api.GetInstanceResponse] { ) *wait.AsyncActionHandler[v3alpha1api.GetInstanceResponse] {
instanceCreated := false instanceCreated := false
var instanceGetResponse *v3alpha1api.GetInstanceResponse var instanceGetResponse *v3alpha1api.GetInstanceResponse
maxWait := time.Minute * 90 maxWait := time.Minute * 45
startTime := time.Now() startTime := time.Now()
extendedTimeout := 0 extendedTimeout := 0
maxFailedCount := 10 maxFailedCount := 3
failedCount := 0 failedCount := 0
handler := wait.New( handler := wait.New(
@ -129,7 +129,7 @@ func CreateInstanceWaitHandler(
}, },
) )
var waitCounter int64 = 1 var waitCounter int64 = 1
maxWaitInt := big.NewInt(10) maxWaitInt := big.NewInt(7)
n, randErr := rand.Int(rand.Reader, maxWaitInt) n, randErr := rand.Int(rand.Reader, maxWaitInt)
if randErr == nil { if randErr == nil {
waitCounter = n.Int64() + 1 waitCounter = n.Int64() + 1
@ -281,8 +281,8 @@ func GetDatabaseByIdWaitHandler(
if databaseID > math.MaxInt32 { if databaseID > math.MaxInt32 {
return false, nil, fmt.Errorf("databaseID too large for int32") return false, nil, fmt.Errorf("databaseID too large for int32")
} }
dbID32 := int32(databaseID) //nolint:gosec // is checked above dbId32 := int32(databaseID) //nolint:gosec // is checked above
s, err := a.GetDatabaseRequest(ctx, projectID, region, instanceID, dbID32).Execute() s, err := a.GetDatabaseRequest(ctx, projectID, region, instanceID, dbId32).Execute()
if err != nil { if err != nil {
var oapiErr *oapierror.GenericOpenAPIError var oapiErr *oapierror.GenericOpenAPIError
ok := errors.As(err, &oapiErr) ok := errors.As(err, &oapiErr)
@ -290,7 +290,6 @@ func GetDatabaseByIdWaitHandler(
return false, nil, fmt.Errorf("could not convert error to oapierror.GenericOpenAPIError") return false, nil, fmt.Errorf("could not convert error to oapierror.GenericOpenAPIError")
} }
switch oapiErr.StatusCode { switch oapiErr.StatusCode {
// TODO: work-around
case http.StatusBadGateway, http.StatusGatewayTimeout, http.StatusServiceUnavailable: case http.StatusBadGateway, http.StatusGatewayTimeout, http.StatusServiceUnavailable:
tflog.Warn( tflog.Warn(
ctx, "api responded with 50[2,3,4] status", map[string]interface{}{ ctx, "api responded with 50[2,3,4] status", map[string]interface{}{

View file

@ -89,16 +89,9 @@ func CreateInstanceWaitHandler(
return false, nil, fmt.Errorf("could not convert error to oapierror.GenericOpenAPIError: %w", err) return false, nil, fmt.Errorf("could not convert error to oapierror.GenericOpenAPIError: %w", err)
} }
switch oapiErr.StatusCode { switch oapiErr.StatusCode {
case http.StatusOK:
return false, nil, nil
case http.StatusNotFound: case http.StatusNotFound:
return false, nil, nil return false, nil, nil
default: default:
// TODO: work-around
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) return false, nil, fmt.Errorf("api error: %w", err)
} }
} }
@ -264,6 +257,7 @@ func DeleteInstanceWaitHandler(
return true, nil, nil return true, nil, nil
}, },
) )
handler.SetTimeout(30 * time.Minute)
return handler return handler
} }
@ -405,5 +399,7 @@ func DeleteUserWaitHandler(
} }
}, },
) )
handler.SetTimeout(15 * time.Minute)
handler.SetSleepBeforeWait(15 * time.Second)
return handler return handler
} }

View file

@ -19,11 +19,11 @@ import (
"github.com/hashicorp/terraform-plugin-log/tflog" "github.com/hashicorp/terraform-plugin-log/tflog"
sdkauth "github.com/stackitcloud/stackit-sdk-go/core/auth" sdkauth "github.com/stackitcloud/stackit-sdk-go/core/auth"
"github.com/stackitcloud/stackit-sdk-go/core/config" "github.com/stackitcloud/stackit-sdk-go/core/config"
sqlserverFlexBetaFlavor "tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit/internal/services/sqlserverflexbeta/flavor"
//sqlserverflexalphaDatabase "tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit/internal/services/sqlserverflexalpha/database" sqlserverflexalphaDatabase "tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit/internal/services/sqlserverflexalpha/database"
//sqlserverflexalphaInstance "tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit/internal/services/sqlserverflexalpha/instance" sqlserverflexalphaInstance "tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit/internal/services/sqlserverflexalpha/instance"
//sqlserverflexalphaUser "tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit/internal/services/sqlserverflexalpha/user" sqlserverflexalphaUser "tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit/internal/services/sqlserverflexalpha/user"
sqlserverflexbetaUser "tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit/internal/services/sqlserverflexbeta/user"
"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/core"
"tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit/internal/features" "tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit/internal/features"
@ -36,7 +36,7 @@ import (
sqlserverFlexBetaDatabase "tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit/internal/services/sqlserverflexbeta/database" sqlserverFlexBetaDatabase "tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit/internal/services/sqlserverflexbeta/database"
sqlserverflexBetaInstance "tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit/internal/services/sqlserverflexbeta/instance" sqlserverflexBetaInstance "tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit/internal/services/sqlserverflexbeta/instance"
sqlserverflexbetaUser "tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit/internal/services/sqlserverflexbeta/user" // sqlserverFlexBetaUser "tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit/internal/services/sqlserverflexbetaUser/user"
) )
// Ensure the implementation satisfies the expected interfaces // Ensure the implementation satisfies the expected interfaces
@ -536,14 +536,14 @@ func (p *Provider) DataSources(_ context.Context) []func() datasource.DataSource
postgresflexalphaFlavors.NewFlavorsDataSource, postgresflexalphaFlavors.NewFlavorsDataSource,
// sqlserverFlexAlphaFlavor.NewFlavorDataSource, // sqlserverFlexAlphaFlavor.NewFlavorDataSource,
//sqlserverflexalphaInstance.NewInstanceDataSource, sqlserverflexalphaInstance.NewInstanceDataSource,
//sqlserverflexalphaUser.NewUserDataSource, sqlserverflexalphaUser.NewUserDataSource,
//sqlserverflexalphaDatabase.NewDatabaseDataSource, sqlserverflexalphaDatabase.NewDatabaseDataSource,
sqlserverFlexBetaDatabase.NewDatabaseDataSource, sqlserverFlexBetaDatabase.NewDatabaseDataSource,
sqlserverflexBetaInstance.NewInstanceDataSource, sqlserverflexBetaInstance.NewInstanceDataSource,
sqlserverflexbetaUser.NewUserDataSource, sqlserverflexbetaUser.NewUserDataSource,
sqlserverFlexBetaFlavor.NewFlavorDataSource, // sqlserverFlexBetaFlavor.NewFlavorDataSource,
} }
} }
@ -554,9 +554,9 @@ func (p *Provider) Resources(_ context.Context) []func() resource.Resource {
postgresFlexAlphaUser.NewUserResource, postgresFlexAlphaUser.NewUserResource,
postgresFlexAlphaDatabase.NewDatabaseResource, postgresFlexAlphaDatabase.NewDatabaseResource,
//sqlserverflexalphaInstance.NewInstanceResource, sqlserverflexalphaInstance.NewInstanceResource,
//sqlserverflexalphaUser.NewUserResource, sqlserverflexalphaUser.NewUserResource,
//sqlserverflexalphaDatabase.NewDatabaseResource, sqlserverflexalphaDatabase.NewDatabaseResource,
sqlserverflexBetaInstance.NewInstanceResource, sqlserverflexBetaInstance.NewInstanceResource,
sqlserverflexbetaUser.NewUserResource, sqlserverflexbetaUser.NewUserResource,

View file

@ -10,6 +10,8 @@ import (
"github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp"
sqlserverflexalphaDatabase "tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit/internal/services/sqlserverflexalpha/database"
//nolint:staticcheck // used for acceptance testing //nolint:staticcheck // used for acceptance testing
postgresFlexAlphaFlavor "tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit/internal/services/postgresflexalpha/flavor" postgresFlexAlphaFlavor "tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit/internal/services/postgresflexalpha/flavor"
@ -21,6 +23,8 @@ import (
postgresflexalphaFlavors "tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit/internal/services/postgresflexalpha/flavors" postgresflexalphaFlavors "tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit/internal/services/postgresflexalpha/flavors"
postgresFlexAlphaInstance "tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit/internal/services/postgresflexalpha/instance" postgresFlexAlphaInstance "tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit/internal/services/postgresflexalpha/instance"
postgresFlexAlphaUser "tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit/internal/services/postgresflexalpha/user" postgresFlexAlphaUser "tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit/internal/services/postgresflexalpha/user"
sqlserverFlexAlphaInstance "tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit/internal/services/sqlserverflexalpha/instance"
sqlserverFlexAlphaUser "tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit/internal/services/sqlserverflexalpha/user"
sqlserverflexBetaDatabase "tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit/internal/services/sqlserverflexbeta/database" sqlserverflexBetaDatabase "tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit/internal/services/sqlserverflexbeta/database"
sqlserverFlexBetaInstance "tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit/internal/services/sqlserverflexbeta/instance" sqlserverFlexBetaInstance "tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit/internal/services/sqlserverflexbeta/instance"
sqlserverFlexBetaUser "tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit/internal/services/sqlserverflexbeta/user" sqlserverFlexBetaUser "tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit/internal/services/sqlserverflexbeta/user"
@ -59,9 +63,9 @@ func TestUnitProviderHasChildDataSources_Basic(t *testing.T) {
postgresflexalphaFlavors.NewFlavorsDataSource(), postgresflexalphaFlavors.NewFlavorsDataSource(),
// sqlserverFlexAlphaFlavor.NewFlavorDataSource(), // sqlserverFlexAlphaFlavor.NewFlavorDataSource(),
//sqlserverFlexAlphaInstance.NewInstanceDataSource(), sqlserverFlexAlphaInstance.NewInstanceDataSource(),
//sqlserverFlexAlphaUser.NewUserDataSource(), sqlserverFlexAlphaUser.NewUserDataSource(),
//sqlserverflexalphaDatabase.NewDatabaseDataSource(), sqlserverflexalphaDatabase.NewDatabaseDataSource(),
sqlserverflexBetaDatabase.NewDatabaseDataSource(), sqlserverflexBetaDatabase.NewDatabaseDataSource(),
sqlserverFlexBetaInstance.NewInstanceDataSource(), sqlserverFlexBetaInstance.NewInstanceDataSource(),
@ -95,9 +99,9 @@ func TestUnitProviderHasChildResources_Basic(t *testing.T) {
postgresFlexAlphaUser.NewUserResource(), postgresFlexAlphaUser.NewUserResource(),
postgresFlexAlphaDatabase.NewDatabaseResource(), postgresFlexAlphaDatabase.NewDatabaseResource(),
//sqlserverFlexAlphaInstance.NewInstanceResource(), sqlserverFlexAlphaInstance.NewInstanceResource(),
//sqlserverFlexAlphaUser.NewUserResource(), sqlserverFlexAlphaUser.NewUserResource(),
//sqlserverflexalphaDatabase.NewDatabaseResource(), sqlserverflexalphaDatabase.NewDatabaseResource(),
sqlserverFlexBetaInstance.NewInstanceResource(), sqlserverFlexBetaInstance.NewInstanceResource(),
sqlserverFlexBetaUser.NewUserResource(), sqlserverFlexBetaUser.NewUserResource(),