Compare commits
37 commits
v0.0.6-alp
...
alpha
| Author | SHA1 | Date | |
|---|---|---|---|
| 01deb9022d | |||
| dd77da71dd | |||
| 3790894563 | |||
| f173fd54fe | |||
| 1033d7e034 | |||
|
|
635a9abf20 | ||
|
|
07458c5677 | ||
|
|
eb13630d2f | ||
| 4a2819787d | |||
|
|
36eccc52c3 | ||
|
|
841e702b95 | ||
|
|
aba831cbdd | ||
|
|
89a24ce780 | ||
|
|
f05e90c35a | ||
|
|
7ee82366d7 | ||
| d5644ec27f | |||
|
|
20e9b3ca4c | ||
|
|
43223f5d1f | ||
|
|
452f73877f | ||
|
|
55a0917a86 | ||
|
|
d90236b02e | ||
|
|
b1f8c8a4d9 | ||
|
|
e01ae1a920 | ||
|
|
843fc46f54 | ||
|
|
10af1dbbba | ||
|
|
459120d3b3 | ||
|
|
82c654f3ba | ||
|
|
0c9ecfc670 | ||
| 131e1700bb | |||
|
|
86fc98461c | ||
|
|
ed7ff0f58e | ||
|
|
f2bffa9ece | ||
| 399e8ccb0c | |||
|
|
e21fe64326 | ||
| 4991897eca | |||
|
|
b737875c68 | ||
|
|
9dbf36dd35 |
221 changed files with 18444 additions and 10418 deletions
243
.github/actions/acc_test/action.yaml
vendored
243
.github/actions/acc_test/action.yaml
vendored
|
|
@ -2,6 +2,16 @@ name: Acceptance Testing
|
|||
description: "Acceptance Testing pipeline"
|
||||
|
||||
inputs:
|
||||
tf_debug:
|
||||
description: "enable terraform debug logs"
|
||||
default: 'false'
|
||||
required: true
|
||||
|
||||
test_timeout_string:
|
||||
description: "string that determines the timeout (default: 45m)"
|
||||
default: '90m'
|
||||
required: true
|
||||
|
||||
go-version:
|
||||
description: "go version to install"
|
||||
default: '1.25'
|
||||
|
|
@ -11,38 +21,78 @@ inputs:
|
|||
description: "STACKIT project ID for tests"
|
||||
required: true
|
||||
|
||||
project_user_email:
|
||||
required: true
|
||||
description: "project user email for acc testing"
|
||||
|
||||
tf_acc_kek_key_id:
|
||||
description: "KEK key ID"
|
||||
required: true
|
||||
|
||||
tf_acc_kek_key_ring_id:
|
||||
description: "KEK key ring ID"
|
||||
required: true
|
||||
|
||||
tf_acc_kek_key_version:
|
||||
description: "KEK key version"
|
||||
required: true
|
||||
|
||||
tf_acc_kek_service_account:
|
||||
description: "KEK service account email"
|
||||
required: true
|
||||
|
||||
region:
|
||||
description: "STACKIT region for tests"
|
||||
default: 'eu01'
|
||||
required: true
|
||||
|
||||
service_account_json:
|
||||
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: ""
|
||||
|
||||
service_account_json_file_path:
|
||||
description: "STACKIT service account JSON file contents"
|
||||
required: true
|
||||
default: 'service_account.json'
|
||||
|
||||
test_file:
|
||||
description: "testfile to run"
|
||||
default: ''
|
||||
|
||||
outputs:
|
||||
random-number:
|
||||
description: "Random number"
|
||||
value: ${{ steps.random-number-generator.outputs.random-number }}
|
||||
|
||||
#outputs:
|
||||
# random-number:
|
||||
# description: "Random number"
|
||||
# value: ${{ steps.random-number-generator.outputs.random-number }}
|
||||
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
- name: Random Number Generator
|
||||
id: random-number-generator
|
||||
run: echo "random-number=$(echo $RANDOM)" >> $GITHUB_OUTPUT
|
||||
shell: bash
|
||||
# - name: Random Number Generator
|
||||
# id: random-number-generator
|
||||
# run: echo "random-number=$(echo $RANDOM)" >> $GITHUB_OUTPUT
|
||||
# shell: bash
|
||||
|
||||
- name: Install needed tools
|
||||
shell: bash
|
||||
run: |
|
||||
echo "::group::apt install"
|
||||
set -e
|
||||
apt-get -y -qq update
|
||||
apt-get -y -qq install jq python3 python3-pip python-is-python3 s3cmd git make wget
|
||||
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 jq python3 python3-pip python-is-python3 s3cmd git make wget >apt_get.log 2>apt_get_err.log
|
||||
if [ $? -ne 0 ]; then
|
||||
cat apt_get.log apt_get_err.log
|
||||
fi
|
||||
echo "::endgroup::"
|
||||
|
||||
- name: Setup JAVA
|
||||
uses: actions/setup-java@v5
|
||||
|
|
@ -53,62 +103,183 @@ runs:
|
|||
- name: Install Go ${{ inputs.go-version }}
|
||||
uses: actions/setup-go@v6
|
||||
with:
|
||||
go-version: ${{ inputs.go-version }}
|
||||
# go-version: ${{ inputs.go-version }}
|
||||
check-latest: true
|
||||
go-version-file: 'go.mod'
|
||||
|
||||
- name: Determine GOMODCACHE
|
||||
shell: bash
|
||||
id: goenv
|
||||
run: |
|
||||
set -e
|
||||
echo "gomodcache=$(go env GOMODCACHE)" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Restore cached GO pkg
|
||||
id: cache-gopkg
|
||||
uses: actions/cache/restore@v5
|
||||
with:
|
||||
path: "${{ steps.goenv.outputs.gomodcache }}"
|
||||
key: ${{ runner.os }}-gopkg
|
||||
|
||||
- name: Install go tools
|
||||
if: steps.cache-gopkg.outputs.cache-hit != 'true'
|
||||
shell: bash
|
||||
run: |
|
||||
echo "::group::go install"
|
||||
set -e
|
||||
go mod download
|
||||
go install golang.org/x/tools/cmd/goimports@latest
|
||||
go install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@v2.7.2
|
||||
go install github.com/hashicorp/terraform-plugin-docs/cmd/tfplugindocs@v0.24.0
|
||||
go install github.com/hashicorp/terraform-plugin-codegen-framework/cmd/tfplugingen-framework@latest
|
||||
go install github.com/hashicorp/terraform-plugin-codegen-openapi/cmd/tfplugingen-openapi@latest
|
||||
go install github.com/hashicorp/terraform-plugin-docs/cmd/tfplugindocs@latest
|
||||
go install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@latest
|
||||
echo "::endgroup::"
|
||||
- name: Run go mod tidy
|
||||
shell: bash
|
||||
run: go mod tidy
|
||||
|
||||
- name: Prepare pkg_gen directory
|
||||
- name: Save GO package Cache
|
||||
id: cache-gopkg-save
|
||||
uses: actions/cache/save@v5
|
||||
with:
|
||||
path: |
|
||||
${{ steps.goenv.outputs.gomodcache }}
|
||||
key: ${{ runner.os }}-gopkg
|
||||
|
||||
- name: Define service account file path variable
|
||||
id: service_account
|
||||
shell: bash
|
||||
run: |
|
||||
go run cmd/main.go build -p
|
||||
echo "safilepath=${PWD}/stackit/${{ inputs.service_account_json_file_path }}" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Creating service_account file from json input
|
||||
if: inputs.service_account_json_content != ''
|
||||
shell: bash
|
||||
run: |
|
||||
echo "::group::create service account file"
|
||||
set -e
|
||||
set -o pipefail
|
||||
|
||||
jsonFile="${{ inputs.service_account_json_file_path }}"
|
||||
jsonFile="${jsonFile:-x}"
|
||||
if [ "${jsonFile}" == "x" ]; then
|
||||
echo "no service account file path provided"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ ! -f "${jsonFile}" ]; then
|
||||
echo "creating service account file '${{ inputs.service_account_json_file_path }}'"
|
||||
echo "${{ inputs.service_account_json_content }}" > stackit/"${{ inputs.service_account_json_file_path }}"
|
||||
fi
|
||||
ls -l stackit/"${{ inputs.service_account_json_file_path }}"
|
||||
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
|
||||
|
||||
jsonFile="${{ inputs.service_account_json_file_path }}"
|
||||
jsonFile="${jsonFile:-x}"
|
||||
if [ "${jsonFile}" == "x" ]; then
|
||||
echo "no service account file path provided"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ ! -f "${jsonFile}" ]; then
|
||||
echo "creating service account file '${{ inputs.service_account_json_file_path }}'"
|
||||
echo "${{ inputs.service_account_json_content_b64 }}" | base64 -d > stackit/"${{ inputs.service_account_json_file_path }}"
|
||||
fi
|
||||
ls -l stackit/"${{ inputs.service_account_json_file_path }}"
|
||||
echo "::endgroup::"
|
||||
|
||||
- name: Run acceptance test file
|
||||
if: ${{ inputs.test_file != '' }}
|
||||
shell: bash
|
||||
run: |
|
||||
echo "::group::go test file"
|
||||
set -e
|
||||
set -o pipefail
|
||||
|
||||
if [[ "${{ inputs.tf_debug }}" == "true" ]]; then
|
||||
TF_LOG=INFO
|
||||
export TF_LOG
|
||||
fi
|
||||
|
||||
echo "Running acceptance tests for the terraform provider"
|
||||
echo "${STACKIT_SERVICE_ACCOUNT_JSON}" > ~/.service_account.json
|
||||
cd stackit
|
||||
cd stackit || exit 1
|
||||
TF_ACC=1 \
|
||||
TF_ACC_PROJECT_ID=${TF_ACC_PROJECT_ID} \
|
||||
TF_ACC_REGION=${TF_ACC_REGION} \
|
||||
go test ${{ inputs.test_file }} -count=1 -timeout=30m
|
||||
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 ${{ inputs.test_file }} -timeout=${{ inputs.test_timeout_string }}
|
||||
echo "::endgroup::"
|
||||
env:
|
||||
STACKIT_SERVICE_ACCOUNT_JSON: ${{ inputs.service_account_json }}
|
||||
TF_PROJECT_ID: ${{ inputs.project_id }}
|
||||
TF_ACC_PROJECT_ID: ${{ inputs.project_id }}
|
||||
TF_ACC_REGION: ${{ inputs.region }}
|
||||
# TF_ACC_TEST_PROJECT_SERVICE_ACCOUNT_EMAIL: ${{ secrets.TF_ACC_TEST_PROJECT_SERVICE_ACCOUNT_EMAIL }}
|
||||
# TF_ACC_TEST_PROJECT_SERVICE_ACCOUNT_TOKEN: ${{ secrets.TF_ACC_TEST_PROJECT_SERVICE_ACCOUNT_TOKEN }}
|
||||
# TF_ACC_TEST_PROJECT_PARENT_CONTAINER_ID: ${{ secrets.TF_ACC_TEST_PROJECT_PARENT_CONTAINER_ID }}
|
||||
# TF_ACC_TEST_PROJECT_PARENT_UUID: ${{ secrets.TF_ACC_TEST_PROJECT_PARENT_UUID }}
|
||||
# TF_ACC_TEST_PROJECT_USER_EMAIL: ${{ secrets.TF_ACC_TEST_PROJECT_USER_EMAIL }}
|
||||
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 }}
|
||||
|
||||
# does not work correctly
|
||||
# - name: Run test action
|
||||
# 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
|
||||
run: |
|
||||
echo "::group::go test all"
|
||||
set -e
|
||||
set -o pipefail
|
||||
|
||||
if [[ "${{ inputs.tf_debug }}" == "true" ]]; then
|
||||
TF_LOG=INFO
|
||||
export TF_LOG
|
||||
fi
|
||||
|
||||
echo "Running acceptance tests for the terraform provider"
|
||||
echo "${STACKIT_SERVICE_ACCOUNT_JSON}" > ~/.service_account.json
|
||||
cd stackit
|
||||
cd stackit || exit 1
|
||||
TF_ACC=1 \
|
||||
TF_ACC_PROJECT_ID=${TF_ACC_PROJECT_ID} \
|
||||
TF_ACC_REGION=${TF_ACC_REGION} \
|
||||
go test ./... -count=1 -timeout=30m
|
||||
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:
|
||||
STACKIT_SERVICE_ACCOUNT_JSON: ${{ inputs.service_account_json }}
|
||||
TF_PROJECT_ID: ${{ inputs.project_id }}
|
||||
TF_ACC_PROJECT_ID: ${{ inputs.project_id }}
|
||||
TF_ACC_REGION: ${{ inputs.region }}
|
||||
# TF_ACC_TEST_PROJECT_SERVICE_ACCOUNT_EMAIL: ${{ secrets.TF_ACC_TEST_PROJECT_SERVICE_ACCOUNT_EMAIL }}
|
||||
# TF_ACC_TEST_PROJECT_SERVICE_ACCOUNT_TOKEN: ${{ secrets.TF_ACC_TEST_PROJECT_SERVICE_ACCOUNT_TOKEN }}
|
||||
# TF_ACC_TEST_PROJECT_PARENT_CONTAINER_ID: ${{ secrets.TF_ACC_TEST_PROJECT_PARENT_CONTAINER_ID }}
|
||||
# TF_ACC_TEST_PROJECT_PARENT_UUID: ${{ secrets.TF_ACC_TEST_PROJECT_PARENT_UUID }}
|
||||
# TF_ACC_TEST_PROJECT_USER_EMAIL: ${{ secrets.TF_ACC_TEST_PROJECT_USER_EMAIL }}
|
||||
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 }}
|
||||
|
|
|
|||
54
.github/actions/build/action.yaml
vendored
54
.github/actions/build/action.yaml
vendored
|
|
@ -20,25 +20,63 @@ runs:
|
|||
run: |
|
||||
set -e
|
||||
apt-get -y -qq update
|
||||
apt-get -y -qq install jq python3 python3-pip python-is-python3 s3cmd git make wget
|
||||
apt-get -y -qq install jq python3 python3-pip python-is-python3 s3cmd git make wget unzip bc
|
||||
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Install Go ${{ inputs.go-version }}
|
||||
uses: actions/setup-go@v6
|
||||
with:
|
||||
go-version: ${{ inputs.go-version }}
|
||||
# go-version: ${{ inputs.go-version }}
|
||||
check-latest: true
|
||||
go-version-file: 'go.mod'
|
||||
|
||||
- name: Determine GOMODCACHE
|
||||
shell: bash
|
||||
id: goenv
|
||||
run: |
|
||||
set -e
|
||||
# echo "::set-output name=gomodcache::$(go env GOMODCACHE)"
|
||||
echo "gomodcache=$(go env GOMODCACHE)" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Restore cached GO pkg
|
||||
id: cache-gopkg
|
||||
uses: actions/cache/restore@v5
|
||||
with:
|
||||
path: "${{ steps.goenv.outputs.gomodcache }}"
|
||||
key: ${{ runner.os }}-gopkg
|
||||
|
||||
- name: Install go tools
|
||||
if: steps.cache-gopkg.outputs.cache-hit != 'true'
|
||||
shell: bash
|
||||
run: |
|
||||
set -e
|
||||
go install golang.org/x/tools/cmd/goimports@latest
|
||||
go install github.com/hashicorp/terraform-plugin-codegen-framework/cmd/tfplugingen-framework@latest
|
||||
go install github.com/hashicorp/terraform-plugin-codegen-openapi/cmd/tfplugingen-openapi@latest
|
||||
go install github.com/hashicorp/terraform-plugin-docs/cmd/tfplugindocs@v0.24.0
|
||||
go install github.com/hashicorp/terraform-plugin-docs/cmd/tfplugindocs@latest
|
||||
|
||||
# - name: Run build pkg directory
|
||||
# shell: bash
|
||||
# run: |
|
||||
# set -e
|
||||
# go run generator/main.go build
|
||||
|
||||
- name: Get all go packages
|
||||
if: steps.cache-gopkg.outputs.cache-hit != 'true'
|
||||
shell: bash
|
||||
run: |
|
||||
set -e
|
||||
go get ./...
|
||||
|
||||
- name: Save Cache
|
||||
id: cache-gopkg-save
|
||||
uses: actions/cache/save@v5
|
||||
with:
|
||||
path: |
|
||||
${{ steps.goenv.outputs.gomodcache }}
|
||||
key: ${{ runner.os }}-gopkg
|
||||
|
||||
- name: Setup JAVA ${{ inputs.java-distribution }} ${{ inputs.go-version }}
|
||||
uses: actions/setup-java@v5
|
||||
|
|
@ -46,16 +84,6 @@ runs:
|
|||
distribution: ${{ inputs.java-distribution }} # See 'Supported distributions' for available options
|
||||
java-version: ${{ inputs.java-version }}
|
||||
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Run build pkg directory
|
||||
shell: bash
|
||||
run: |
|
||||
set -e
|
||||
go run cmd/main.go build
|
||||
|
||||
|
||||
- name: Run make to build app
|
||||
shell: bash
|
||||
run: |
|
||||
|
|
|
|||
71
.github/actions/setup-cache-go/action.yaml
vendored
Normal file
71
.github/actions/setup-cache-go/action.yaml
vendored
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
name: 'Setup Go and cache dependencies'
|
||||
author: 'Forgejo authors, Marcel S. Henselin'
|
||||
description: |
|
||||
Wrap the setup-go with improved dependency caching.
|
||||
|
||||
inputs:
|
||||
username:
|
||||
description: 'User for which to manage the dependency cache'
|
||||
default: root
|
||||
|
||||
go-version:
|
||||
description: "go version to install"
|
||||
default: '1.25'
|
||||
required: true
|
||||
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
- name: "Install zstd for faster caching"
|
||||
shell: bash
|
||||
run: |
|
||||
apt-get update -qq
|
||||
apt-get -q install -qq -y zstd
|
||||
|
||||
- name: "Set up Go using setup-go"
|
||||
uses: https://code.forgejo.org/actions/setup-go@v6
|
||||
id: go-version
|
||||
with:
|
||||
# go-version: ${{ inputs.go-version }}
|
||||
check-latest: true # Always check for the latest patch release
|
||||
go-version-file: "go.mod"
|
||||
# do not cache dependencies, we do this manually
|
||||
cache: false
|
||||
|
||||
- name: "Get go environment information"
|
||||
shell: bash
|
||||
id: go-environment
|
||||
run: |
|
||||
chmod 755 $HOME # ensure ${RUN_AS_USER} has permission when go is located in $HOME
|
||||
export GOROOT="$(go env GOROOT)"
|
||||
echo "modcache=$(su ${RUN_AS_USER} -c '${GOROOT}/bin/go env GOMODCACHE')" >> "$GITHUB_OUTPUT"
|
||||
echo "cache=$(su ${RUN_AS_USER} -c '${GOROOT}/bin/go env GOCACHE')" >> "$GITHUB_OUTPUT"
|
||||
env:
|
||||
RUN_AS_USER: ${{ inputs.username }}
|
||||
GO_VERSION: ${{ steps.go-version.outputs.go-version }}
|
||||
|
||||
- name: "Create cache folders with correct permissions (for non-root users)"
|
||||
shell: bash
|
||||
if: inputs.username != 'root'
|
||||
# when the cache is restored, only the permissions of the last part are restored
|
||||
# so assuming that /home/user exists and we are restoring /home/user/go/pkg/mod,
|
||||
# both folders will have the correct permissions, but
|
||||
# /home/user/go and /home/user/go/pkg might be owned by root
|
||||
run: |
|
||||
su ${RUN_AS_USER} -c 'mkdir -p "${MODCACHE_DIR}" "${CACHE_DIR}"'
|
||||
env:
|
||||
RUN_AS_USER: ${{ inputs.username }}
|
||||
MODCACHE_DIR: ${{ steps.go-environment.outputs.modcache }}
|
||||
CACHE_DIR: ${{ steps.go-environment.outputs.cache }}
|
||||
|
||||
- name: "Restore Go dependencies from cache or mark for later caching"
|
||||
id: cache-deps
|
||||
uses: https://code.forgejo.org/actions/cache@v5
|
||||
with:
|
||||
key: setup-cache-go-deps-${{ runner.os }}-${{ inputs.username }}-${{ steps.go-version.outputs.go_version }}-${{ hashFiles('go.sum', 'go.mod') }}
|
||||
restore-keys: |
|
||||
setup-cache-go-deps-${{ runner.os }}-${{ inputs.username }}-${{ steps.go-version.outputs.go_version }}-
|
||||
setup-cache-go-deps-${{ runner.os }}-${{ inputs.username }}-
|
||||
path: |
|
||||
${{ steps.go-environment.outputs.modcache }}
|
||||
${{ steps.go-environment.outputs.cache }}
|
||||
|
|
@ -6,6 +6,11 @@ on:
|
|||
- alpha
|
||||
- main
|
||||
workflow_dispatch:
|
||||
schedule:
|
||||
# every sunday at 00:00
|
||||
# - cron: '0 0 * * 0'
|
||||
# every day at 00:00
|
||||
- cron: '0 0 * * *'
|
||||
push:
|
||||
branches:
|
||||
- '!main'
|
||||
|
|
@ -17,6 +22,39 @@ env:
|
|||
CODE_COVERAGE_ARTIFACT_NAME: "code-coverage"
|
||||
|
||||
jobs:
|
||||
runner_test:
|
||||
name: "Test STACKIT runner"
|
||||
runs-on: stackit-docker
|
||||
steps:
|
||||
- name: Install needed tools
|
||||
run: |
|
||||
apt-get -y -qq update
|
||||
apt-get -y -qq install jq python3 python3-pip python-is-python3 s3cmd git make wget
|
||||
|
||||
- name: Setup Go
|
||||
uses: actions/setup-go@v6
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
|
||||
- name: Install go tools
|
||||
run: |
|
||||
go install golang.org/x/tools/cmd/goimports@latest
|
||||
go install github.com/hashicorp/terraform-plugin-codegen-framework/cmd/tfplugingen-framework@latest
|
||||
go install github.com/hashicorp/terraform-plugin-codegen-openapi/cmd/tfplugingen-openapi@latest
|
||||
|
||||
- name: Setup JAVA
|
||||
uses: actions/setup-java@v5
|
||||
with:
|
||||
distribution: 'temurin' # See 'Supported distributions' for available options
|
||||
java-version: '21'
|
||||
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Run build pkg directory
|
||||
run: |
|
||||
go run cmd/main.go build
|
||||
|
||||
publish_test:
|
||||
name: "Test readiness for publishing provider"
|
||||
needs: config
|
||||
|
|
@ -99,20 +137,78 @@ jobs:
|
|||
--gpgPubKeyFile=public_key.pem \
|
||||
--version=${VERSION}
|
||||
|
||||
testing:
|
||||
name: CI run tests
|
||||
runs-on: ubuntu-latest
|
||||
needs: config
|
||||
env:
|
||||
TF_ACC_PROJECT_ID: ${{ vars.TF_ACC_PROJECT_ID }}
|
||||
TF_ACC_REGION: ${{ vars.TF_ACC_REGION }}
|
||||
TF_ACC_TEST_PROJECT_SERVICE_ACCOUNT_EMAIL: ${{ vars.TF_ACC_TEST_PROJECT_SERVICE_ACCOUNT_EMAIL }}
|
||||
TF_ACC_SERVICE_ACCOUNT_FILE: "~/service_account.json"
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Build
|
||||
uses: ./.github/actions/build
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
|
||||
- name: Setup Terraform
|
||||
uses: hashicorp/setup-terraform@v2
|
||||
with:
|
||||
terraform_wrapper: false
|
||||
|
||||
- name: Create service account json file
|
||||
if: ${{ github.event_name == 'pull_request' }}
|
||||
run: |
|
||||
echo "${{ secrets.TF_ACC_SERVICE_ACCOUNT_JSON }}" >~/service_account.json
|
||||
|
||||
- name: Run go mod tidy
|
||||
if: ${{ github.event_name == 'pull_request' }}
|
||||
run: go mod tidy
|
||||
|
||||
- name: Testing
|
||||
run: make test
|
||||
|
||||
- name: Acceptance Testing
|
||||
env:
|
||||
TF_ACC: "1"
|
||||
if: ${{ github.event_name == 'pull_request' }}
|
||||
run: make test-acceptance-tf
|
||||
|
||||
- name: Check coverage threshold
|
||||
shell: bash
|
||||
run: |
|
||||
make coverage
|
||||
COVERAGE=$(go tool cover -func=coverage.out | grep total | awk '{print $3}' | sed 's/%//')
|
||||
echo "Coverage: $COVERAGE%"
|
||||
if (( $(echo "$COVERAGE < 80" | bc -l) )); then
|
||||
echo "Coverage is below 80%"
|
||||
# exit 1
|
||||
fi
|
||||
|
||||
- name: Archive code coverage results
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ${{ env.CODE_COVERAGE_ARTIFACT_NAME }}
|
||||
path: "stackit/${{ env.CODE_COVERAGE_FILE_NAME }}"
|
||||
|
||||
main:
|
||||
name: CI
|
||||
if: ${{ github.event_name != 'schedule' }}
|
||||
name: CI run build and linting
|
||||
runs-on: ubuntu-latest
|
||||
needs: config
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
|
||||
|
||||
- name: Build
|
||||
uses: ./.github/actions/build
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
|
||||
|
||||
- name: Setup Terraform
|
||||
uses: hashicorp/setup-terraform@v2
|
||||
with:
|
||||
|
|
@ -130,22 +226,40 @@ jobs:
|
|||
- name: golangci-lint
|
||||
uses: golangci/golangci-lint-action@v9
|
||||
with:
|
||||
version: v2.7
|
||||
version: v2.9
|
||||
args: --config=golang-ci.yaml --allow-parallel-runners --timeout=5m
|
||||
continue-on-error: true
|
||||
|
||||
- name: Lint
|
||||
- name: Linting
|
||||
run: make lint
|
||||
|
||||
- name: Test
|
||||
run: make test
|
||||
continue-on-error: true
|
||||
|
||||
- name: Archive code coverage results
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ${{ env.CODE_COVERAGE_ARTIFACT_NAME }}
|
||||
path: "stackit/${{ env.CODE_COVERAGE_FILE_NAME }}"
|
||||
# - name: Testing
|
||||
# run: make test
|
||||
#
|
||||
# - name: Acceptance Testing
|
||||
# if: ${{ github.event_name == 'pull_request' }}
|
||||
# run: make test-acceptance-tf
|
||||
#
|
||||
# - name: Check coverage threshold
|
||||
# shell: bash
|
||||
# run: |
|
||||
# make coverage
|
||||
# COVERAGE=$(go tool cover -func=coverage.out | grep total | awk '{print $3}' | sed 's/%//')
|
||||
# echo "Coverage: $COVERAGE%"
|
||||
# if (( $(echo "$COVERAGE < 80" | bc -l) )); then
|
||||
# echo "Coverage is below 80%"
|
||||
# # exit 1
|
||||
# fi
|
||||
|
||||
# - name: Archive code coverage results
|
||||
# uses: actions/upload-artifact@v4
|
||||
# with:
|
||||
# name: ${{ env.CODE_COVERAGE_ARTIFACT_NAME }}
|
||||
# path: "stackit/${{ env.CODE_COVERAGE_FILE_NAME }}"
|
||||
|
||||
config:
|
||||
if: ${{ github.event_name != 'schedule' }}
|
||||
name: Check GoReleaser config
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
354
.github/workflows/ci_new.yaml
vendored
Normal file
354
.github/workflows/ci_new.yaml
vendored
Normal file
|
|
@ -0,0 +1,354 @@
|
|||
name: CI Workflow
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types: [ opened, synchronize, reopened ]
|
||||
branches:
|
||||
- alpha
|
||||
- main
|
||||
workflow_dispatch:
|
||||
schedule:
|
||||
# every sunday at 00:00
|
||||
# - cron: '0 0 * * 0'
|
||||
# every day at 00:00
|
||||
- cron: '0 0 * * *'
|
||||
push:
|
||||
branches:
|
||||
- '!main'
|
||||
- '!alpha'
|
||||
paths:
|
||||
- '!.github'
|
||||
|
||||
env:
|
||||
GO_VERSION: "1.25"
|
||||
CODE_COVERAGE_FILE_NAME: "coverage.out" # must be the same as in Makefile
|
||||
CODE_COVERAGE_ARTIFACT_NAME: "code-coverage"
|
||||
|
||||
jobs:
|
||||
config:
|
||||
if: ${{ github.event_name != 'schedule' }}
|
||||
name: Check GoReleaser config
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Check GoReleaser
|
||||
uses: goreleaser/goreleaser-action@v7
|
||||
with:
|
||||
args: check
|
||||
|
||||
prepare:
|
||||
name: Prepare GO cache
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
actions: read # Required to identify workflow run.
|
||||
checks: write # Required to add status summary.
|
||||
contents: read # Required to checkout repository.
|
||||
pull-requests: write # Required to add PR comment.
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Install Go ${{ inputs.go-version }}
|
||||
id: go-install
|
||||
uses: actions/setup-go@v6
|
||||
with:
|
||||
# go-version: ${{ inputs.go-version }}
|
||||
check-latest: true
|
||||
go-version-file: 'go.mod'
|
||||
|
||||
- name: Determine GOMODCACHE
|
||||
shell: bash
|
||||
id: goenv
|
||||
run: |
|
||||
set -e
|
||||
# echo "::set-output name=gomodcache::$(go env GOMODCACHE)"
|
||||
echo "gomodcache=$(go env GOMODCACHE)" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Restore cached GO pkg
|
||||
id: cache-gopkg
|
||||
uses: actions/cache/restore@v5
|
||||
with:
|
||||
path: "${{ steps.goenv.outputs.gomodcache }}"
|
||||
key: ${{ runner.os }}-gopkg
|
||||
|
||||
- name: Install go tools
|
||||
if: steps.cache-gopkg.outputs.cache-hit != 'true'
|
||||
run: |
|
||||
go install golang.org/x/tools/cmd/goimports@latest
|
||||
go install github.com/hashicorp/terraform-plugin-codegen-framework/cmd/tfplugingen-framework@latest
|
||||
go install github.com/hashicorp/terraform-plugin-codegen-openapi/cmd/tfplugingen-openapi@latest
|
||||
|
||||
- name: Get all go packages
|
||||
if: steps.cache-gopkg.outputs.cache-hit != 'true'
|
||||
shell: bash
|
||||
run: |
|
||||
set -e
|
||||
go get ./...
|
||||
|
||||
- name: Save Cache
|
||||
if: steps.cache-gopkg.outputs.cache-hit != 'true'
|
||||
id: cache-gopkg-save
|
||||
uses: actions/cache/save@v5
|
||||
with:
|
||||
path: |
|
||||
${{ steps.goenv.outputs.gomodcache }}
|
||||
key: ${{ runner.os }}-gopkg
|
||||
|
||||
|
||||
publish_test:
|
||||
name: "Test readiness for publishing provider"
|
||||
needs:
|
||||
- config
|
||||
- prepare
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
actions: read # Required to identify workflow run.
|
||||
checks: write # Required to add status summary.
|
||||
contents: read # Required to checkout repository.
|
||||
pull-requests: write # Required to add PR comment.
|
||||
steps:
|
||||
- name: Install needed tools
|
||||
run: |
|
||||
apt-get -y -qq update
|
||||
apt-get -y -qq install jq python3 python3-pip python-is-python3 s3cmd git make wget unzip bc
|
||||
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Setup Go
|
||||
uses: actions/setup-go@v6
|
||||
with:
|
||||
# go-version: ${{ env.GO_VERSION }}
|
||||
check-latest: true
|
||||
go-version-file: 'go.mod'
|
||||
|
||||
- name: Install go tools
|
||||
run: |
|
||||
go install golang.org/x/tools/cmd/goimports@latest
|
||||
go install github.com/hashicorp/terraform-plugin-codegen-framework/cmd/tfplugingen-framework@latest
|
||||
go install github.com/hashicorp/terraform-plugin-codegen-openapi/cmd/tfplugingen-openapi@latest
|
||||
|
||||
- name: Setup JAVA
|
||||
uses: actions/setup-java@v5
|
||||
with:
|
||||
distribution: 'temurin' # See 'Supported distributions' for available options
|
||||
java-version: '21'
|
||||
|
||||
# - name: Run build pkg directory
|
||||
# run: |
|
||||
# go run generator/main.go build
|
||||
|
||||
- name: Set up s3cfg
|
||||
run: |
|
||||
cat <<'EOF' >> ~/.s3cfg
|
||||
[default]
|
||||
host_base = https://object.storage.eu01.onstackit.cloud
|
||||
host_bucket = https://%(bucket).object.storage.eu01.onstackit.cloud
|
||||
check_ssl_certificate = False
|
||||
access_key = ${{ secrets.S3_ACCESS_KEY }}
|
||||
secret_key = ${{ secrets.S3_SECRET_KEY }}
|
||||
EOF
|
||||
|
||||
- name: Import GPG key
|
||||
run: |
|
||||
echo "${{ secrets.PRIVATE_KEY_PEM }}" > ~/private.key.pem
|
||||
gpg --import ~/private.key.pem
|
||||
rm ~/private.key.pem
|
||||
|
||||
- name: Run GoReleaser with SNAPSHOT
|
||||
id: goreleaser
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ env.FORGEJO_TOKEN }}
|
||||
GPG_FINGERPRINT: ${{ secrets.GPG_FINGERPRINT }}
|
||||
uses: goreleaser/goreleaser-action@v7
|
||||
with:
|
||||
args: release --skip publish --clean --snapshot
|
||||
|
||||
- name: Prepare key file
|
||||
run: |
|
||||
echo "${{ secrets.PUBLIC_KEY_PEM }}" >public_key.pem
|
||||
|
||||
- name: Prepare provider directory structure
|
||||
run: |
|
||||
VERSION=$(jq -r .version < dist/metadata.json)
|
||||
go run generator/main.go \
|
||||
publish \
|
||||
--namespace=mhenselin \
|
||||
--providerName=stackitprivatepreview \
|
||||
--repoName=terraform-provider-stackitprivatepreview \
|
||||
--domain=tfregistry.sysops.stackit.rocks \
|
||||
--gpgFingerprint="${{ secrets.GPG_FINGERPRINT }}" \
|
||||
--gpgPubKeyFile=public_key.pem \
|
||||
--version=${VERSION}
|
||||
|
||||
testing:
|
||||
name: CI run tests
|
||||
runs-on: ubuntu-latest
|
||||
needs:
|
||||
- config
|
||||
- prepare
|
||||
env:
|
||||
TF_ACC_PROJECT_ID: ${{ vars.TF_ACC_PROJECT_ID }}
|
||||
TF_ACC_ORGANIZATION_ID: ${{ vars.TF_ACC_ORGANIZATION_ID }}
|
||||
TF_ACC_REGION: ${{ vars.TF_ACC_REGION }}
|
||||
TF_ACC_TEST_PROJECT_SERVICE_ACCOUNT_EMAIL: ${{ vars.TF_ACC_TEST_PROJECT_SERVICE_ACCOUNT_EMAIL }}
|
||||
TF_ACC_SERVICE_ACCOUNT_FILE: "~/service_account.json"
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Build
|
||||
uses: ./.github/actions/build
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
|
||||
- name: Setup Terraform
|
||||
uses: hashicorp/setup-terraform@v2
|
||||
with:
|
||||
terraform_wrapper: false
|
||||
|
||||
- name: Create service account json file
|
||||
if: ${{ github.event_name == 'pull_request' }}
|
||||
run: |
|
||||
echo "${{ secrets.TF_ACC_SERVICE_ACCOUNT_JSON }}" >~/.service_account.json
|
||||
|
||||
- name: Run go mod tidy
|
||||
if: ${{ github.event_name == 'pull_request' }}
|
||||
run: go mod tidy
|
||||
|
||||
- name: Testing
|
||||
if: ${{ github.event_name != 'pull_request' }}
|
||||
run: |
|
||||
unset TF_ACC
|
||||
TF_ACC_SERVICE_ACCOUNT_FILE=~/.service_account.json
|
||||
export TF_ACC_SERVICE_ACCOUNT_FILE
|
||||
make test
|
||||
|
||||
- name: Testing with coverage
|
||||
if: ${{ github.event_name == 'pull_request' }}
|
||||
run: |
|
||||
unset TF_ACC
|
||||
TF_ACC_SERVICE_ACCOUNT_FILE=~/.service_account.json
|
||||
export TF_ACC_SERVICE_ACCOUNT_FILE
|
||||
make coverage
|
||||
|
||||
# - name: Acceptance Testing
|
||||
# env:
|
||||
# TF_ACC: "1"
|
||||
# if: ${{ github.event_name == 'pull_request' }}
|
||||
# run: |
|
||||
# TF_ACC_SERVICE_ACCOUNT_FILE=~/.service_account.json
|
||||
# export TF_ACC_SERVICE_ACCOUNT_FILE
|
||||
# make test-acceptance-tf
|
||||
|
||||
# - name: Run Acceptance Test
|
||||
# if: ${{ github.event_name == 'pull_request' }}
|
||||
# uses: ./.github/actions/acc_test
|
||||
# with:
|
||||
# go-version: ${{ env.GO_VERSION }}
|
||||
# project_id: ${{ vars.TF_ACC_PROJECT_ID }}
|
||||
# region: ${{ vars.TF_ACC_REGION }}
|
||||
# service_account_json_content_b64: "${{ secrets.TF_ACC_SERVICE_ACCOUNT_JSON_B64 }}"
|
||||
# project_user_email: ${{ vars.TEST_PROJECT_USER_EMAIL }}
|
||||
# tf_acc_kek_key_id: ${{ vars.TF_ACC_KEK_KEY_ID }}
|
||||
# tf_acc_kek_key_ring_id: ${{ vars.TF_ACC_KEK_KEY_RING_ID }}
|
||||
# tf_acc_kek_key_version: ${{ vars.TF_ACC_KEK_KEY_VERSION }}
|
||||
# tf_acc_kek_service_account: ${{ vars.TF_ACC_KEK_SERVICE_ACCOUNT }}
|
||||
# # service_account_json_file_path: "~/service_account.json"
|
||||
|
||||
- name: Check coverage threshold
|
||||
shell: bash
|
||||
run: |
|
||||
make coverage
|
||||
COVERAGE=$(go tool cover -func=coverage.out | grep total | awk '{print $3}' | sed 's/%//')
|
||||
echo "Coverage: $COVERAGE%"
|
||||
if (( $(echo "$COVERAGE < 80" | bc -l) )); then
|
||||
echo "Coverage is below 80%"
|
||||
# exit 1
|
||||
fi
|
||||
|
||||
- name: Archive code coverage results
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ${{ env.CODE_COVERAGE_ARTIFACT_NAME }}
|
||||
path: "stackit/${{ env.CODE_COVERAGE_FILE_NAME }}"
|
||||
|
||||
main:
|
||||
if: ${{ github.event_name != 'schedule' }}
|
||||
name: CI run build and linting
|
||||
runs-on: ubuntu-latest
|
||||
needs:
|
||||
- config
|
||||
- prepare
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
|
||||
# - uses: actions/cache@v5
|
||||
# id: cache
|
||||
# with:
|
||||
# path: path/to/dependencies
|
||||
# key: ${{ runner.os }}-${{ hashFiles('**/lockfiles') }}
|
||||
|
||||
# - name: Install Dependencies
|
||||
# if: steps.cache.outputs.cache-hit != 'true'
|
||||
# run: /install.sh
|
||||
|
||||
- name: Build
|
||||
uses: ./.github/actions/build
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
|
||||
- name: Setup Terraform
|
||||
uses: hashicorp/setup-terraform@v2
|
||||
with:
|
||||
terraform_wrapper: false
|
||||
|
||||
- name: "Ensure docs are up-to-date"
|
||||
if: ${{ github.event_name == 'pull_request' }}
|
||||
run: ./scripts/check-docs.sh
|
||||
continue-on-error: true
|
||||
|
||||
- name: "Run go mod tidy"
|
||||
if: ${{ github.event_name == 'pull_request' }}
|
||||
run: go mod tidy
|
||||
|
||||
- name: golangci-lint
|
||||
uses: golangci/golangci-lint-action@v9
|
||||
with:
|
||||
version: v2.10
|
||||
args: --config=.golang-ci.yaml --allow-parallel-runners --timeout=5m
|
||||
continue-on-error: true
|
||||
|
||||
- name: Linting terraform files
|
||||
run: make lint-tf
|
||||
continue-on-error: true
|
||||
|
||||
code_coverage:
|
||||
name: "Code coverage report"
|
||||
if: github.event_name == 'pull_request' # Do not run when workflow is triggered by push to main branch
|
||||
runs-on: ubuntu-latest
|
||||
needs:
|
||||
- main
|
||||
- prepare
|
||||
permissions:
|
||||
contents: read
|
||||
actions: read # to download code coverage results from "main" job
|
||||
pull-requests: write # write permission needed to comment on PR
|
||||
steps:
|
||||
- name: Install needed tools
|
||||
shell: bash
|
||||
run: |
|
||||
set -e
|
||||
apt-get -y -qq update
|
||||
apt-get -y -qq install sudo
|
||||
|
||||
- name: Check new code coverage
|
||||
uses: fgrosse/go-coverage-report@v1.2.0
|
||||
continue-on-error: true # Add this line to prevent pipeline failures in forks
|
||||
with:
|
||||
coverage-artifact-name: ${{ env.CODE_COVERAGE_ARTIFACT_NAME }}
|
||||
coverage-file-name: ${{ env.CODE_COVERAGE_FILE_NAME }}
|
||||
root-package: 'github.com/stackitcloud/terraform-provider-stackit'
|
||||
32
.github/workflows/publish.yaml
vendored
32
.github/workflows/publish.yaml
vendored
|
|
@ -23,7 +23,7 @@ jobs:
|
|||
uses: actions/checkout@v6
|
||||
|
||||
- name: Check GoReleaser
|
||||
uses: goreleaser/goreleaser-action@v6
|
||||
uses: goreleaser/goreleaser-action@v7
|
||||
with:
|
||||
args: check
|
||||
|
||||
|
|
@ -43,10 +43,15 @@ jobs:
|
|||
apt-get -y -qq update
|
||||
apt-get -y -qq install jq python3 python3-pip python-is-python3 s3cmd git make wget
|
||||
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Setup Go
|
||||
uses: actions/setup-go@v6
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
# go-version: ${{ env.GO_VERSION }}
|
||||
check-latest: true
|
||||
go-version-file: 'go.mod'
|
||||
|
||||
- name: Install go tools
|
||||
run: |
|
||||
|
|
@ -60,16 +65,6 @@ jobs:
|
|||
distribution: 'temurin' # See 'Supported distributions' for available options
|
||||
java-version: '21'
|
||||
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Run build pkg directory
|
||||
run: |
|
||||
set -e
|
||||
mkdir -p generated/services
|
||||
mkdir -p generated/internal/services
|
||||
go run cmd/main.go build
|
||||
|
||||
- name: Set up s3cfg
|
||||
run: |
|
||||
cat <<'EOF' >> ~/.s3cfg
|
||||
|
|
@ -93,7 +88,7 @@ jobs:
|
|||
env:
|
||||
GITHUB_TOKEN: ${{ env.FORGEJO_TOKEN }}
|
||||
GPG_FINGERPRINT: ${{ secrets.GPG_FINGERPRINT }}
|
||||
uses: goreleaser/goreleaser-action@v6
|
||||
uses: goreleaser/goreleaser-action@v7
|
||||
with:
|
||||
args: release --skip publish --clean --snapshot
|
||||
|
||||
|
|
@ -103,7 +98,7 @@ jobs:
|
|||
env:
|
||||
GITHUB_TOKEN: ${{ env.FORGEJO_TOKEN }}
|
||||
GPG_FINGERPRINT: ${{ secrets.GPG_FINGERPRINT }}
|
||||
uses: goreleaser/goreleaser-action@v6
|
||||
uses: goreleaser/goreleaser-action@v7
|
||||
with:
|
||||
args: release --skip publish --clean
|
||||
|
||||
|
|
@ -114,7 +109,7 @@ jobs:
|
|||
- name: Prepare provider directory structure
|
||||
run: |
|
||||
VERSION=$(jq -r .version < dist/metadata.json)
|
||||
go run cmd/main.go \
|
||||
go run generator/main.go \
|
||||
publish \
|
||||
--namespace=mhenselin \
|
||||
--providerName=stackitprivatepreview \
|
||||
|
|
@ -124,6 +119,12 @@ jobs:
|
|||
--gpgPubKeyFile=public_key.pem \
|
||||
--version=${VERSION}
|
||||
|
||||
- name: Prepare documentation nav file
|
||||
run: |
|
||||
go run generator/main.go \
|
||||
docs \
|
||||
--outFile nav.md
|
||||
|
||||
- name: Publish provider to S3
|
||||
run: |
|
||||
set -e
|
||||
|
|
@ -143,3 +144,4 @@ jobs:
|
|||
ssh -o StrictHostKeyChecking=no ubuntu@${{ vars.DOCS_SERVER_IP }} 'rm -rf /srv/www/docs'
|
||||
echo "${{ github.ref_name }}" >docs/_version.txt
|
||||
scp -o StrictHostKeyChecking=no -r docs ubuntu@${{ vars.DOCS_SERVER_IP }}:/srv/www/
|
||||
scp -o StrictHostKeyChecking=no nav.md ubuntu@${{ vars.DOCS_SERVER_IP }}:/srv/www/
|
||||
|
|
|
|||
6
.github/workflows/release.yaml
vendored
6
.github/workflows/release.yaml
vendored
|
|
@ -22,17 +22,19 @@ jobs:
|
|||
with:
|
||||
# Allow goreleaser to access older tag information.
|
||||
fetch-depth: 0
|
||||
- uses: actions/setup-go@v5
|
||||
|
||||
- uses: https://code.forgejo.org/actions/setup-go@v6
|
||||
with:
|
||||
go-version-file: "go.mod"
|
||||
cache: true
|
||||
|
||||
- name: Import GPG key
|
||||
uses: crazy-max/ghaction-import-gpg@v6
|
||||
id: import_gpg
|
||||
with:
|
||||
gpg_private_key: ${{ secrets.GPG_PRIVATE_KEY }}
|
||||
- name: Run GoReleaser
|
||||
uses: goreleaser/goreleaser-action@v6
|
||||
uses: goreleaser/goreleaser-action@v7
|
||||
with:
|
||||
args: release --clean
|
||||
env:
|
||||
|
|
|
|||
6
.github/workflows/renovate.yaml
vendored
6
.github/workflows/renovate.yaml
vendored
|
|
@ -12,8 +12,10 @@ jobs:
|
|||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Self-hosted Renovate
|
||||
uses: renovatebot/github-action@v41.0.0
|
||||
uses: renovatebot/github-action@v46.1.4
|
||||
with:
|
||||
configurationFile: .github/renovate.json
|
||||
token: ${{ secrets.RENOVATE_TOKEN }}
|
||||
# token: ${{ secrets.RENOVATE_TOKEN }}
|
||||
token: ${{ env.FORGEJO_TOKEN }}
|
||||
|
|
|
|||
29
.github/workflows/runnerstats.yaml
vendored
Normal file
29
.github/workflows/runnerstats.yaml
vendored
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
name: Runner stats
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
stats-own:
|
||||
name: "Get own runner stats"
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Install needed tools
|
||||
run: |
|
||||
apt-get -y -qq update
|
||||
apt-get -y -qq install inxi
|
||||
|
||||
- name: Show stats
|
||||
run: inxi -c 0
|
||||
|
||||
stats-stackit:
|
||||
name: "Get STACKIT runner stats"
|
||||
runs-on: stackit-docker
|
||||
steps:
|
||||
- name: Install needed tools
|
||||
run: |
|
||||
apt-get -y -qq update
|
||||
apt-get -y -qq install inxi
|
||||
|
||||
- name: Show stats
|
||||
run: inxi -c 0
|
||||
43
.github/workflows/tf-acc-test.yaml
vendored
43
.github/workflows/tf-acc-test.yaml
vendored
|
|
@ -1,10 +1,24 @@
|
|||
name: TF Acceptance Tests Workflow
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types: [opened, synchronize, reopened]
|
||||
branches:
|
||||
- alpha
|
||||
- main
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
enable_debug:
|
||||
description: "enable terraform debug logs"
|
||||
default: 'false'
|
||||
required: true
|
||||
test_timeout_string:
|
||||
description: "string that determines the timeout (default: 45m)"
|
||||
default: '90m'
|
||||
required: true
|
||||
|
||||
jobs:
|
||||
acc_test:
|
||||
|
|
@ -14,10 +28,33 @@ jobs:
|
|||
- name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Run Test
|
||||
- name: Run Test (workflow dispatch)
|
||||
if: ${{ github.event_name == 'workflow_dispatch' }}
|
||||
uses: ./.github/actions/acc_test
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
project_id: ${{ vars.TEST_PROJECT_ID }}
|
||||
project_id: ${{ vars.TF_ACC_PROJECT_ID }}
|
||||
region: 'eu01'
|
||||
service_account_json: ${{ secrets.TF_ACC_SERVICE_ACCOUNT_JSON }}
|
||||
service_account_json_content_b64: "${{ secrets.TF_ACC_SERVICE_ACCOUNT_JSON_B64 }}"
|
||||
project_user_email: ${{ vars.TEST_PROJECT_USER_EMAIL }}
|
||||
tf_acc_kek_key_id: ${{ vars.TF_ACC_KEK_KEY_ID }}
|
||||
tf_acc_kek_key_ring_id: ${{ vars.TF_ACC_KEK_KEY_RING_ID }}
|
||||
tf_acc_kek_key_version: ${{ vars.TF_ACC_KEK_KEY_VERSION }}
|
||||
tf_acc_kek_service_account: ${{ vars.TF_ACC_KEK_SERVICE_ACCOUNT }}
|
||||
tf_debug: ${{ inputs.enable_debug }}
|
||||
test_timeout_string: ${{ inputs.test_timeout_string }}
|
||||
|
||||
- name: Run Test (automatic)
|
||||
if: ${{ github.event_name != 'workflow_dispatch' }}
|
||||
uses: ./.github/actions/acc_test
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
project_id: ${{ vars.TF_ACC_PROJECT_ID }}
|
||||
region: 'eu01'
|
||||
service_account_json_content_b64: "${{ secrets.TF_ACC_SERVICE_ACCOUNT_JSON_B64 }}"
|
||||
project_user_email: ${{ vars.TEST_PROJECT_USER_EMAIL }}
|
||||
tf_acc_kek_key_id: ${{ vars.TF_ACC_KEK_KEY_ID }}
|
||||
tf_acc_kek_key_ring_id: ${{ vars.TF_ACC_KEK_KEY_RING_ID }}
|
||||
tf_acc_kek_key_version: ${{ vars.TF_ACC_KEK_KEY_VERSION }}
|
||||
tf_acc_kek_service_account: ${{ vars.TF_ACC_KEK_SERVICE_ACCOUNT }}
|
||||
tf_debug: ${{ inputs.enable_debug }}
|
||||
|
|
|
|||
3
.gitignore
vendored
3
.gitignore
vendored
|
|
@ -40,9 +40,12 @@ coverage.out
|
|||
coverage.html
|
||||
generated
|
||||
stackit-sdk-generator
|
||||
stackit-sdk-generator/**
|
||||
dist
|
||||
|
||||
.secrets
|
||||
|
||||
pkg_gen
|
||||
/release/
|
||||
.env
|
||||
**/.env
|
||||
|
|
|
|||
|
|
@ -1,7 +1,13 @@
|
|||
|
||||
version: "2"
|
||||
run:
|
||||
concurrency: 4
|
||||
output:
|
||||
formats:
|
||||
text:
|
||||
print-linter-name: true
|
||||
print-issued-lines: true
|
||||
colors: true
|
||||
path: stdout
|
||||
linters:
|
||||
enable:
|
||||
- bodyclose
|
||||
|
|
@ -23,7 +29,8 @@ linters:
|
|||
depguard:
|
||||
rules:
|
||||
main:
|
||||
list-mode: lax
|
||||
list-mode: original
|
||||
allow: []
|
||||
deny:
|
||||
- pkg: github.com/stretchr/testify
|
||||
desc: Do not use a testing framework
|
||||
|
|
@ -63,13 +70,17 @@ linters:
|
|||
- name: empty-lines
|
||||
- name: early-return
|
||||
exclusions:
|
||||
generated: lax
|
||||
paths:
|
||||
- third_party$
|
||||
- builtin$
|
||||
- examples$
|
||||
- tools/copy.go
|
||||
- tools/main.go
|
||||
- generator/
|
||||
- internal/testutils
|
||||
generated: lax
|
||||
warn-unused: true
|
||||
# Excluding configuration per-path, per-linter, per-text and per-source.
|
||||
rules:
|
||||
# Exclude some linters from running on tests files.
|
||||
- path: _test\.go
|
||||
linters:
|
||||
- gochecknoinits
|
||||
formatters:
|
||||
enable:
|
||||
- gofmt
|
||||
|
|
@ -77,10 +88,4 @@ formatters:
|
|||
settings:
|
||||
goimports:
|
||||
local-prefixes:
|
||||
- github.com/freiheit-com/nmww
|
||||
exclusions:
|
||||
generated: lax
|
||||
paths:
|
||||
- third_party$
|
||||
- builtin$
|
||||
- examples$
|
||||
- tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview
|
||||
|
|
@ -19,20 +19,20 @@ builds:
|
|||
ldflags:
|
||||
- '-s -w -X main.version={{.Version}} -X main.commit={{.Commit}}'
|
||||
goos:
|
||||
# - freebsd
|
||||
# - windows
|
||||
- freebsd
|
||||
- windows
|
||||
- linux
|
||||
- darwin
|
||||
goarch:
|
||||
- amd64
|
||||
# - '386'
|
||||
# - arm
|
||||
- '386'
|
||||
- arm
|
||||
- arm64
|
||||
# ignore:
|
||||
# - goos: darwin
|
||||
# goarch: '386'
|
||||
# - goos: windows
|
||||
# goarch: arm
|
||||
ignore:
|
||||
- goos: darwin
|
||||
goarch: '386'
|
||||
- goos: windows
|
||||
goarch: arm
|
||||
binary: '{{ .ProjectName }}_v{{ .Version }}'
|
||||
archives:
|
||||
- formats: [ 'zip' ]
|
||||
|
|
|
|||
16
Makefile
16
Makefile
|
|
@ -12,17 +12,20 @@ project-tools:
|
|||
# LINT
|
||||
lint-golangci-lint:
|
||||
@echo "Linting with golangci-lint"
|
||||
@$(SCRIPTS_BASE)/lint-golangci-lint.sh
|
||||
@go run github.com/golangci/golangci-lint/v2/cmd/golangci-lint run --fix --config .golang-ci.yaml
|
||||
|
||||
lint-tf:
|
||||
|
||||
lint-tf:
|
||||
@echo "Linting terraform files"
|
||||
@terraform fmt -check -diff -recursive
|
||||
@terraform fmt -check -diff -recursive examples/
|
||||
@terraform fmt -check -diff -recursive stackit/
|
||||
|
||||
lint: lint-golangci-lint lint-tf
|
||||
|
||||
# DOCUMENTATION GENERATION
|
||||
generate-docs:
|
||||
@echo "Generating documentation with tfplugindocs"
|
||||
|
||||
@$(SCRIPTS_BASE)/tfplugindocs.sh
|
||||
|
||||
build:
|
||||
|
|
@ -34,15 +37,16 @@ fmt:
|
|||
@terraform fmt -diff -recursive
|
||||
|
||||
# TEST
|
||||
.PHONY: test coverage
|
||||
test:
|
||||
@echo "Running tests for the terraform provider"
|
||||
@cd $(ROOT_DIR)/stackit && go test ./... -count=1 -coverprofile=coverage.out && cd $(ROOT_DIR)
|
||||
@cd $(ROOT_DIR)/stackit && go test -timeout 0 ./... -count=1 -coverprofile=../coverage.out && cd $(ROOT_DIR)
|
||||
|
||||
# Test coverage
|
||||
coverage:
|
||||
@echo ">> Creating test coverage report for the terraform provider"
|
||||
@cd $(ROOT_DIR)/stackit && (go test ./... -count=1 -coverprofile=coverage.out || true) && cd $(ROOT_DIR)
|
||||
@cd $(ROOT_DIR)/stackit && go tool cover -html=coverage.out -o coverage.html && cd $(ROOT_DIR)
|
||||
@cd $(ROOT_DIR)/stackit && (go test -timeout 0 ./... -count=1 -coverprofile=../coverage.out || true) && cd $(ROOT_DIR)
|
||||
@cd $(ROOT_DIR)/stackit && go tool cover -html=../coverage.out -o ../coverage.html && cd $(ROOT_DIR)
|
||||
|
||||
test-acceptance-tf:
|
||||
@if [ -z $(TF_ACC_PROJECT_ID) ]; then echo "Input TF_ACC_PROJECT_ID missing"; exit 1; fi
|
||||
|
|
|
|||
133
README.md
133
README.md
|
|
@ -1,15 +1,14 @@
|
|||
<div align="center">
|
||||
<br>
|
||||
<img src=".github/images/stackit-logo.svg" alt="STACKIT logo" width="50%"/>
|
||||
<br>
|
||||
<br>
|
||||
</div>
|
||||
|
||||
# STACKIT Terraform Provider (PRIVATE PREVIEW)
|
||||
# STACKIT Terraform Provider <br />(PRIVATE PREVIEW)
|
||||
|
||||
[](https://registry.terraform.io/providers/stackitcloud/stackit/latest)  [](https://www.apache.org/licenses/LICENSE-2.0)
|
||||
|
||||
This project is the official [Terraform Provider](https://registry.terraform.io/providers/stackitcloud/stackit/latest/docs) for [STACKIT](https://www.stackit.de/en/), which allows you to manage STACKIT resources through Terraform.
|
||||
This project is the **NOT** official [Terraform Provider](https://registry.terraform.io/providers/stackitcloud/stackit/latest/docs) for [STACKIT](https://www.stackit.de/en/)!
|
||||
|
||||
This a **private preview only**, which allows you to manage STACKIT resources through Terraform.
|
||||
|
||||
## Getting Started
|
||||
|
||||
|
|
@ -18,26 +17,27 @@ To install the [STACKIT Terraform Provider](https://registry.terraform.io/provid
|
|||
```hcl
|
||||
terraform {
|
||||
required_providers {
|
||||
stackit = {
|
||||
source = "stackitcloud/stackit"
|
||||
version = "X.X.X"
|
||||
stackitprivatepreview = {
|
||||
source = "tfregistry.sysops.stackit.rocks/mhenselin/stackitprivatepreview"
|
||||
version = ">= 0.1.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
provider "stackit" {
|
||||
provider "stackitprivatepreview" {
|
||||
# Configuration options
|
||||
}
|
||||
```
|
||||
|
||||
Check one of the examples in the [examples](examples/) folder.
|
||||
|
||||
<big font-size="3rem">TODO: revise the following sections</big>
|
||||
|
||||
## Authentication
|
||||
|
||||
To authenticate, you will need a [service account](https://docs.stackit.cloud/platform/access-and-identity/service-accounts/). Create it in the [STACKIT Portal](https://portal.stackit.cloud/) and assign the necessary permissions to it, e.g. `project.owner`. There are multiple ways to authenticate:
|
||||
|
||||
- Key flow (recommended)
|
||||
- Token flow (is scheduled for deprecation and will be removed on December 17, 2025.)
|
||||
|
||||
When setting up authentication, the provider will always try to use the key flow first and search for credentials in several locations, following a specific order:
|
||||
|
||||
|
|
@ -51,7 +51,6 @@ When setting up authentication, the provider will always try to use the key flow
|
|||
|
||||
```json
|
||||
{
|
||||
"STACKIT_SERVICE_ACCOUNT_TOKEN": "foo_token",
|
||||
"STACKIT_SERVICE_ACCOUNT_KEY_PATH": "path/to/sa_key.json"
|
||||
}
|
||||
```
|
||||
|
|
@ -70,35 +69,41 @@ To configure the key flow, follow this steps:
|
|||
|
||||
1. Create a service account key:
|
||||
|
||||
- Use the [STACKIT Portal](https://portal.stackit.cloud/): go to the `Service Accounts` tab, choose a `Service Account` and go to `Service Account Keys` to create a key. For more details, see [Create a service account key](https://docs.stackit.cloud/platform/access-and-identity/service-accounts/how-tos/manage-service-account-keys/)
|
||||
- Use the [STACKIT Portal](https://portal.stackit.cloud/): go to the `Service Accounts` tab, choose a `Service Account` and go to `Service Account Keys` to create a key. For more details, see [Create a service account key](https://docs.stackit.cloud/platform/access-and-identity/service-accounts/how-tos/manage-service-account-keys/)
|
||||
|
||||
2. Save the content of the service account key by copying it and saving it in a JSON file.
|
||||
|
||||
The expected format of the service account key is a **JSON** with the following structure:
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "uuid",
|
||||
"publicKey": "public key",
|
||||
"createdAt": "2023-08-24T14:15:22Z",
|
||||
"validUntil": "2023-08-24T14:15:22Z",
|
||||
"keyType": "USER_MANAGED",
|
||||
"keyOrigin": "USER_PROVIDED",
|
||||
"keyAlgorithm": "RSA_2048",
|
||||
"active": true,
|
||||
"credentials": {
|
||||
"kid": "string",
|
||||
"iss": "my-sa@sa.stackit.cloud",
|
||||
"sub": "uuid",
|
||||
"aud": "string",
|
||||
(optional) "privateKey": "private key when generated by the SA service"
|
||||
}
|
||||
}
|
||||
```
|
||||
```json
|
||||
{
|
||||
"id": "uuid",
|
||||
"publicKey": "public key",
|
||||
"createdAt": "2023-08-24T14:15:22Z",
|
||||
"validUntil": "2023-08-24T14:15:22Z",
|
||||
"keyType": "USER_MANAGED",
|
||||
"keyOrigin": "USER_PROVIDED",
|
||||
"keyAlgorithm": "RSA_2048",
|
||||
"active": true,
|
||||
"credentials": {
|
||||
"kid": "string",
|
||||
"iss": "my-sa@sa.stackit.cloud",
|
||||
"sub": "uuid",
|
||||
"aud": "string",
|
||||
(optional) "privateKey": "private key when generated by the SA service"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
3. Configure the service account key for authentication in the provider by following one of the alternatives below:
|
||||
|
||||
- setting the fields in the provider block: `service_account_key` or `service_account_key_path`
|
||||
```hcl
|
||||
provider "stackitprivatepreview" {
|
||||
default_region = "eu01"
|
||||
service_account_key_path = "../service_account.json"
|
||||
}
|
||||
```
|
||||
- setting the environment variable: `STACKIT_SERVICE_ACCOUNT_KEY_PATH` or `STACKIT_SERVICE_ACCOUNT_KEY`
|
||||
- ensure the set the service account key in `STACKIT_SERVICE_ACCOUNT_KEY` is correctly formatted. Use e.g.
|
||||
`$ export STACKIT_SERVICE_ACCOUNT_KEY=$(cat ./service-account-key.json)`
|
||||
|
|
@ -110,16 +115,6 @@ To configure the key flow, follow this steps:
|
|||
> - setting the environment variable: `STACKIT_PRIVATE_KEY_PATH` or `STACKIT_PRIVATE_KEY`
|
||||
> - setting `STACKIT_PRIVATE_KEY_PATH` in the credentials file (see above)
|
||||
|
||||
### Token flow
|
||||
|
||||
> Is scheduled for deprecation and will be removed on December 17, 2025.
|
||||
|
||||
Using this flow is less secure since the token is long-lived. You can provide the token in several ways:
|
||||
|
||||
1. Setting the field `service_account_token` in the provider
|
||||
2. Setting the environment variable `STACKIT_SERVICE_ACCOUNT_TOKEN`
|
||||
3. Setting it in the credentials file (see above)
|
||||
|
||||
## Backend configuration
|
||||
|
||||
To keep track of your terraform state, you can configure an [S3 backend](https://developer.hashicorp.com/terraform/language/settings/backends/s3) using [STACKIT Object Storage](https://docs.stackit.cloud/products/storage/object-storage).
|
||||
|
|
@ -149,62 +144,6 @@ terraform {
|
|||
|
||||
Note: AWS specific checks must be skipped as they do not work on STACKIT. For details on what those validations do, see [here](https://developer.hashicorp.com/terraform/language/settings/backends/s3#configuration).
|
||||
|
||||
## Opting into Beta Resources
|
||||
|
||||
To use beta resources in the STACKIT Terraform provider, follow these steps:
|
||||
|
||||
1. **Provider Configuration Option**
|
||||
|
||||
Set the `enable_beta_resources` option in the provider configuration. This is a boolean attribute that can be either `true` or `false`.
|
||||
|
||||
```hcl
|
||||
provider "stackit" {
|
||||
default_region = "eu01"
|
||||
enable_beta_resources = true
|
||||
}
|
||||
```
|
||||
|
||||
2. **Environment Variable**
|
||||
|
||||
Set the `STACKIT_TF_ENABLE_BETA_RESOURCES` environment variable to `"true"` or `"false"`. Other values will be ignored and will produce a warning.
|
||||
|
||||
```sh
|
||||
export STACKIT_TF_ENABLE_BETA_RESOURCES=true
|
||||
```
|
||||
|
||||
> **Note**: The environment variable takes precedence over the provider configuration option. This means that if the `STACKIT_TF_ENABLE_BETA_RESOURCES` environment variable is set to a valid value (`"true"` or `"false"`), it will override the `enable_beta_resources` option specified in the provider configuration.
|
||||
|
||||
For more details, please refer to the [beta resources configuration guide](https://registry.terraform.io/providers/stackitcloud/stackit/latest/docs/guides/opting_into_beta_resources).
|
||||
|
||||
## Opting into Experiments
|
||||
|
||||
Experiments are features that are even less mature and stable than Beta Resources. While there is some assumed stability in beta resources, will have to expect breaking changes while using experimental resources. Experimental Resources do not come with any support or warranty.
|
||||
|
||||
To enable experiments set the experiments field in the provider definition:
|
||||
|
||||
```hcl
|
||||
provider "stackit" {
|
||||
default_region = "eu01"
|
||||
experiments = ["iam", "routing-tables", "network"]
|
||||
}
|
||||
```
|
||||
|
||||
### Available Experiments
|
||||
|
||||
#### `iam`
|
||||
|
||||
Enables IAM management features in the Terraform provider. The underlying IAM API is expected to undergo a redesign in the future, which leads to it being considered experimental.
|
||||
|
||||
#### `routing-tables`
|
||||
|
||||
This feature enables experimental routing table capabilities in the Terraform Provider, available only to designated SNAs at this time.
|
||||
|
||||
#### `network`
|
||||
|
||||
The `stackit_network` provides the fields `region` and `routing_table_id` when the experiment flag `network` is set.
|
||||
The underlying API is not stable yet and could change in the future.
|
||||
If you don't need these fields, don't set the experiment flag `network`, to use the stable api.
|
||||
|
||||
## Acceptance Tests
|
||||
|
||||
> [!WARNING]
|
||||
|
|
|
|||
|
|
@ -1,958 +0,0 @@
|
|||
package build
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"go/ast"
|
||||
"go/parser"
|
||||
"go/token"
|
||||
"io"
|
||||
"log"
|
||||
"log/slog"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"text/template"
|
||||
|
||||
"github.com/ldez/go-git-cmd-wrapper/v2/clone"
|
||||
"github.com/ldez/go-git-cmd-wrapper/v2/git"
|
||||
)
|
||||
|
||||
const (
|
||||
OAS_REPO_NAME = "stackit-api-specifications"
|
||||
OAS_REPO = "https://github.com/stackitcloud/stackit-api-specifications.git"
|
||||
GEN_REPO_NAME = "stackit-sdk-generator"
|
||||
GEN_REPO = "https://github.com/stackitcloud/stackit-sdk-generator.git"
|
||||
)
|
||||
|
||||
var supportedVersions = []string{"alpha", "beta"}
|
||||
|
||||
type version struct {
|
||||
verString string
|
||||
major int
|
||||
minor int
|
||||
}
|
||||
|
||||
type Builder struct {
|
||||
SkipClone bool
|
||||
SkipCleanup bool
|
||||
PackagesOnly bool
|
||||
}
|
||||
|
||||
func (b *Builder) Build() error {
|
||||
slog.Info("Starting Builder")
|
||||
if b.PackagesOnly {
|
||||
slog.Info(" >>> only generating pkg_gen <<<")
|
||||
}
|
||||
|
||||
root, err := getRoot()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
if root == nil || *root == "" {
|
||||
return fmt.Errorf("unable to determine root directory from git")
|
||||
}
|
||||
slog.Info(" ... using root directory", "dir", *root)
|
||||
|
||||
if !b.PackagesOnly {
|
||||
slog.Info(" ... Checking needed commands available")
|
||||
err := checkCommands([]string{"tfplugingen-framework", "tfplugingen-openapi"})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if !b.SkipCleanup {
|
||||
slog.Info("Cleaning up old packages directory")
|
||||
err = os.RemoveAll(path.Join(*root, "pkg_gen"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if !b.SkipCleanup && !b.PackagesOnly {
|
||||
slog.Info("Cleaning up old packages directory")
|
||||
err = os.RemoveAll(path.Join(*root, "pkg_gen"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
slog.Info("Creating generator dir", "dir", fmt.Sprintf("%s/%s", *root, GEN_REPO_NAME))
|
||||
genDir := path.Join(*root, GEN_REPO_NAME)
|
||||
if !b.SkipClone {
|
||||
err = createGeneratorDir(GEN_REPO, genDir, b.SkipClone)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
slog.Info("Creating oas repo dir", "dir", fmt.Sprintf("%s/%s", *root, OAS_REPO_NAME))
|
||||
repoDir, err := createRepoDir(genDir, OAS_REPO, OAS_REPO_NAME, b.SkipClone)
|
||||
if err != nil {
|
||||
return fmt.Errorf("%s", err.Error())
|
||||
}
|
||||
|
||||
slog.Info("Retrieving versions from subdirs")
|
||||
// TODO - major
|
||||
verMap, err := getVersions(repoDir)
|
||||
if err != nil {
|
||||
return fmt.Errorf("%s", err.Error())
|
||||
}
|
||||
|
||||
slog.Info("Reducing to only latest or highest")
|
||||
res, err := getOnlyLatest(verMap)
|
||||
if err != nil {
|
||||
return fmt.Errorf("%s", err.Error())
|
||||
}
|
||||
|
||||
slog.Info("Creating OAS dir")
|
||||
err = os.MkdirAll(path.Join(genDir, "oas"), 0755)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
slog.Info("Copying OAS files")
|
||||
for service, item := range res {
|
||||
baseService := strings.TrimSuffix(service, "alpha")
|
||||
baseService = strings.TrimSuffix(baseService, "beta")
|
||||
itemVersion := fmt.Sprintf("v%d%s", item.major, item.verString)
|
||||
if item.minor != 0 {
|
||||
itemVersion = itemVersion + "" + strconv.Itoa(item.minor)
|
||||
}
|
||||
srcFile := path.Join(
|
||||
repoDir,
|
||||
"services",
|
||||
baseService,
|
||||
itemVersion,
|
||||
fmt.Sprintf("%s.json", baseService),
|
||||
)
|
||||
dstFile := path.Join(genDir, "oas", fmt.Sprintf("%s.json", service))
|
||||
_, err = copyFile(srcFile, dstFile)
|
||||
if err != nil {
|
||||
return fmt.Errorf("%s", err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
slog.Info("Changing dir", "dir", genDir)
|
||||
err = os.Chdir(genDir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
slog.Info("Calling make", "command", "generate-go-sdk")
|
||||
cmd := exec.Command("make", "generate-go-sdk")
|
||||
var stdOut, stdErr bytes.Buffer
|
||||
cmd.Stdout = &stdOut
|
||||
cmd.Stderr = &stdErr
|
||||
|
||||
if err = cmd.Start(); err != nil {
|
||||
slog.Error("cmd.Start", "error", err)
|
||||
return err
|
||||
}
|
||||
|
||||
if err = cmd.Wait(); err != nil {
|
||||
var exitErr *exec.ExitError
|
||||
if errors.As(err, &exitErr) {
|
||||
slog.Error("cmd.Wait", "code", exitErr.ExitCode(), "error", err, "stdout", stdOut.String(), "stderr", stdErr.String())
|
||||
return fmt.Errorf("%s", stdErr.String())
|
||||
}
|
||||
if err != nil {
|
||||
slog.Error("cmd.Wait", "err", err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
slog.Info("Cleaning up go.mod and go.sum files")
|
||||
cleanDir := path.Join(genDir, "sdk-repo-updated", "services")
|
||||
dirEntries, err := os.ReadDir(cleanDir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, entry := range dirEntries {
|
||||
if entry.IsDir() {
|
||||
err = deleteFiles(
|
||||
path.Join(cleanDir, entry.Name(), "go.mod"),
|
||||
path.Join(cleanDir, entry.Name(), "go.sum"),
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
slog.Info("Changing dir", "dir", *root)
|
||||
err = os.Chdir(*root)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
slog.Info("Rearranging package directories")
|
||||
err = os.MkdirAll(path.Join(*root, "pkg_gen"), 0755) // noqa:gosec
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
srcDir := path.Join(genDir, "sdk-repo-updated", "services")
|
||||
items, err := os.ReadDir(srcDir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, item := range items {
|
||||
if item.IsDir() {
|
||||
slog.Info(" -> package", "name", item.Name())
|
||||
tgtDir := path.Join(*root, "pkg_gen", item.Name())
|
||||
if fileExists(tgtDir) {
|
||||
delErr := os.RemoveAll(tgtDir)
|
||||
if delErr != nil {
|
||||
return delErr
|
||||
}
|
||||
}
|
||||
err = os.Rename(path.Join(srcDir, item.Name()), tgtDir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !b.PackagesOnly {
|
||||
slog.Info("Generating service boilerplate")
|
||||
err = generateServiceFiles(*root, path.Join(*root, GEN_REPO_NAME))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
slog.Info("Copying all service files")
|
||||
err = CopyDirectory(
|
||||
path.Join(*root, "generated", "internal", "services"),
|
||||
path.Join(*root, "stackit", "internal", "services"),
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = createBoilerplate(*root, path.Join(*root, "stackit", "internal", "services"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if !b.SkipCleanup {
|
||||
slog.Info("Finally removing temporary files and directories")
|
||||
err = os.RemoveAll(path.Join(*root, "generated"))
|
||||
if err != nil {
|
||||
slog.Error("RemoveAll", "dir", path.Join(*root, "generated"), "err", err)
|
||||
return err
|
||||
}
|
||||
|
||||
err = os.RemoveAll(path.Join(*root, GEN_REPO_NAME))
|
||||
if err != nil {
|
||||
slog.Error("RemoveAll", "dir", path.Join(*root, GEN_REPO_NAME), "err", err)
|
||||
return err
|
||||
}
|
||||
|
||||
slog.Info("Cleaning up", "dir", repoDir)
|
||||
err = os.RemoveAll(filepath.Dir(repoDir))
|
||||
if err != nil {
|
||||
return fmt.Errorf("%s", err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
slog.Info("Done")
|
||||
return nil
|
||||
}
|
||||
|
||||
type templateData struct {
|
||||
PackageName string
|
||||
PackageNameCamel string
|
||||
PackageNamePascal string
|
||||
NameCamel string
|
||||
NamePascal string
|
||||
NameSnake string
|
||||
Fields []string
|
||||
}
|
||||
|
||||
func fileExists(path string) bool {
|
||||
_, err := os.Stat(path)
|
||||
if os.IsNotExist(err) {
|
||||
return false
|
||||
}
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func createBoilerplate(rootFolder, folder string) error {
|
||||
services, err := os.ReadDir(folder)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, svc := range services {
|
||||
if !svc.IsDir() {
|
||||
continue
|
||||
}
|
||||
resources, err := os.ReadDir(path.Join(folder, svc.Name()))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var handleDS bool
|
||||
var handleRes bool
|
||||
var foundDS bool
|
||||
var foundRes bool
|
||||
|
||||
for _, res := range resources {
|
||||
if !res.IsDir() {
|
||||
continue
|
||||
}
|
||||
|
||||
resourceName := res.Name()
|
||||
|
||||
dsFile := path.Join(folder, svc.Name(), res.Name(), "datasources_gen", fmt.Sprintf("%s_data_source_gen.go", res.Name()))
|
||||
handleDS = fileExists(dsFile)
|
||||
|
||||
resFile := path.Join(folder, svc.Name(), res.Name(), "resources_gen", fmt.Sprintf("%s_resource_gen.go", res.Name()))
|
||||
handleRes = fileExists(resFile)
|
||||
|
||||
dsGoFile := path.Join(folder, svc.Name(), res.Name(), "datasource.go")
|
||||
foundDS = fileExists(dsGoFile)
|
||||
|
||||
resGoFile := path.Join(folder, svc.Name(), res.Name(), "resource.go")
|
||||
foundRes = fileExists(resGoFile)
|
||||
|
||||
if handleDS && !foundDS {
|
||||
slog.Info(" creating missing datasource.go", "service", svc.Name(), "resource", resourceName)
|
||||
if !ValidateSnakeCase(resourceName) {
|
||||
return errors.New("resource name is invalid")
|
||||
}
|
||||
|
||||
fields, tokenErr := getTokens(dsFile)
|
||||
if tokenErr != nil {
|
||||
return fmt.Errorf("error reading tokens: %w", tokenErr)
|
||||
}
|
||||
|
||||
tplName := "data_source_scaffold.gotmpl"
|
||||
err = writeTemplateToFile(
|
||||
tplName,
|
||||
path.Join(rootFolder, "cmd", "cmd", "build", "templates", tplName),
|
||||
dsGoFile,
|
||||
&templateData{
|
||||
PackageName: svc.Name(),
|
||||
PackageNameCamel: ToCamelCase(svc.Name()),
|
||||
PackageNamePascal: ToPascalCase(svc.Name()),
|
||||
NameCamel: ToCamelCase(resourceName),
|
||||
NamePascal: ToPascalCase(resourceName),
|
||||
NameSnake: resourceName,
|
||||
Fields: fields,
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
if handleRes && !foundRes {
|
||||
slog.Info(" creating missing resource.go", "service", svc.Name(), "resource", resourceName)
|
||||
if !ValidateSnakeCase(resourceName) {
|
||||
return errors.New("resource name is invalid")
|
||||
}
|
||||
|
||||
fields, tokenErr := getTokens(resFile)
|
||||
if tokenErr != nil {
|
||||
return fmt.Errorf("error reading tokens: %w", tokenErr)
|
||||
}
|
||||
|
||||
tplName := "resource_scaffold.gotmpl"
|
||||
err = writeTemplateToFile(
|
||||
tplName,
|
||||
path.Join(rootFolder, "cmd", "cmd", "build", "templates", tplName),
|
||||
resGoFile,
|
||||
&templateData{
|
||||
PackageName: svc.Name(),
|
||||
PackageNameCamel: ToCamelCase(svc.Name()),
|
||||
PackageNamePascal: ToPascalCase(svc.Name()),
|
||||
NameCamel: ToCamelCase(resourceName),
|
||||
NamePascal: ToPascalCase(resourceName),
|
||||
NameSnake: resourceName,
|
||||
Fields: fields,
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !fileExists(path.Join(folder, svc.Name(), res.Name(), "functions.go")) {
|
||||
slog.Info(" creating missing functions.go", "service", svc.Name(), "resource", resourceName)
|
||||
if !ValidateSnakeCase(resourceName) {
|
||||
return errors.New("resource name is invalid")
|
||||
}
|
||||
fncTplName := "functions_scaffold.gotmpl"
|
||||
err = writeTemplateToFile(
|
||||
fncTplName,
|
||||
path.Join(rootFolder, "cmd", "cmd", "build", "templates", fncTplName),
|
||||
path.Join(folder, svc.Name(), res.Name(), "functions.go"),
|
||||
&templateData{
|
||||
PackageName: svc.Name(),
|
||||
PackageNameCamel: ToCamelCase(svc.Name()),
|
||||
PackageNamePascal: ToPascalCase(svc.Name()),
|
||||
NameCamel: ToCamelCase(resourceName),
|
||||
NamePascal: ToPascalCase(resourceName),
|
||||
NameSnake: resourceName,
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func ucfirst(s string) string {
|
||||
if len(s) == 0 {
|
||||
return ""
|
||||
}
|
||||
return strings.ToUpper(s[:1]) + s[1:]
|
||||
}
|
||||
|
||||
func writeTemplateToFile(tplName, tplFile, outFile string, data *templateData) error {
|
||||
fn := template.FuncMap{
|
||||
"ucfirst": ucfirst,
|
||||
}
|
||||
|
||||
tmpl, err := template.New(tplName).Funcs(fn).ParseFiles(tplFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var f *os.File
|
||||
f, err = os.Create(outFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = tmpl.Execute(f, *data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = f.Close()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func generateServiceFiles(rootDir, generatorDir string) error {
|
||||
// slog.Info("Generating specs folder")
|
||||
err := os.MkdirAll(path.Join(rootDir, "generated", "specs"), 0755)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
services, err := os.ReadDir(path.Join(rootDir, "service_specs"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, service := range services {
|
||||
if !service.IsDir() {
|
||||
continue
|
||||
}
|
||||
|
||||
versions, err := os.ReadDir(path.Join(rootDir, "service_specs", service.Name()))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, svcVersion := range versions {
|
||||
if !svcVersion.IsDir() {
|
||||
continue
|
||||
}
|
||||
|
||||
// TODO: use const of supported versions
|
||||
if svcVersion.Name() != "alpha" && svcVersion.Name() != "beta" {
|
||||
continue
|
||||
}
|
||||
|
||||
specFiles, err := os.ReadDir(path.Join(rootDir, "service_specs", service.Name(), svcVersion.Name()))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, specFile := range specFiles {
|
||||
if specFile.IsDir() {
|
||||
continue
|
||||
}
|
||||
|
||||
// slog.Info("Checking spec", "name", spec.Name())
|
||||
r := regexp.MustCompile(`^(.*)_config.yml$`)
|
||||
matches := r.FindAllStringSubmatch(specFile.Name(), -1)
|
||||
if matches != nil {
|
||||
fileName := matches[0][0]
|
||||
resource := matches[0][1]
|
||||
slog.Info(
|
||||
" found service spec",
|
||||
"name",
|
||||
specFile.Name(),
|
||||
"service",
|
||||
service.Name(),
|
||||
"resource",
|
||||
resource,
|
||||
)
|
||||
|
||||
oasFile := path.Join(generatorDir, "oas", fmt.Sprintf("%s%s.json", service.Name(), svcVersion.Name()))
|
||||
if _, oasErr := os.Stat(oasFile); os.IsNotExist(oasErr) {
|
||||
slog.Warn(" could not find matching oas", "svc", service.Name(), "version", svcVersion.Name())
|
||||
continue
|
||||
}
|
||||
|
||||
scName := fmt.Sprintf("%s%s", service.Name(), svcVersion.Name())
|
||||
scName = strings.ReplaceAll(scName, "-", "")
|
||||
err = os.MkdirAll(path.Join(rootDir, "generated", "internal", "services", scName, resource), 0755)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// slog.Info("Generating openapi spec json")
|
||||
specJsonFile := path.Join(rootDir, "generated", "specs", fmt.Sprintf("%s_%s_spec.json", scName, resource))
|
||||
|
||||
var stdOut, stdErr bytes.Buffer
|
||||
|
||||
// noqa:gosec
|
||||
cmd := exec.Command(
|
||||
"tfplugingen-openapi",
|
||||
"generate",
|
||||
"--config",
|
||||
path.Join(rootDir, "service_specs", service.Name(), svcVersion.Name(), fileName),
|
||||
"--output",
|
||||
specJsonFile,
|
||||
oasFile,
|
||||
)
|
||||
cmd.Stdout = &stdOut
|
||||
cmd.Stderr = &stdErr
|
||||
|
||||
if err = cmd.Start(); err != nil {
|
||||
slog.Error(
|
||||
"tfplugingen-openapi generate",
|
||||
"error",
|
||||
err,
|
||||
"stdOut",
|
||||
stdOut.String(),
|
||||
"stdErr",
|
||||
stdErr.String(),
|
||||
)
|
||||
return err
|
||||
}
|
||||
|
||||
if err = cmd.Wait(); err != nil {
|
||||
var exitErr *exec.ExitError
|
||||
if errors.As(err, &exitErr) {
|
||||
slog.Error("tfplugingen-openapi generate", "code", exitErr.ExitCode(), "error", err, "stdout", stdOut.String(), "stderr", stdErr.String())
|
||||
return fmt.Errorf("%s", stdErr.String())
|
||||
}
|
||||
if err != nil {
|
||||
slog.Error("tfplugingen-openapi generate", "err", err, "stdout", stdOut.String(), "stderr", stdErr.String())
|
||||
return err
|
||||
}
|
||||
}
|
||||
if stdOut.Len() > 0 {
|
||||
slog.Warn(" command output", "stdout", stdOut.String(), "stderr", stdErr.String())
|
||||
}
|
||||
|
||||
// slog.Info("Creating terraform svc resource files folder")
|
||||
tgtFolder := path.Join(rootDir, "generated", "internal", "services", scName, resource, "resources_gen")
|
||||
err = os.MkdirAll(tgtFolder, 0755)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// slog.Info("Generating terraform svc resource files")
|
||||
|
||||
// noqa:gosec
|
||||
cmd2 := exec.Command(
|
||||
"tfplugingen-framework",
|
||||
"generate",
|
||||
"resources",
|
||||
"--input",
|
||||
specJsonFile,
|
||||
"--output",
|
||||
tgtFolder,
|
||||
"--package",
|
||||
scName,
|
||||
)
|
||||
|
||||
cmd2.Stdout = &stdOut
|
||||
cmd2.Stderr = &stdErr
|
||||
if err = cmd2.Start(); err != nil {
|
||||
slog.Error("tfplugingen-framework generate resources", "error", err)
|
||||
return err
|
||||
}
|
||||
|
||||
if err = cmd2.Wait(); err != nil {
|
||||
var exitErr *exec.ExitError
|
||||
if errors.As(err, &exitErr) {
|
||||
slog.Error("tfplugingen-framework generate resources", "code", exitErr.ExitCode(), "error", err, "stdout", stdOut.String(), "stderr", stdErr.String())
|
||||
return fmt.Errorf("%s", stdErr.String())
|
||||
}
|
||||
if err != nil {
|
||||
slog.Error("tfplugingen-framework generate resources", "err", err, "stdout", stdOut.String(), "stderr", stdErr.String())
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// slog.Info("Creating terraform svc datasource files folder")
|
||||
tgtFolder = path.Join(rootDir, "generated", "internal", "services", scName, resource, "datasources_gen")
|
||||
err = os.MkdirAll(tgtFolder, 0755)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// slog.Info("Generating terraform svc resource files")
|
||||
|
||||
// noqa:gosec
|
||||
cmd3 := exec.Command(
|
||||
"tfplugingen-framework",
|
||||
"generate",
|
||||
"data-sources",
|
||||
"--input",
|
||||
specJsonFile,
|
||||
"--output",
|
||||
tgtFolder,
|
||||
"--package",
|
||||
scName,
|
||||
)
|
||||
var stdOut3, stdErr3 bytes.Buffer
|
||||
cmd3.Stdout = &stdOut3
|
||||
cmd3.Stderr = &stdErr3
|
||||
|
||||
if err = cmd3.Start(); err != nil {
|
||||
slog.Error("tfplugingen-framework generate data-sources", "error", err)
|
||||
return err
|
||||
}
|
||||
|
||||
if err = cmd3.Wait(); err != nil {
|
||||
var exitErr *exec.ExitError
|
||||
if errors.As(err, &exitErr) {
|
||||
slog.Error("tfplugingen-framework generate data-sources", "code", exitErr.ExitCode(), "error", err, "stdout", stdOut.String(), "stderr", stdErr.String())
|
||||
return fmt.Errorf("%s", stdErr.String())
|
||||
}
|
||||
if err != nil {
|
||||
slog.Error("tfplugingen-framework generate data-sources", "err", err, "stdout", stdOut.String(), "stderr", stdErr.String())
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
tfAnoErr := handleTfTagForDatasourceFile(
|
||||
path.Join(tgtFolder, fmt.Sprintf("%s_data_source_gen.go", resource)),
|
||||
scName,
|
||||
resource,
|
||||
)
|
||||
if tfAnoErr != nil {
|
||||
return tfAnoErr
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// handleTfTagForDatasourceFile replaces existing "id" with "stf_original_api_id"
|
||||
func handleTfTagForDatasourceFile(filePath, service, resource string) error {
|
||||
slog.Info(" handle terraform tag for datasource", "service", service, "resource", resource)
|
||||
if !fileExists(filePath) {
|
||||
slog.Warn(" could not find file, skipping", "path", filePath)
|
||||
return nil
|
||||
}
|
||||
f, err := os.Open(filePath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
root, err := getRoot()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
tmp, err := os.CreateTemp(*root, "replace-*")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer tmp.Close()
|
||||
|
||||
sc := bufio.NewScanner(f)
|
||||
for sc.Scan() {
|
||||
resLine, err := handleLine(sc.Text())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := io.WriteString(tmp, resLine+"\n"); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if scErr := sc.Err(); scErr != nil {
|
||||
return scErr
|
||||
}
|
||||
|
||||
if err := tmp.Close(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := f.Close(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := os.Rename(tmp.Name(), filePath); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func handleLine(line string) (string, error) {
|
||||
schemaRegex := regexp.MustCompile(`(\s+")(id)(": schema.[a-zA-Z0-9]+Attribute{)`)
|
||||
|
||||
schemaMatches := schemaRegex.FindAllStringSubmatch(line, -1)
|
||||
if schemaMatches != nil {
|
||||
return fmt.Sprintf("%stf_original_api_id%s", schemaMatches[0][1], schemaMatches[0][3]), nil
|
||||
}
|
||||
|
||||
modelRegex := regexp.MustCompile(`(\s+Id\s+types.[a-zA-Z0-9]+\s+.tfsdk:")(id)(".)`)
|
||||
modelMatches := modelRegex.FindAllStringSubmatch(line, -1)
|
||||
if modelMatches != nil {
|
||||
return fmt.Sprintf("%stf_original_api_id%s", modelMatches[0][1], modelMatches[0][3]), nil
|
||||
}
|
||||
|
||||
return line, nil
|
||||
}
|
||||
|
||||
func checkCommands(commands []string) error {
|
||||
for _, commandName := range commands {
|
||||
if !commandExists(commandName) {
|
||||
return fmt.Errorf("missing command %s", commandName)
|
||||
}
|
||||
slog.Info(" found", "command", commandName)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func commandExists(cmd string) bool {
|
||||
_, err := exec.LookPath(cmd)
|
||||
return err == nil
|
||||
}
|
||||
|
||||
func deleteFiles(fNames ...string) error {
|
||||
for _, fName := range fNames {
|
||||
if _, err := os.Stat(fName); !os.IsNotExist(err) {
|
||||
err = os.Remove(fName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func copyFile(src, dst string) (int64, error) {
|
||||
sourceFileStat, err := os.Stat(src)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
if !sourceFileStat.Mode().IsRegular() {
|
||||
return 0, fmt.Errorf("%s is not a regular file", src)
|
||||
}
|
||||
|
||||
source, err := os.Open(src)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
defer source.Close()
|
||||
|
||||
destination, err := os.Create(dst)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
defer destination.Close()
|
||||
nBytes, err := io.Copy(destination, source)
|
||||
return nBytes, err
|
||||
}
|
||||
|
||||
func getOnlyLatest(m map[string]version) (map[string]version, error) {
|
||||
tmpMap := make(map[string]version)
|
||||
for k, v := range m {
|
||||
item, ok := tmpMap[k]
|
||||
if !ok {
|
||||
tmpMap[k] = v
|
||||
} else {
|
||||
if item.major == v.major && item.minor < v.minor {
|
||||
tmpMap[k] = v
|
||||
}
|
||||
}
|
||||
}
|
||||
return tmpMap, nil
|
||||
}
|
||||
|
||||
func getVersions(dir string) (map[string]version, error) {
|
||||
res := make(map[string]version)
|
||||
children, err := os.ReadDir(path.Join(dir, "services"))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, entry := range children {
|
||||
if entry.IsDir() {
|
||||
versions, err := os.ReadDir(path.Join(dir, "services", entry.Name()))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
m, err2 := extractVersions(entry.Name(), versions)
|
||||
if err2 != nil {
|
||||
return m, err2
|
||||
}
|
||||
for k, v := range m {
|
||||
res[k] = v
|
||||
}
|
||||
}
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func extractVersions(service string, versionDirs []os.DirEntry) (map[string]version, error) {
|
||||
res := make(map[string]version)
|
||||
for _, vDir := range versionDirs {
|
||||
if vDir.IsDir() {
|
||||
r := regexp.MustCompile(`v([0-9]+)([a-z]+)([0-9]*)`)
|
||||
matches := r.FindAllStringSubmatch(vDir.Name(), -1)
|
||||
if matches == nil {
|
||||
continue
|
||||
}
|
||||
svc, ver, err := handleVersion(service, matches[0])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if svc != nil && ver != nil {
|
||||
res[*svc] = *ver
|
||||
}
|
||||
}
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func handleVersion(service string, match []string) (*string, *version, error) {
|
||||
if match == nil {
|
||||
fmt.Println("no matches")
|
||||
return nil, nil, nil
|
||||
}
|
||||
verString := match[2]
|
||||
if verString != "alpha" && verString != "beta" {
|
||||
return nil, nil, errors.New("unsupported version")
|
||||
}
|
||||
majVer, err := strconv.Atoi(match[1])
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
if match[3] == "" {
|
||||
match[3] = "0"
|
||||
}
|
||||
minVer, err := strconv.Atoi(match[3])
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
resStr := fmt.Sprintf("%s%s", service, verString)
|
||||
return &resStr, &version{verString: verString, major: majVer, minor: minVer}, nil
|
||||
}
|
||||
|
||||
func createRepoDir(root, repoUrl, repoName string, skipClone bool) (string, error) {
|
||||
targetDir := path.Join(root, repoName)
|
||||
if !skipClone {
|
||||
if fileExists(targetDir) {
|
||||
slog.Warn("target dir exists - skipping", "targetDir", targetDir)
|
||||
return targetDir, nil
|
||||
}
|
||||
_, err := git.Clone(
|
||||
clone.Repository(repoUrl),
|
||||
clone.Directory(targetDir),
|
||||
)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
return targetDir, nil
|
||||
}
|
||||
|
||||
func createGeneratorDir(repoUrl, targetDir string, skipClone bool) error {
|
||||
if !skipClone {
|
||||
if fileExists(targetDir) {
|
||||
remErr := os.RemoveAll(targetDir)
|
||||
if remErr != nil {
|
||||
return remErr
|
||||
}
|
||||
}
|
||||
_, cloneErr := git.Clone(
|
||||
clone.Repository(repoUrl),
|
||||
clone.Directory(targetDir),
|
||||
)
|
||||
if cloneErr != nil {
|
||||
return cloneErr
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func getRoot() (*string, error) {
|
||||
cmd := exec.Command("git", "rev-parse", "--show-toplevel")
|
||||
out, err := cmd.Output()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
lines := strings.Split(string(out), "\n")
|
||||
return &lines[0], nil
|
||||
}
|
||||
|
||||
func getTokens(fileName string) ([]string, error) {
|
||||
fset := token.NewFileSet()
|
||||
|
||||
var result []string
|
||||
|
||||
node, err := parser.ParseFile(fset, fileName, nil, parser.ParseComments)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ast.Inspect(node, func(n ast.Node) bool {
|
||||
// Suche nach Typ-Deklarationen (structs)
|
||||
ts, ok := n.(*ast.TypeSpec)
|
||||
if ok {
|
||||
if strings.Contains(ts.Name.Name, "Model") {
|
||||
// fmt.Printf("found model: %s\n", ts.Name.Name)
|
||||
ast.Inspect(ts, func(sn ast.Node) bool {
|
||||
tts, tok := sn.(*ast.Field)
|
||||
if tok {
|
||||
// fmt.Printf(" found: %+v\n", tts.Names[0])
|
||||
// spew.Dump(tts.Type)
|
||||
|
||||
result = append(result, tts.Names[0].String())
|
||||
|
||||
//fld, fldOk := tts.Type.(*ast.Ident)
|
||||
//if fldOk {
|
||||
// fmt.Printf("type: %+v\n", fld)
|
||||
//}
|
||||
}
|
||||
return true
|
||||
})
|
||||
}
|
||||
}
|
||||
return true
|
||||
})
|
||||
return result, nil
|
||||
}
|
||||
|
|
@ -28,6 +28,9 @@ data "stackitprivatepreview_postgresflexalpha_database" "example" {
|
|||
- `database_id` (Number) The ID of the database.
|
||||
- `instance_id` (String) The ID of the instance.
|
||||
- `project_id` (String) The STACKIT project ID.
|
||||
|
||||
### Optional
|
||||
|
||||
- `region` (String) The region which should be addressed
|
||||
|
||||
### Read-Only
|
||||
|
|
|
|||
|
|
@ -26,17 +26,21 @@ data "stackitprivatepreview_postgresflexalpha_instance" "example" {
|
|||
|
||||
- `instance_id` (String) The ID of the instance.
|
||||
- `project_id` (String) The STACKIT project ID.
|
||||
|
||||
### Optional
|
||||
|
||||
- `region` (String) The region which should be addressed
|
||||
|
||||
### Read-Only
|
||||
|
||||
- `acl` (List of String) List of IPV4 cidr.
|
||||
- `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.
|
||||
- `connection_info` (Attributes) The DNS name and port in the instance overview (see [below for nested schema](#nestedatt--connection_info))
|
||||
- `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.
|
||||
- `connection_info` (Attributes) The connection information of the instance (see [below for nested schema](#nestedatt--connection_info))
|
||||
- `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))
|
||||
- `flavor_id` (String) The id of the instance flavor.
|
||||
- `id` (String) internal ID
|
||||
- `is_deletable` (Boolean) Whether the instance can be deleted or not.
|
||||
- `name` (String) The name of the instance.
|
||||
- `network` (Attributes) The access configuration of the instance (see [below for nested schema](#nestedatt--network))
|
||||
|
|
@ -52,10 +56,18 @@ data "stackitprivatepreview_postgresflexalpha_instance" "example" {
|
|||
|
||||
Read-Only:
|
||||
|
||||
- `write` (Attributes) The DNS name and port in the instance overview (see [below for nested schema](#nestedatt--connection_info--write))
|
||||
|
||||
<a id="nestedatt--connection_info--write"></a>
|
||||
### Nested Schema for `connection_info.write`
|
||||
|
||||
Read-Only:
|
||||
|
||||
- `host` (String) The host of the instance.
|
||||
- `port` (Number) The port of the instance.
|
||||
|
||||
|
||||
|
||||
<a id="nestedatt--encryption"></a>
|
||||
### Nested Schema for `encryption`
|
||||
|
||||
|
|
|
|||
|
|
@ -27,12 +27,12 @@ data "stackitprivatepreview_postgresflexalpha_user" "example" {
|
|||
|
||||
- `instance_id` (String) The ID of the instance.
|
||||
- `project_id` (String) The STACKIT project ID.
|
||||
- `region` (String) The region which should be addressed
|
||||
- `user_id` (Number) The ID of the user.
|
||||
|
||||
### Optional
|
||||
|
||||
- `id` (String) Terraform's internal resource ID. It is structured as \"`project_id`,`region`,`instance_id`,`user_id`\".",
|
||||
- `region` (String) The region which should be addressed
|
||||
|
||||
### Read-Only
|
||||
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ description: |-
|
|||
|
||||
- `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) Terraform's internal resource ID. It is structured as \"`project_id`,`region`,`instance_id`,`database_id`\".",
|
||||
- `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.
|
||||
|
|
|
|||
|
|
@ -1,54 +0,0 @@
|
|||
---
|
||||
# generated by https://github.com/hashicorp/terraform-plugin-docs
|
||||
page_title: "stackitprivatepreview_sqlserverflexalpha_flavor Data Source - stackitprivatepreview"
|
||||
subcategory: ""
|
||||
description: |-
|
||||
|
||||
---
|
||||
|
||||
# stackitprivatepreview_sqlserverflexalpha_flavor (Data Source)
|
||||
|
||||
|
||||
|
||||
## Example Usage
|
||||
|
||||
```terraform
|
||||
data "stackitprivatepreview_sqlserverflexalpha_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 replica
|
||||
- `project_id` (String) The cpu count of the instance.
|
||||
- `ram` (Number) The memory of the instance in Gibibyte.
|
||||
- `region` (String) The flavor description.
|
||||
- `storage_class` (String) The memory of the instance in Gibibyte.
|
||||
|
||||
### Read-Only
|
||||
|
||||
- `description` (String) The flavor description.
|
||||
- `flavor_id` (String) The flavor id of the instance flavor.
|
||||
- `id` (String) The terraform 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) (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)
|
||||
|
|
@ -34,7 +34,6 @@ data "stackitprivatepreview_sqlserverflexalpha_instance" "example" {
|
|||
- `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.
|
||||
- `id` (String) Terraform's internal resource ID. It is structured as \"`project_id`,`region`,`instance_id`\".
|
||||
- `is_deletable` (Boolean) Whether the instance can be deleted or not.
|
||||
- `name` (String) The name of the instance.
|
||||
- `network` (Attributes) The access configuration of the instance (see [below for nested schema](#nestedatt--network))
|
||||
|
|
|
|||
|
|
@ -3,12 +3,12 @@
|
|||
page_title: "stackitprivatepreview_sqlserverflexalpha_user Data Source - stackitprivatepreview"
|
||||
subcategory: ""
|
||||
description: |-
|
||||
SQLServer Flex user data source schema. Must have a region specified in the provider configuration.
|
||||
|
||||
---
|
||||
|
||||
# stackitprivatepreview_sqlserverflexalpha_user (Data Source)
|
||||
|
||||
SQLServer Flex user data source schema. Must have a `region` specified in the provider configuration.
|
||||
|
||||
|
||||
## Example Usage
|
||||
|
||||
|
|
@ -25,20 +25,38 @@ data "stackitprivatepreview_sqlserverflexalpha_user" "example" {
|
|||
|
||||
### Required
|
||||
|
||||
- `instance_id` (String) ID of the SQLServer Flex instance.
|
||||
- `project_id` (String) STACKIT project ID to which the instance is associated.
|
||||
- `user_id` (Number) User ID.
|
||||
- `instance_id` (String) The ID of the instance.
|
||||
- `project_id` (String) The STACKIT project ID.
|
||||
- `region` (String) The region which should be addressed
|
||||
|
||||
### Optional
|
||||
|
||||
- `region` (String) The resource region. If not defined, the provider region is used.
|
||||
- `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
|
||||
|
||||
- `default_database` (String)
|
||||
- `host` (String)
|
||||
- `id` (String) Terraform's internal data source. ID. It is structured as "`project_id`,`region`,`instance_id`,`user_id`".
|
||||
- `port` (Number)
|
||||
- `roles` (Set of String) Database access levels for the user.
|
||||
- `status` (String)
|
||||
- `username` (String) Username of the SQLServer Flex instance.
|
||||
- `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.
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
54
docs/data-sources/sqlserverflexbeta_user.md
Normal file
54
docs/data-sources/sqlserverflexbeta_user.md
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
---
|
||||
# generated by https://github.com/hashicorp/terraform-plugin-docs
|
||||
page_title: "stackitprivatepreview_sqlserverflexbeta_user Data Source - stackitprivatepreview"
|
||||
subcategory: ""
|
||||
description: |-
|
||||
|
||||
---
|
||||
|
||||
# stackitprivatepreview_sqlserverflexbeta_user (Data Source)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- 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.
|
||||
|
|
@ -25,6 +25,16 @@ import {
|
|||
to = stackitprivatepreview_postgresflexalpha_database.import-example
|
||||
id = "${var.project_id},${var.region},${var.postgres_instance_id},${var.postgres_database_id}"
|
||||
}
|
||||
|
||||
import {
|
||||
to = stackitprivatepreview_postgresflexalpha_database.import-example
|
||||
identity = {
|
||||
project_id = "project_id"
|
||||
region = "region"
|
||||
instance_id = "instance_id"
|
||||
database_id = "database_id"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
<!-- schema generated by tfplugindocs -->
|
||||
|
|
@ -44,4 +54,4 @@ import {
|
|||
|
||||
### Read-Only
|
||||
|
||||
- `id` (Number) The id of the database.
|
||||
- `id` (String) The id of the database.
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ description: |-
|
|||
## Example Usage
|
||||
|
||||
```terraform
|
||||
resource "stackitprivatepreview_postgresflexalpha_instance" "msh-instance-only" {
|
||||
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"]
|
||||
|
|
@ -32,7 +32,7 @@ resource "stackitprivatepreview_postgresflexalpha_instance" "msh-instance-only"
|
|||
service_account = "service@account.email"
|
||||
}
|
||||
network = {
|
||||
acl = ["XXX.XXX.XXX.X/XX", "XX.XXX.XX.X/XX"]
|
||||
acl = ["XXX.XXX.XXX.X/XX", "XX.XXX.XX.X/XX"]
|
||||
access_scope = "PUBLIC"
|
||||
}
|
||||
version = 17
|
||||
|
|
@ -59,7 +59,7 @@ import {
|
|||
|
||||
### 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 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.
|
||||
- `network` (Attributes) The access configuration of the instance (see [below for nested schema](#nestedatt--network))
|
||||
|
|
@ -80,7 +80,7 @@ import {
|
|||
### Read-Only
|
||||
|
||||
- `acl` (List of String) List of IPV4 cidr.
|
||||
- `connection_info` (Attributes) The DNS name and port in the instance overview (see [below for nested schema](#nestedatt--connection_info))
|
||||
- `connection_info` (Attributes) The connection information of the instance (see [below for nested schema](#nestedatt--connection_info))
|
||||
- `id` (String) The ID of the instance.
|
||||
- `is_deletable` (Boolean) Whether the instance can be deleted or not.
|
||||
- `status` (String) The current status of the instance.
|
||||
|
|
@ -127,5 +127,12 @@ Required:
|
|||
|
||||
Read-Only:
|
||||
|
||||
- `write` (Attributes) The DNS name and port in the instance overview (see [below for nested schema](#nestedatt--connection_info--write))
|
||||
|
||||
<a id="nestedatt--connection_info--write"></a>
|
||||
### Nested Schema for `connection_info.write`
|
||||
|
||||
Read-Only:
|
||||
|
||||
- `host` (String) The host of the instance.
|
||||
- `port` (Number) The port of the instance.
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ description: |-
|
|||
resource "stackitprivatepreview_postgresflexalpha_user" "example" {
|
||||
project_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
|
||||
instance_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
|
||||
username = "username"
|
||||
name = "username"
|
||||
roles = ["role"]
|
||||
}
|
||||
|
||||
|
|
@ -25,6 +25,16 @@ import {
|
|||
to = stackitprivatepreview_postgresflexalpha_user.import-example
|
||||
id = "${var.project_id},${var.region},${var.postgres_instance_id},${var.user_id}"
|
||||
}
|
||||
|
||||
import {
|
||||
to = stackitprivatepreview_postgresflexalpha_user.import-example
|
||||
identity = {
|
||||
project_id = "project.id"
|
||||
region = "region"
|
||||
instance_id = "instance.id"
|
||||
user_id = "user.id"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
<!-- schema generated by tfplugindocs -->
|
||||
|
|
@ -44,7 +54,6 @@ import {
|
|||
|
||||
### Read-Only
|
||||
|
||||
- `connection_string` (String) The connection string for the user to the instance.
|
||||
- `id` (Number) The ID of the user.
|
||||
- `id` (String) The ID of the user.
|
||||
- `password` (String) The password for the user.
|
||||
- `status` (String) The current status of the user.
|
||||
|
|
|
|||
|
|
@ -10,7 +10,34 @@ description: |-
|
|||
|
||||
|
||||
|
||||
## 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
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ import {
|
|||
|
||||
### Required
|
||||
|
||||
- `roles` (List of String) A list containing the user roles for the instance.
|
||||
- `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
|
||||
|
|
|
|||
|
|
@ -10,7 +10,22 @@ description: |-
|
|||
|
||||
|
||||
|
||||
## 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
|
||||
|
|
|
|||
53
docs/resources/sqlserverflexbeta_user.md
Normal file
53
docs/resources/sqlserverflexbeta_user.md
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
---
|
||||
# generated by https://github.com/hashicorp/terraform-plugin-docs
|
||||
page_title: "stackitprivatepreview_sqlserverflexbeta_user Resource - stackitprivatepreview"
|
||||
subcategory: ""
|
||||
description: |-
|
||||
|
||||
---
|
||||
|
||||
# stackitprivatepreview_sqlserverflexbeta_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.
|
||||
|
|
@ -9,4 +9,14 @@ resource "stackitprivatepreview_postgresflexalpha_database" "example" {
|
|||
import {
|
||||
to = stackitprivatepreview_postgresflexalpha_database.import-example
|
||||
id = "${var.project_id},${var.region},${var.postgres_instance_id},${var.postgres_database_id}"
|
||||
}
|
||||
}
|
||||
|
||||
import {
|
||||
to = stackitprivatepreview_postgresflexalpha_database.import-example
|
||||
identity = {
|
||||
project_id = "project_id"
|
||||
region = "region"
|
||||
instance_id = "instance_id"
|
||||
database_id = "database_id"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
resource "stackitprivatepreview_postgresflexalpha_instance" "msh-instance-only" {
|
||||
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"]
|
||||
|
|
@ -17,7 +17,7 @@ resource "stackitprivatepreview_postgresflexalpha_instance" "msh-instance-only"
|
|||
service_account = "service@account.email"
|
||||
}
|
||||
network = {
|
||||
acl = ["XXX.XXX.XXX.X/XX", "XX.XXX.XX.X/XX"]
|
||||
acl = ["XXX.XXX.XXX.X/XX", "XX.XXX.XX.X/XX"]
|
||||
access_scope = "PUBLIC"
|
||||
}
|
||||
version = 17
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
resource "stackitprivatepreview_postgresflexalpha_user" "example" {
|
||||
project_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
|
||||
instance_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
|
||||
username = "username"
|
||||
name = "username"
|
||||
roles = ["role"]
|
||||
}
|
||||
|
||||
|
|
@ -9,4 +9,14 @@ resource "stackitprivatepreview_postgresflexalpha_user" "example" {
|
|||
import {
|
||||
to = stackitprivatepreview_postgresflexalpha_user.import-example
|
||||
id = "${var.project_id},${var.region},${var.postgres_instance_id},${var.user_id}"
|
||||
}
|
||||
}
|
||||
|
||||
import {
|
||||
to = stackitprivatepreview_postgresflexalpha_user.import-example
|
||||
identity = {
|
||||
project_id = "project.id"
|
||||
region = "region"
|
||||
instance_id = "instance.id"
|
||||
user_id = "user.id"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,24 @@
|
|||
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"
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
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}"
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
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}"
|
||||
}
|
||||
341
generator/cmd/build/build.go
Normal file
341
generator/cmd/build/build.go
Normal file
|
|
@ -0,0 +1,341 @@
|
|||
package build
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"go/ast"
|
||||
"go/parser"
|
||||
"go/token"
|
||||
"log/slog"
|
||||
"os"
|
||||
"path"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/generator/cmd/tools"
|
||||
)
|
||||
|
||||
type Builder struct {
|
||||
rootDir string
|
||||
SkipClone bool
|
||||
SkipCleanup bool
|
||||
PackagesOnly bool
|
||||
Verbose bool
|
||||
Debug bool
|
||||
}
|
||||
|
||||
func (b *Builder) Build() error {
|
||||
slog.Info("Starting Builder")
|
||||
if b.PackagesOnly {
|
||||
slog.Info(" >>> only generating pkg_gen <<<")
|
||||
}
|
||||
|
||||
rootErr := b.determineRoot()
|
||||
if rootErr != nil {
|
||||
return rootErr
|
||||
}
|
||||
|
||||
if !b.PackagesOnly {
|
||||
if b.Verbose {
|
||||
slog.Info(" ... Checking needed commands available")
|
||||
}
|
||||
chkErr := checkCommands([]string{})
|
||||
if chkErr != nil {
|
||||
return chkErr
|
||||
}
|
||||
}
|
||||
|
||||
// if !b.SkipCleanup {
|
||||
// slog.Info("Cleaning up old packages directory")
|
||||
// err := os.RemoveAll(path.Join(b.rootDir, "pkg_gen"))
|
||||
// if err != nil {
|
||||
// return err
|
||||
// }
|
||||
//}
|
||||
//
|
||||
// if !b.SkipCleanup && !b.PackagesOnly {
|
||||
// slog.Info("Cleaning up old packages directory")
|
||||
// err := os.RemoveAll(path.Join(b.rootDir, "pkg_gen"))
|
||||
// if err != nil {
|
||||
// return err
|
||||
// }
|
||||
//}
|
||||
|
||||
// slog.Info("Creating generator dir", "dir", fmt.Sprintf("%s/%s", *root, GEN_REPO_NAME))
|
||||
// genDir := path.Join(*root, GEN_REPO_NAME)
|
||||
// if !b.SkipClone {
|
||||
// err = createGeneratorDir(GEN_REPO, genDir, b.SkipClone)
|
||||
// if err != nil {
|
||||
// return err
|
||||
// }
|
||||
//}
|
||||
|
||||
oasHandlerErr := b.oasHandler(path.Join(b.rootDir, "service_specs"))
|
||||
if oasHandlerErr != nil {
|
||||
return oasHandlerErr
|
||||
}
|
||||
|
||||
// if !b.PackagesOnly {
|
||||
// slog.Info("Generating service boilerplate")
|
||||
// err = generateServiceFiles(*root, path.Join(*root, GEN_REPO_NAME))
|
||||
// if err != nil {
|
||||
// return err
|
||||
// }
|
||||
//
|
||||
// slog.Info("Copying all service files")
|
||||
// err = CopyDirectory(
|
||||
// path.Join(*root, "generated", "internal", "services"),
|
||||
// path.Join(*root, "stackit", "internal", "services"),
|
||||
// )
|
||||
// if err != nil {
|
||||
// return err
|
||||
// }
|
||||
//
|
||||
// err = createBoilerplate(*root, path.Join(*root, "stackit", "internal", "services"))
|
||||
// if err != nil {
|
||||
// return err
|
||||
// }
|
||||
//}
|
||||
|
||||
// workaround to remove linter complain :D
|
||||
if b.PackagesOnly && b.Verbose && b.SkipClone && b.SkipCleanup {
|
||||
bpErr := createBoilerplate(b.rootDir, "boilerplate")
|
||||
if bpErr != nil {
|
||||
return bpErr
|
||||
}
|
||||
}
|
||||
|
||||
slog.Info("Done")
|
||||
return nil
|
||||
}
|
||||
|
||||
type templateData struct {
|
||||
PackageName string
|
||||
PackageNameCamel string
|
||||
PackageNamePascal string
|
||||
NameCamel string
|
||||
NamePascal string
|
||||
NameSnake string
|
||||
Fields []string
|
||||
}
|
||||
|
||||
func createBoilerplate(rootFolder, folder string) error {
|
||||
services, err := os.ReadDir(folder)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, svc := range services {
|
||||
if !svc.IsDir() {
|
||||
continue
|
||||
}
|
||||
resources, err := os.ReadDir(path.Join(folder, svc.Name()))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var handleDS bool
|
||||
var handleRes bool
|
||||
var foundDS bool
|
||||
var foundRes bool
|
||||
|
||||
for _, res := range resources {
|
||||
if !res.IsDir() {
|
||||
continue
|
||||
}
|
||||
|
||||
resourceName := res.Name()
|
||||
|
||||
dsFile := path.Join(
|
||||
folder,
|
||||
svc.Name(),
|
||||
res.Name(),
|
||||
"datasources_gen",
|
||||
fmt.Sprintf("%s_data_source_gen.go", res.Name()),
|
||||
)
|
||||
handleDS = FileExists(dsFile)
|
||||
|
||||
resFile := path.Join(
|
||||
folder,
|
||||
svc.Name(),
|
||||
res.Name(),
|
||||
"resources_gen",
|
||||
fmt.Sprintf("%s_resource_gen.go", res.Name()),
|
||||
)
|
||||
handleRes = FileExists(resFile)
|
||||
|
||||
dsGoFile := path.Join(folder, svc.Name(), res.Name(), "datasource.go")
|
||||
foundDS = FileExists(dsGoFile)
|
||||
|
||||
resGoFile := path.Join(folder, svc.Name(), res.Name(), "resource.go")
|
||||
foundRes = FileExists(resGoFile)
|
||||
|
||||
if handleDS && !foundDS {
|
||||
slog.Info(" creating missing datasource.go", "service", svc.Name(), "resource", resourceName)
|
||||
if !ValidateSnakeCase(resourceName) {
|
||||
return errors.New("resource name is invalid")
|
||||
}
|
||||
|
||||
fields, tokenErr := getTokens(dsFile)
|
||||
if tokenErr != nil {
|
||||
return fmt.Errorf("error reading tokens: %w", tokenErr)
|
||||
}
|
||||
|
||||
tplName := "data_source_scaffold.gotmpl"
|
||||
err = writeTemplateToFile(
|
||||
tplName,
|
||||
path.Join(rootFolder, "cmd", "cmd", "build", "templates", tplName),
|
||||
dsGoFile,
|
||||
&templateData{
|
||||
PackageName: svc.Name(),
|
||||
PackageNameCamel: ToCamelCase(svc.Name()),
|
||||
PackageNamePascal: ToPascalCase(svc.Name()),
|
||||
NameCamel: ToCamelCase(resourceName),
|
||||
NamePascal: ToPascalCase(resourceName),
|
||||
NameSnake: resourceName,
|
||||
Fields: fields,
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
if handleRes && !foundRes {
|
||||
slog.Info(" creating missing resource.go", "service", svc.Name(), "resource", resourceName)
|
||||
if !ValidateSnakeCase(resourceName) {
|
||||
return errors.New("resource name is invalid")
|
||||
}
|
||||
|
||||
fields, tokenErr := getTokens(resFile)
|
||||
if tokenErr != nil {
|
||||
return fmt.Errorf("error reading tokens: %w", tokenErr)
|
||||
}
|
||||
|
||||
tplName := "resource_scaffold.gotmpl"
|
||||
err = writeTemplateToFile(
|
||||
tplName,
|
||||
path.Join(rootFolder, "cmd", "cmd", "build", "templates", tplName),
|
||||
resGoFile,
|
||||
&templateData{
|
||||
PackageName: svc.Name(),
|
||||
PackageNameCamel: ToCamelCase(svc.Name()),
|
||||
PackageNamePascal: ToPascalCase(svc.Name()),
|
||||
NameCamel: ToCamelCase(resourceName),
|
||||
NamePascal: ToPascalCase(resourceName),
|
||||
NameSnake: resourceName,
|
||||
Fields: fields,
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !FileExists(path.Join(folder, svc.Name(), res.Name(), "functions.go")) {
|
||||
slog.Info(" creating missing functions.go", "service", svc.Name(), "resource", resourceName)
|
||||
if !ValidateSnakeCase(resourceName) {
|
||||
return errors.New("resource name is invalid")
|
||||
}
|
||||
fncTplName := "functions_scaffold.gotmpl"
|
||||
err = writeTemplateToFile(
|
||||
fncTplName,
|
||||
path.Join(rootFolder, "cmd", "cmd", "build", "templates", fncTplName),
|
||||
path.Join(folder, svc.Name(), res.Name(), "functions.go"),
|
||||
&templateData{
|
||||
PackageName: svc.Name(),
|
||||
PackageNameCamel: ToCamelCase(svc.Name()),
|
||||
PackageNamePascal: ToPascalCase(svc.Name()),
|
||||
NameCamel: ToCamelCase(resourceName),
|
||||
NamePascal: ToPascalCase(resourceName),
|
||||
NameSnake: resourceName,
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func handleLine(line string) (string, error) {
|
||||
schemaRegex := regexp.MustCompile(`(\s+")(id)(": schema.[a-zA-Z0-9]+Attribute{)`)
|
||||
|
||||
schemaMatches := schemaRegex.FindAllStringSubmatch(line, -1)
|
||||
if schemaMatches != nil {
|
||||
return fmt.Sprintf("%stf_original_api_id%s", schemaMatches[0][1], schemaMatches[0][3]), nil
|
||||
}
|
||||
|
||||
modelRegex := regexp.MustCompile(`(\s+Id\s+types.[a-zA-Z0-9]+\s+.tfsdk:")(id)(".)`)
|
||||
modelMatches := modelRegex.FindAllStringSubmatch(line, -1)
|
||||
if modelMatches != nil {
|
||||
return fmt.Sprintf("%stf_original_api_id%s", modelMatches[0][1], modelMatches[0][3]), nil
|
||||
}
|
||||
|
||||
return line, nil
|
||||
}
|
||||
|
||||
func (b *Builder) determineRoot() error {
|
||||
root, err := tools.GetGitRoot()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
b.rootDir = root
|
||||
if b.Verbose {
|
||||
slog.Info(" ... using root", "dir", b.rootDir)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// func createGeneratorDir(repoUrl, targetDir string, skipClone bool) error {
|
||||
// if !skipClone {
|
||||
// if FileExists(targetDir) {
|
||||
// remErr := os.RemoveAll(targetDir)
|
||||
// if remErr != nil {
|
||||
// return remErr
|
||||
// }
|
||||
// }
|
||||
// _, cloneErr := git.Clone(
|
||||
// clone.Repository(repoUrl),
|
||||
// clone.Directory(targetDir),
|
||||
// )
|
||||
// if cloneErr != nil {
|
||||
// return cloneErr
|
||||
// }
|
||||
// }
|
||||
// return nil
|
||||
//}
|
||||
|
||||
func getTokens(fileName string) ([]string, error) {
|
||||
fset := token.NewFileSet()
|
||||
|
||||
var result []string
|
||||
|
||||
node, err := parser.ParseFile(fset, fileName, nil, parser.ParseComments)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ast.Inspect(
|
||||
node, func(n ast.Node) bool {
|
||||
// Suche nach Typ-Deklarationen (structs)
|
||||
ts, ok := n.(*ast.TypeSpec)
|
||||
if ok {
|
||||
if strings.Contains(ts.Name.Name, "Model") {
|
||||
ast.Inspect(
|
||||
ts, func(sn ast.Node) bool {
|
||||
tts, tok := sn.(*ast.Field)
|
||||
if tok {
|
||||
result = append(result, tts.Names[0].String())
|
||||
}
|
||||
return true
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
return true
|
||||
},
|
||||
)
|
||||
return result, nil
|
||||
}
|
||||
|
|
@ -3,6 +3,7 @@ package build
|
|||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"log/slog"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"syscall"
|
||||
|
|
@ -74,14 +75,24 @@ func Copy(srcFile, dstFile string) error {
|
|||
return err
|
||||
}
|
||||
|
||||
defer out.Close()
|
||||
defer func(out *os.File) {
|
||||
err := out.Close()
|
||||
if err != nil {
|
||||
slog.Error("failed to close file", slog.Any("err", err))
|
||||
}
|
||||
}(out)
|
||||
|
||||
in, err := os.Open(srcFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer in.Close()
|
||||
defer func(in *os.File) {
|
||||
err := in.Close()
|
||||
if err != nil {
|
||||
slog.Error("error closing destination file", slog.Any("err", err))
|
||||
}
|
||||
}(in)
|
||||
|
||||
_, err = io.Copy(out, in)
|
||||
if err != nil {
|
||||
120
generator/cmd/build/functions.go
Normal file
120
generator/cmd/build/functions.go
Normal file
|
|
@ -0,0 +1,120 @@
|
|||
package build
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
"text/template"
|
||||
)
|
||||
|
||||
func FileExists(pathValue string) bool {
|
||||
_, err := os.Stat(pathValue)
|
||||
if os.IsNotExist(err) {
|
||||
return false
|
||||
}
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func ucfirst(s string) string {
|
||||
if s == "" {
|
||||
return ""
|
||||
}
|
||||
return strings.ToUpper(s[:1]) + s[1:]
|
||||
}
|
||||
|
||||
func writeTemplateToFile(tplName, tplFile, outFile string, data *templateData) error {
|
||||
fn := template.FuncMap{
|
||||
"ucfirst": ucfirst,
|
||||
}
|
||||
|
||||
tmpl, err := template.New(tplName).Funcs(fn).ParseFiles(tplFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var f *os.File
|
||||
f, err = os.Create(outFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = tmpl.Execute(f, *data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = f.Close()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
/* saved for later
|
||||
func deleteFiles(fNames ...string) error {
|
||||
for _, fName := range fNames {
|
||||
if _, err := os.Stat(fName); !os.IsNotExist(err) {
|
||||
err = os.Remove(fName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func copyFile(src, dst string) (int64, error) {
|
||||
sourceFileStat, err := os.Stat(src)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
if !sourceFileStat.Mode().IsRegular() {
|
||||
return 0, fmt.Errorf("%s is not a regular file", src)
|
||||
}
|
||||
|
||||
source, err := os.Open(src)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
defer func(source *os.File) {
|
||||
err := source.Close()
|
||||
if err != nil {
|
||||
slog.Error("copyFile", "err", err)
|
||||
}
|
||||
}(source)
|
||||
|
||||
destination, err := os.Create(dst)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
defer func(destination *os.File) {
|
||||
err := destination.Close()
|
||||
if err != nil {
|
||||
slog.Error("copyFile", "err", err)
|
||||
}
|
||||
}(destination)
|
||||
nBytes, err := io.Copy(destination, source)
|
||||
return nBytes, err
|
||||
}
|
||||
*/
|
||||
|
||||
func checkCommands(commands []string) error {
|
||||
for _, commandName := range commands {
|
||||
if !commandExists(commandName) {
|
||||
return fmt.Errorf("missing command %s", commandName)
|
||||
}
|
||||
slog.Info(" found", "command", commandName)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func commandExists(cmd string) bool {
|
||||
_, err := exec.LookPath(cmd)
|
||||
return err == nil
|
||||
}
|
||||
446
generator/cmd/build/oas-handler.go
Normal file
446
generator/cmd/build/oas-handler.go
Normal file
|
|
@ -0,0 +1,446 @@
|
|||
package build
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log"
|
||||
"log/slog"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"gopkg.in/yaml.v3"
|
||||
|
||||
"github.com/ldez/go-git-cmd-wrapper/v2/clone"
|
||||
"github.com/ldez/go-git-cmd-wrapper/v2/git"
|
||||
)
|
||||
|
||||
const (
|
||||
OasRepoName = "stackit-api-specifications"
|
||||
OasRepo = "https://github.com/stackitcloud/stackit-api-specifications.git"
|
||||
|
||||
ResTypeResource = "resources"
|
||||
ResTypeDataSource = "datasources"
|
||||
)
|
||||
|
||||
type Data struct {
|
||||
ServiceName string `yaml:",omitempty" json:",omitempty"`
|
||||
Versions []Version `yaml:"versions" json:"versions"`
|
||||
}
|
||||
|
||||
type Version struct {
|
||||
Name string `yaml:"name" json:"name"`
|
||||
Path string `yaml:"path" json:"path"`
|
||||
}
|
||||
|
||||
var oasTempDir string
|
||||
|
||||
func (b *Builder) oasHandler(specDir string) error {
|
||||
if b.Verbose {
|
||||
slog.Info("creating schema files", "dir", specDir)
|
||||
}
|
||||
if _, err := os.Stat(specDir); os.IsNotExist(err) {
|
||||
return fmt.Errorf("spec files directory does not exist")
|
||||
}
|
||||
|
||||
err := b.createRepoDir(b.SkipClone)
|
||||
if err != nil {
|
||||
return fmt.Errorf("%s", err.Error())
|
||||
}
|
||||
|
||||
err2 := b.handleServices(specDir)
|
||||
if err2 != nil {
|
||||
return err2
|
||||
}
|
||||
|
||||
if !b.SkipCleanup {
|
||||
if b.Verbose {
|
||||
slog.Info("Finally removing temporary files and directories")
|
||||
}
|
||||
err := os.RemoveAll(path.Join(b.rootDir, "generated"))
|
||||
if err != nil {
|
||||
slog.Error("RemoveAll", "dir", path.Join(b.rootDir, "generated"), "err", err)
|
||||
return err
|
||||
}
|
||||
|
||||
err = os.RemoveAll(oasTempDir)
|
||||
if err != nil {
|
||||
slog.Error("RemoveAll", "dir", oasTempDir, "err", err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *Builder) handleServices(specDir string) error {
|
||||
services, err := os.ReadDir(specDir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, svc := range services {
|
||||
if !svc.IsDir() {
|
||||
continue
|
||||
}
|
||||
|
||||
if b.Verbose {
|
||||
slog.Info(" ... found", "service", svc.Name())
|
||||
}
|
||||
var svcVersions Data
|
||||
svcVersions.ServiceName = svc.Name()
|
||||
|
||||
versionsErr := b.getServiceVersions(path.Join(specDir, svc.Name(), "generator_settings.yml"), &svcVersions)
|
||||
if versionsErr != nil {
|
||||
return versionsErr
|
||||
}
|
||||
|
||||
oasSpecErr := b.generateServiceFiles(&svcVersions)
|
||||
if oasSpecErr != nil {
|
||||
return oasSpecErr
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *Builder) getServiceVersions(confFile string, data *Data) error {
|
||||
if _, cfgFileErr := os.Stat(confFile); os.IsNotExist(cfgFileErr) {
|
||||
return fmt.Errorf("config file does not exist")
|
||||
}
|
||||
|
||||
fileContent, fileErr := os.ReadFile(confFile)
|
||||
if fileErr != nil {
|
||||
return fileErr
|
||||
}
|
||||
convErr := yaml.Unmarshal(fileContent, &data)
|
||||
if convErr != nil {
|
||||
return convErr
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *Builder) createRepoDir(skipClone bool) error {
|
||||
tmpDirName, err := os.MkdirTemp("", "oasbuild")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
oasTempDir = path.Join(tmpDirName, OasRepoName)
|
||||
slog.Info("Creating oas repo dir", "dir", oasTempDir)
|
||||
if !skipClone {
|
||||
if FileExists(oasTempDir) {
|
||||
slog.Warn("target dir exists - skipping", "targetDir", oasTempDir)
|
||||
return nil
|
||||
}
|
||||
out, cloneErr := git.Clone(
|
||||
clone.Repository(OasRepo),
|
||||
clone.Directory(oasTempDir),
|
||||
)
|
||||
if cloneErr != nil {
|
||||
slog.Error("git clone error", "output", out)
|
||||
return cloneErr
|
||||
}
|
||||
if b.Verbose {
|
||||
slog.Info("git clone result", "output", out)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *Builder) generateServiceFiles(data *Data) error {
|
||||
err := os.MkdirAll(path.Join(b.rootDir, "generated", "specs"), 0o750)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, v := range data.Versions {
|
||||
specFiles, specsErr := os.ReadDir(path.Join(b.rootDir, "service_specs", data.ServiceName, v.Name))
|
||||
if specsErr != nil {
|
||||
return specsErr
|
||||
}
|
||||
for _, specFile := range specFiles {
|
||||
if specFile.IsDir() {
|
||||
continue
|
||||
}
|
||||
r := regexp.MustCompile(`^(.*)_config.yml$`)
|
||||
matches := r.FindAllStringSubmatch(specFile.Name(), -1)
|
||||
if matches == nil {
|
||||
slog.Warn(" skipping file (no regex match)", "file", specFile.Name())
|
||||
continue
|
||||
}
|
||||
|
||||
srcSpecFile := path.Join(b.rootDir, "service_specs", data.ServiceName, v.Name, specFile.Name())
|
||||
|
||||
if matches[0][0] != specFile.Name() {
|
||||
return fmt.Errorf("matched filename differs from original filename - this should not happen")
|
||||
}
|
||||
resource := matches[0][1]
|
||||
if b.Verbose {
|
||||
slog.Info(
|
||||
" found service spec",
|
||||
"service",
|
||||
data.ServiceName,
|
||||
"resource",
|
||||
resource,
|
||||
"file",
|
||||
specFile.Name(),
|
||||
)
|
||||
}
|
||||
|
||||
oasFile := path.Join(
|
||||
oasTempDir,
|
||||
"services",
|
||||
data.ServiceName,
|
||||
v.Path,
|
||||
fmt.Sprintf("%s.json", data.ServiceName),
|
||||
)
|
||||
if _, oasErr := os.Stat(oasFile); os.IsNotExist(oasErr) {
|
||||
slog.Warn(
|
||||
" could not find matching oas",
|
||||
"svc",
|
||||
data.ServiceName,
|
||||
"version",
|
||||
v.Name,
|
||||
)
|
||||
continue
|
||||
}
|
||||
|
||||
// determine correct target service name
|
||||
scName := fmt.Sprintf("%s%s", data.ServiceName, v.Name)
|
||||
scName = strings.ReplaceAll(scName, "-", "")
|
||||
|
||||
specJSONFile := path.Join(
|
||||
b.rootDir,
|
||||
"generated",
|
||||
"specs",
|
||||
fmt.Sprintf("%s_%s_spec.json", scName, resource),
|
||||
)
|
||||
|
||||
cmdErr := b.runTerraformPluginGenOpenAPI(srcSpecFile, specJSONFile, oasFile)
|
||||
if cmdErr != nil {
|
||||
return cmdErr
|
||||
}
|
||||
|
||||
cmdResGenErr := b.runTerraformPluginGenFramework(ResTypeResource, scName, resource, specJSONFile)
|
||||
if cmdResGenErr != nil {
|
||||
return cmdResGenErr
|
||||
}
|
||||
|
||||
cmdDsGenErr := b.runTerraformPluginGenFramework(ResTypeDataSource, scName, resource, specJSONFile)
|
||||
if cmdDsGenErr != nil {
|
||||
return cmdDsGenErr
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *Builder) runTerraformPluginGenFramework(resType, svcName, resource, specJSONFile string) error {
|
||||
var stdOut, stdErr bytes.Buffer
|
||||
tgtFolder := path.Join(
|
||||
b.rootDir,
|
||||
"stackit",
|
||||
"internal",
|
||||
"services",
|
||||
svcName,
|
||||
resource,
|
||||
fmt.Sprintf("%s_gen", resType),
|
||||
)
|
||||
|
||||
//nolint:gosec // this file is not sensitive, so we can use 0755
|
||||
err := os.MkdirAll(tgtFolder, 0o755)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var subCmd string
|
||||
switch resType {
|
||||
case ResTypeResource:
|
||||
subCmd = "resources"
|
||||
case ResTypeDataSource:
|
||||
subCmd = "data-sources"
|
||||
default:
|
||||
return fmt.Errorf("unknown resource type given: %s", resType)
|
||||
}
|
||||
|
||||
// nolint:gosec // #nosec this command is not using any untrusted input, so we can ignore gosec warning
|
||||
cmd := exec.Command(
|
||||
"tfplugingen-framework",
|
||||
"generate",
|
||||
subCmd,
|
||||
"--input",
|
||||
specJSONFile,
|
||||
"--output",
|
||||
tgtFolder,
|
||||
"--package",
|
||||
svcName,
|
||||
)
|
||||
|
||||
cmd.Stdout = &stdOut
|
||||
cmd.Stderr = &stdErr
|
||||
if err = cmd.Start(); err != nil {
|
||||
slog.Error(fmt.Sprintf("tfplugingen-framework generate %s", resType), "error", err)
|
||||
return err
|
||||
}
|
||||
|
||||
if err = cmd.Wait(); err != nil {
|
||||
var exitErr *exec.ExitError
|
||||
if errors.As(err, &exitErr) {
|
||||
slog.Error(
|
||||
fmt.Sprintf("tfplugingen-framework generate %s", resType),
|
||||
"code",
|
||||
exitErr.ExitCode(),
|
||||
"error",
|
||||
err,
|
||||
"stdout",
|
||||
stdOut.String(),
|
||||
"stderr",
|
||||
stdErr.String(),
|
||||
)
|
||||
return fmt.Errorf("%s", stdErr.String())
|
||||
}
|
||||
if err != nil {
|
||||
slog.Error(
|
||||
fmt.Sprintf("tfplugingen-framework generate %s", resType),
|
||||
"err",
|
||||
err,
|
||||
"stdout",
|
||||
stdOut.String(),
|
||||
"stderr",
|
||||
stdErr.String(),
|
||||
)
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if resType == ResTypeDataSource {
|
||||
tfAnoErr := b.handleTfTagForDatasourceFile(
|
||||
path.Join(tgtFolder, fmt.Sprintf("%s_data_source_gen.go", resource)),
|
||||
svcName,
|
||||
resource,
|
||||
)
|
||||
if tfAnoErr != nil {
|
||||
return tfAnoErr
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *Builder) runTerraformPluginGenOpenAPI(srcSpecFile, specJSONFile, oasFile string) error {
|
||||
var stdOut, stdErr bytes.Buffer
|
||||
|
||||
// nolint:gosec // #nosec this command is not using any untrusted input, so we can ignore gosec warning
|
||||
cmd := exec.Command(
|
||||
"tfplugingen-openapi",
|
||||
"generate",
|
||||
"--config",
|
||||
srcSpecFile,
|
||||
"--output",
|
||||
specJSONFile,
|
||||
oasFile,
|
||||
)
|
||||
cmd.Stdout = &stdOut
|
||||
cmd.Stderr = &stdErr
|
||||
|
||||
if err := cmd.Start(); err != nil {
|
||||
slog.Error(
|
||||
"tfplugingen-openapi generate",
|
||||
"error",
|
||||
err,
|
||||
"stdOut",
|
||||
stdOut.String(),
|
||||
"stdErr",
|
||||
stdErr.String(),
|
||||
)
|
||||
return err
|
||||
}
|
||||
|
||||
if err := cmd.Wait(); err != nil {
|
||||
var exitErr *exec.ExitError
|
||||
if errors.As(err, &exitErr) {
|
||||
slog.Error(
|
||||
"tfplugingen-openapi generate",
|
||||
"code",
|
||||
exitErr.ExitCode(),
|
||||
"error",
|
||||
err,
|
||||
"stdout",
|
||||
stdOut.String(),
|
||||
"stderr",
|
||||
stdErr.String(),
|
||||
)
|
||||
return fmt.Errorf("%s", stdErr.String())
|
||||
}
|
||||
if err != nil {
|
||||
slog.Error(
|
||||
"tfplugingen-openapi generate",
|
||||
"err",
|
||||
err,
|
||||
"stdout",
|
||||
stdOut.String(),
|
||||
"stderr",
|
||||
stdErr.String(),
|
||||
)
|
||||
return err
|
||||
}
|
||||
}
|
||||
if stdOut.Len() > 0 {
|
||||
slog.Warn(" command output", "stdout", stdOut.String(), "stderr", stdErr.String())
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// handleTfTagForDatasourceFile replaces existing "id" with "stf_original_api_id"
|
||||
func (b *Builder) handleTfTagForDatasourceFile(filePath, service, resource string) error {
|
||||
if b.Verbose {
|
||||
slog.Info(" handle terraform tag for datasource", "service", service, "resource", resource)
|
||||
}
|
||||
if !FileExists(filePath) {
|
||||
slog.Warn(" could not find file, skipping", "path", filePath)
|
||||
return nil
|
||||
}
|
||||
f, err := os.Open(filePath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
tmp, err := os.CreateTemp(b.rootDir, "replace-*")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
sc := bufio.NewScanner(f)
|
||||
for sc.Scan() {
|
||||
resLine, err := handleLine(sc.Text())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := tmp.WriteString(resLine + "\n"); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if scErr := sc.Err(); scErr != nil {
|
||||
return scErr
|
||||
}
|
||||
|
||||
if err := tmp.Close(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := f.Close(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
//nolint:gosec // path traversal is not a concern here
|
||||
if err := os.Rename(tmp.Name(), filePath); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
@ -39,17 +39,25 @@ type {{.NameCamel}}Resource struct{
|
|||
providerData core.ProviderData
|
||||
}
|
||||
|
||||
// resourceModel represents the Terraform resource state
|
||||
type resourceModel = {{.PackageName}}.{{.NamePascal}}Model
|
||||
|
||||
type {{.NamePascal}}ResourceIdentityModel struct {
|
||||
ProjectID types.String `tfsdk:"project_id"`
|
||||
Region types.String `tfsdk:"region"`
|
||||
{{.NamePascal}}ID types.String `tfsdk:"instance_id"`
|
||||
// TODO: implement further needed parts
|
||||
{{.NamePascal}}ID types.String `tfsdk:"{{.NameSnake}}_id"`
|
||||
}
|
||||
|
||||
// Metadata defines terraform resource name
|
||||
func (r *{{.NameCamel}}Resource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
|
||||
resp.TypeName = req.ProviderTypeName + "_{{.PackageName}}_{{.NameSnake}}"
|
||||
}
|
||||
|
||||
//go:embed planModifiers.yaml
|
||||
var modifiersFileByte []byte
|
||||
|
||||
// Schema loads the schema from generated files and adds plan modifiers
|
||||
func (r *{{.NameCamel}}Resource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
|
||||
schema = {{.PackageName}}ResGen.{{.NamePascal}}ResourceSchema(ctx)
|
||||
|
||||
|
|
@ -67,6 +75,7 @@ func (r *{{.NameCamel}}Resource) Schema(ctx context.Context, req resource.Schema
|
|||
resp.Schema = schema
|
||||
}
|
||||
|
||||
// IdentitySchema defines the identity schema
|
||||
func (r *instanceResource) IdentitySchema(_ context.Context, _ resource.IdentitySchemaRequest, resp *resource.IdentitySchemaResponse) {
|
||||
resp.IdentitySchema = identityschema.Schema{
|
||||
Attributes: map[string]identityschema.Attribute{
|
||||
|
|
@ -79,11 +88,11 @@ func (r *instanceResource) IdentitySchema(_ context.Context, _ resource.Identity
|
|||
"instance_id": identityschema.StringAttribute{
|
||||
RequiredForImport: true, // can be defaulted by the provider configuration
|
||||
},
|
||||
// TODO: implement remaining schema parts
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Configure adds the provider configured client to the resource.
|
||||
func (r *{{.NameCamel}}Resource) Configure(
|
||||
ctx context.Context,
|
||||
|
|
@ -152,27 +161,12 @@ func (r *{{.NameCamel}}Resource) ModifyPlan(
|
|||
return
|
||||
}
|
||||
|
||||
var identityModel {{.NamePascal}}ResourceIdentityModel
|
||||
identityModel.ProjectID = planModel.ProjectId
|
||||
identityModel.Region = planModel.Region
|
||||
if !planModel.{{.NamePascal}}Id.IsNull() && !planModel.{{.NamePascal}}Id.IsUnknown() {
|
||||
identityModel.{{.NamePascal}}ID = planModel.{{.NamePascal}}Id
|
||||
}
|
||||
|
||||
resp.Diagnostics.Append(resp.Identity.Set(ctx, identityModel)...)
|
||||
if resp.Diagnostics.HasError() {
|
||||
return
|
||||
}
|
||||
|
||||
resp.Diagnostics.Append(resp.Plan.Set(ctx, planModel)...)
|
||||
if resp.Diagnostics.HasError() {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
//go:embed planModifiers.yaml
|
||||
var modifiersFileByte []byte
|
||||
|
||||
// Create creates a new resource
|
||||
func (r *{{.NameCamel}}Resource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
|
||||
var data {{.PackageName}}ResGen.{{.NamePascal}}Model
|
||||
|
|
@ -184,19 +178,13 @@ func (r *{{.NameCamel}}Resource) Create(ctx context.Context, req resource.Create
|
|||
return
|
||||
}
|
||||
|
||||
// Read identity data
|
||||
var identityData {{.NamePascal}}ResourceIdentityModel
|
||||
resp.Diagnostics.Append(req.Identity.Get(ctx, &identityData)...)
|
||||
if resp.Diagnostics.HasError() {
|
||||
return
|
||||
}
|
||||
|
||||
ctx = core.InitProviderContext(ctx)
|
||||
|
||||
projectId := identityData.ProjectID.ValueString()
|
||||
region := identityData.Region.ValueString()
|
||||
projectId := data.ProjectId.ValueString()
|
||||
region := data.Region.ValueString()
|
||||
ctx = tflog.SetField(ctx, "project_id", projectId)
|
||||
ctx = tflog.SetField(ctx, "region", region)
|
||||
// TODO: add remaining fields
|
||||
|
||||
// TODO: Create API call logic
|
||||
/*
|
||||
|
|
@ -320,7 +308,7 @@ func (r *{{.NameCamel}}Resource) Read(ctx context.Context, req resource.ReadRequ
|
|||
ctx = tflog.SetField(ctx, "project_id", projectId)
|
||||
ctx = tflog.SetField(ctx, "region", region)
|
||||
|
||||
// Todo: Read API call logic
|
||||
// TODO: Read API call logic
|
||||
|
||||
// Save updated data into Terraform state
|
||||
resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
|
||||
|
|
@ -348,22 +336,26 @@ func (r *{{.NameCamel}}Resource) Update(ctx context.Context, req resource.Update
|
|||
return
|
||||
}
|
||||
|
||||
// Read identity data
|
||||
var identityData {{.NamePascal}}ResourceIdentityModel
|
||||
resp.Diagnostics.Append(req.Identity.Get(ctx, &identityData)...)
|
||||
if resp.Diagnostics.HasError() {
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
ctx = core.InitProviderContext(ctx)
|
||||
|
||||
projectId := identityData.ProjectID.ValueString()
|
||||
region := identityData.Region.ValueString()
|
||||
projectId := data.ProjectId.ValueString()
|
||||
region := data.Region.ValueString()
|
||||
ctx = tflog.SetField(ctx, "project_id", projectId)
|
||||
ctx = tflog.SetField(ctx, "region", region)
|
||||
|
||||
// Todo: Update API call logic
|
||||
// TODO: Update API call logic
|
||||
|
||||
// TODO: Set data returned by API in identity
|
||||
identity := {{.NamePascal}}ResourceIdentityModel{
|
||||
ProjectID: types.StringValue(projectId),
|
||||
Region: types.StringValue(region),
|
||||
// TODO: add missing values
|
||||
{{.NamePascal}}ID: types.StringValue({{.NamePascal}}Id),
|
||||
}
|
||||
resp.Diagnostics.Append(resp.Identity.Set(ctx, identity)...)
|
||||
if resp.Diagnostics.HasError() {
|
||||
return
|
||||
}
|
||||
|
||||
// Save updated data into Terraform state
|
||||
resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
|
||||
|
|
@ -395,7 +387,7 @@ func (r *{{.NameCamel}}Resource) Delete(ctx context.Context, req resource.Delete
|
|||
ctx = tflog.SetField(ctx, "project_id", projectId)
|
||||
ctx = tflog.SetField(ctx, "region", region)
|
||||
|
||||
// Todo: Delete API call logic
|
||||
// TODO: Delete API call logic
|
||||
|
||||
tflog.Info(ctx, "{{.PackageName}}.{{.NamePascal}} deleted")
|
||||
}
|
||||
|
|
@ -409,7 +401,8 @@ func (r *{{.NameCamel}}Resource) ImportState(
|
|||
) {
|
||||
idParts := strings.Split(req.ID, core.Separator)
|
||||
|
||||
// Todo: Import logic
|
||||
// TODO: Import logic
|
||||
// TODO: fix len and parts itself
|
||||
if len(idParts) < 2 || idParts[0] == "" || idParts[1] == "" {
|
||||
core.LogAndAddError(
|
||||
ctx, &resp.Diagnostics,
|
||||
|
|
@ -2,24 +2,29 @@ package cmd
|
|||
|
||||
import (
|
||||
"github.com/spf13/cobra"
|
||||
"tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/cmd/cmd/build"
|
||||
|
||||
"tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/generator/cmd/build"
|
||||
)
|
||||
|
||||
var (
|
||||
skipCleanup bool
|
||||
skipClone bool
|
||||
packagesOnly bool
|
||||
verbose bool
|
||||
debug bool
|
||||
)
|
||||
|
||||
var buildCmd = &cobra.Command{
|
||||
Use: "build",
|
||||
Short: "Build the necessary boilerplate",
|
||||
Long: `...`,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
RunE: func(_ *cobra.Command, _ []string) error {
|
||||
b := build.Builder{
|
||||
SkipClone: skipClone,
|
||||
SkipCleanup: skipCleanup,
|
||||
PackagesOnly: packagesOnly,
|
||||
Verbose: verbose,
|
||||
Debug: debug,
|
||||
}
|
||||
return b.Build()
|
||||
},
|
||||
|
|
@ -29,8 +34,10 @@ func NewBuildCmd() *cobra.Command {
|
|||
return buildCmd
|
||||
}
|
||||
|
||||
func init() { // nolint: gochecknoinits
|
||||
func init() { //nolint:gochecknoinits // This is the standard way to set up Cobra commands
|
||||
buildCmd.Flags().BoolVarP(&skipCleanup, "skip-clean", "c", false, "Skip cleanup steps")
|
||||
buildCmd.Flags().BoolVarP(&debug, "debug", "d", false, "Enable debug output")
|
||||
buildCmd.Flags().BoolVarP(&skipClone, "skip-clone", "g", false, "Skip cloning from git")
|
||||
buildCmd.Flags().BoolVarP(&packagesOnly, "packages-only", "p", false, "Only generate packages")
|
||||
buildCmd.Flags().BoolVarP(&verbose, "verbose", "v", false, "verbose - show more logs")
|
||||
}
|
||||
247
generator/cmd/docCmd.go
Normal file
247
generator/cmd/docCmd.go
Normal file
|
|
@ -0,0 +1,247 @@
|
|||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"os"
|
||||
"path"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strings"
|
||||
"text/template"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/generator/cmd/tools"
|
||||
)
|
||||
|
||||
var outFile string
|
||||
|
||||
var docsCmd = &cobra.Command{
|
||||
Use: "docs",
|
||||
Short: "handle documentation",
|
||||
Long: `...`,
|
||||
RunE: func(_ *cobra.Command, _ []string) error {
|
||||
// filePathStr := "stackit/internal/services/postgresflexalpha/database/datasources_gen/database_data_source_gen.go"
|
||||
//
|
||||
// src, err := os.ReadFile(filePathStr)
|
||||
// if err != nil {
|
||||
// return err
|
||||
//}
|
||||
//
|
||||
// i := interp.New(
|
||||
// interp.Options{
|
||||
// GoPath: "/home/henselinm/.asdf/installs/golang/1.25.6/packages",
|
||||
// BuildTags: nil,
|
||||
// Stdin: nil,
|
||||
// Stdout: nil,
|
||||
// Stderr: nil,
|
||||
// Args: nil,
|
||||
// Env: nil,
|
||||
// SourcecodeFilesystem: nil,
|
||||
// Unrestricted: false,
|
||||
// },
|
||||
//)
|
||||
// err = i.Use(i.Symbols("github.com/hashicorp/terraform-plugin-framework-validators"))
|
||||
// if err != nil {
|
||||
// return err
|
||||
//}
|
||||
// err = i.Use(stdlib.Symbols)
|
||||
// if err != nil {
|
||||
// return err
|
||||
//}
|
||||
// _, err = i.Eval(string(src))
|
||||
// if err != nil {
|
||||
// return err
|
||||
//}
|
||||
//
|
||||
// v, err := i.Eval("DatabaseDataSourceSchema")
|
||||
// if err != nil {
|
||||
// return err
|
||||
//}
|
||||
//
|
||||
// bar := v.Interface().(func(string) string)
|
||||
//
|
||||
// r := bar("Kung")
|
||||
// println(r)
|
||||
//
|
||||
// evalPath, err := i.EvalPath(filePathStr)
|
||||
// if err != nil {
|
||||
// return err
|
||||
//}
|
||||
//
|
||||
// fmt.Printf("%+v\n", evalPath)
|
||||
|
||||
// _, err = i.Eval(`import "fmt"`)
|
||||
// if err != nil {
|
||||
// return err
|
||||
//}
|
||||
// _, err = i.Eval(`func Hallo() { fmt.Println("Hi!") }`)
|
||||
// if err != nil {
|
||||
// return err
|
||||
//}
|
||||
|
||||
// v = i.Symbols("Hallo")
|
||||
|
||||
// fmt.Println(v)
|
||||
return workDocs()
|
||||
},
|
||||
}
|
||||
|
||||
type NavDocs struct {
|
||||
PageTitle string
|
||||
Description string
|
||||
NavigationTitle string
|
||||
ProviderTitle string
|
||||
IndexFound bool
|
||||
Services []Service
|
||||
}
|
||||
|
||||
type Service struct {
|
||||
ServiceTitle string
|
||||
DataSources []ResItem
|
||||
Resources []ResItem
|
||||
}
|
||||
|
||||
type ResItem struct {
|
||||
ItemName string
|
||||
ItemLink string
|
||||
}
|
||||
|
||||
func workDocs() error {
|
||||
slog.Info("creating docs navigation")
|
||||
root, err := tools.GetGitRoot()
|
||||
if err != nil {
|
||||
slog.Error("ERROR", "err", err)
|
||||
return err
|
||||
}
|
||||
|
||||
nav := NavDocs{
|
||||
PageTitle: "STACKIT terraform provider PRIVATE-PREVIEW",
|
||||
Description: "",
|
||||
NavigationTitle: "Navigation",
|
||||
ProviderTitle: "Provider",
|
||||
IndexFound: false,
|
||||
}
|
||||
startPath := path.Join(root, "docs")
|
||||
|
||||
docs, err := os.ReadDir(startPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
services := make(map[string]Service)
|
||||
dataSources := make(map[string][]ResItem)
|
||||
resources := make(map[string][]ResItem)
|
||||
|
||||
for _, entry := range docs {
|
||||
if !entry.IsDir() {
|
||||
if entry.Name() == "index.md" {
|
||||
slog.Debug(" found provider index file")
|
||||
nav.IndexFound = true
|
||||
continue
|
||||
}
|
||||
slog.Debug(" found am ignored file", "fileName", entry.Name())
|
||||
continue
|
||||
}
|
||||
|
||||
if entry.Name() != "data-sources" && entry.Name() != "resources" {
|
||||
slog.Error("unable to handle entry, skipping", "entry", entry.Name())
|
||||
continue
|
||||
}
|
||||
|
||||
elements, err := os.ReadDir(path.Join(startPath, entry.Name()))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, res := range elements {
|
||||
if res.IsDir() {
|
||||
slog.Warn("found unexpected directory", "dir", res.Name())
|
||||
continue
|
||||
}
|
||||
|
||||
re := regexp.MustCompile(`([a-z]+)_([a-z]+).md`)
|
||||
matches := re.FindAllStringSubmatch(res.Name(), -1)
|
||||
if matches == nil {
|
||||
slog.Error("unable to identify resource", "item", res.Name())
|
||||
continue
|
||||
}
|
||||
services[matches[0][1]] = Service{
|
||||
ServiceTitle: matches[0][1],
|
||||
}
|
||||
switch entry.Name() {
|
||||
case "data-sources":
|
||||
dataSources[matches[0][1]] = append(dataSources[matches[0][1]], ResItem{
|
||||
ItemName: matches[0][2],
|
||||
ItemLink: fmt.Sprintf("docs/%s/%s", entry.Name(), matches[0][0]),
|
||||
})
|
||||
case "resources":
|
||||
resources[matches[0][1]] = append(resources[matches[0][1]], ResItem{
|
||||
ItemName: matches[0][2],
|
||||
ItemLink: fmt.Sprintf("docs/%s/%s", entry.Name(), matches[0][0]),
|
||||
})
|
||||
default:
|
||||
return fmt.Errorf("this should never have happened")
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
keys := make([]string, 0, len(services))
|
||||
for k := range services {
|
||||
keys = append(keys, k)
|
||||
}
|
||||
sort.Strings(keys)
|
||||
|
||||
for _, name := range keys {
|
||||
item := services[name]
|
||||
item.DataSources = dataSources[name]
|
||||
item.Resources = resources[name]
|
||||
nav.Services = append(nav.Services, item)
|
||||
}
|
||||
|
||||
fn := template.FuncMap{
|
||||
"ucfirst": ucfirst,
|
||||
}
|
||||
|
||||
tmpl, err := template.
|
||||
New("nav.md.gompl").
|
||||
Funcs(fn).
|
||||
ParseFiles(path.Join(root, "generator", "cmd", "docs", "templates", "nav.md.gompl"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var f *os.File
|
||||
f, err = os.Create(outFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = tmpl.Execute(f, nav)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = f.Close()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
slog.Info("finished")
|
||||
return nil
|
||||
}
|
||||
|
||||
func NewDocsCmd() *cobra.Command {
|
||||
return docsCmd
|
||||
}
|
||||
|
||||
func ucfirst(s string) string {
|
||||
if s == "" {
|
||||
return ""
|
||||
}
|
||||
return strings.ToUpper(s[:1]) + s[1:]
|
||||
}
|
||||
|
||||
func init() { // nolint: gochecknoinits
|
||||
docsCmd.Flags().StringVarP(&outFile, "outFile", "o", "nav.md", "nav.md")
|
||||
}
|
||||
27
generator/cmd/docs/templates/nav.md.gompl
vendored
Normal file
27
generator/cmd/docs/templates/nav.md.gompl
vendored
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
---
|
||||
page_title: {{ .PageTitle }}
|
||||
description: {{ .Description }}
|
||||
---
|
||||
## {{ .NavigationTitle }}
|
||||
### {{ .ProviderTitle }}
|
||||
{{ if .IndexFound }}
|
||||
[Provider](/docs/docs/index.md)
|
||||
{{ end }}
|
||||
{{- range $index, $service := .Services }}
|
||||
### {{ $service.ServiceTitle }}
|
||||
<details>
|
||||
|
||||
#### data sources
|
||||
|
||||
{{- range $service.DataSources }}
|
||||
- [{{ .ItemName }}]({{ .ItemLink }})
|
||||
{{- end }}
|
||||
|
||||
#### resources
|
||||
|
||||
{{- range $service.Resources }}
|
||||
- [{{ .ItemName }}]({{ .ItemLink }})
|
||||
{{- end }}
|
||||
</details>
|
||||
|
||||
{{ end }}
|
||||
114
generator/cmd/examplesCmd.go
Normal file
114
generator/cmd/examplesCmd.go
Normal file
|
|
@ -0,0 +1,114 @@
|
|||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var examplesCmd = &cobra.Command{
|
||||
Use: "examples",
|
||||
Short: "create examples",
|
||||
Long: `...`,
|
||||
RunE: func(_ *cobra.Command, _ []string) error {
|
||||
// filePathStr := "stackit/internal/services/postgresflexalpha/database/datasources_gen/database_data_source_gen.go"
|
||||
//
|
||||
// src, err := os.ReadFile(filePathStr)
|
||||
// if err != nil {
|
||||
// return err
|
||||
//}
|
||||
//
|
||||
// i := interp.New(
|
||||
// interp.Options{
|
||||
// GoPath: "/home/henselinm/.asdf/installs/golang/1.25.6/packages",
|
||||
// BuildTags: nil,
|
||||
// Stdin: nil,
|
||||
// Stdout: nil,
|
||||
// Stderr: nil,
|
||||
// Args: nil,
|
||||
// Env: nil,
|
||||
// SourcecodeFilesystem: nil,
|
||||
// Unrestricted: false,
|
||||
// },
|
||||
//)
|
||||
// err = i.Use(i.Symbols("github.com/hashicorp/terraform-plugin-framework-validators"))
|
||||
// if err != nil {
|
||||
// return err
|
||||
//}
|
||||
// err = i.Use(stdlib.Symbols)
|
||||
// if err != nil {
|
||||
// return err
|
||||
//}
|
||||
// _, err = i.Eval(string(src))
|
||||
// if err != nil {
|
||||
// return err
|
||||
//}
|
||||
//
|
||||
// v, err := i.Eval("DatabaseDataSourceSchema")
|
||||
// if err != nil {
|
||||
// return err
|
||||
//}
|
||||
//
|
||||
// bar := v.Interface().(func(string) string)
|
||||
//
|
||||
// r := bar("Kung")
|
||||
// println(r)
|
||||
//
|
||||
// evalPath, err := i.EvalPath(filePathStr)
|
||||
// if err != nil {
|
||||
// return err
|
||||
//}
|
||||
//
|
||||
// fmt.Printf("%+v\n", evalPath)
|
||||
|
||||
// _, err = i.Eval(`import "fmt"`)
|
||||
// if err != nil {
|
||||
// return err
|
||||
//}
|
||||
// _, err = i.Eval(`func Hallo() { fmt.Println("Hi!") }`)
|
||||
// if err != nil {
|
||||
// return err
|
||||
//}
|
||||
|
||||
// v = i.Symbols("Hallo")
|
||||
|
||||
// fmt.Println(v)
|
||||
return workServices()
|
||||
},
|
||||
}
|
||||
|
||||
func workServices() error {
|
||||
startPath := path.Join("stackit", "internal", "services")
|
||||
|
||||
services, err := os.ReadDir(startPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, entry := range services {
|
||||
if !entry.IsDir() {
|
||||
continue
|
||||
}
|
||||
resources, err := os.ReadDir(path.Join(startPath, entry.Name()))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, res := range resources {
|
||||
if !res.IsDir() {
|
||||
continue
|
||||
}
|
||||
fmt.Println("Gefunden:", startPath, "subdir", entry.Name(), "resource", res.Name())
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func NewExamplesCmd() *cobra.Command {
|
||||
return examplesCmd
|
||||
}
|
||||
|
||||
// func init() { // nolint: gochecknoinits
|
||||
// examplesCmd.Flags().BoolVarP(&example, "example", "e", false, "example")
|
||||
//}
|
||||
|
|
@ -24,7 +24,7 @@ var getFieldsCmd = &cobra.Command{
|
|||
Use: "get-fields",
|
||||
Short: "get fields from file",
|
||||
Long: `...`,
|
||||
PreRunE: func(cmd *cobra.Command, args []string) error {
|
||||
PreRunE: func(_ *cobra.Command, _ []string) error {
|
||||
typeStr := "data_source"
|
||||
if resType != "resource" && resType != "datasource" {
|
||||
return fmt.Errorf("--type can only be resource or datasource")
|
||||
|
|
@ -75,14 +75,14 @@ var getFieldsCmd = &cobra.Command{
|
|||
filePath = p
|
||||
|
||||
//// Enum check
|
||||
//switch format {
|
||||
//case "json", "yaml":
|
||||
// switch format {
|
||||
// case "json", "yaml":
|
||||
//default:
|
||||
// return fmt.Errorf("invalid --format: %s (want json|yaml)", format)
|
||||
//}
|
||||
return nil
|
||||
},
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
RunE: func(_ *cobra.Command, _ []string) error {
|
||||
return getFields(filePath)
|
||||
},
|
||||
}
|
||||
|
|
@ -107,31 +107,26 @@ func getTokens(fileName string) ([]string, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
ast.Inspect(node, func(n ast.Node) bool {
|
||||
// Suche nach Typ-Deklarationen (structs)
|
||||
ts, ok := n.(*ast.TypeSpec)
|
||||
if ok {
|
||||
if strings.Contains(ts.Name.Name, "Model") {
|
||||
// fmt.Printf("found model: %s\n", ts.Name.Name)
|
||||
ast.Inspect(ts, func(sn ast.Node) bool {
|
||||
tts, tok := sn.(*ast.Field)
|
||||
if tok {
|
||||
// fmt.Printf(" found: %+v\n", tts.Names[0])
|
||||
// spew.Dump(tts.Type)
|
||||
|
||||
result = append(result, tts.Names[0].String())
|
||||
|
||||
//fld, fldOk := tts.Type.(*ast.Ident)
|
||||
//if fldOk {
|
||||
// fmt.Printf("type: %+v\n", fld)
|
||||
//}
|
||||
}
|
||||
return true
|
||||
})
|
||||
ast.Inspect(
|
||||
node, func(n ast.Node) bool {
|
||||
// Suche nach Typ-Deklarationen (structs)
|
||||
ts, ok := n.(*ast.TypeSpec)
|
||||
if ok {
|
||||
if strings.Contains(ts.Name.Name, "Model") {
|
||||
ast.Inspect(
|
||||
ts, func(sn ast.Node) bool {
|
||||
tts, tok := sn.(*ast.Field)
|
||||
if tok {
|
||||
result = append(result, tts.Names[0].String())
|
||||
}
|
||||
return true
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
})
|
||||
return true
|
||||
},
|
||||
)
|
||||
return result, nil
|
||||
}
|
||||
|
||||
|
|
@ -139,9 +134,15 @@ func NewGetFieldsCmd() *cobra.Command {
|
|||
return getFieldsCmd
|
||||
}
|
||||
|
||||
func init() { // nolint: gochecknoinits
|
||||
func init() { //nolint:gochecknoinits //this is the only way to add the command to the rootCmd
|
||||
getFieldsCmd.Flags().StringVarP(&inFile, "infile", "i", "", "input filename incl path")
|
||||
getFieldsCmd.Flags().StringVarP(&svcName, "service", "s", "", "service name")
|
||||
getFieldsCmd.Flags().StringVarP(&resName, "resource", "r", "", "resource name")
|
||||
getFieldsCmd.Flags().StringVarP(&resType, "type", "t", "resource", "resource type (data-source or resource [default])")
|
||||
getFieldsCmd.Flags().StringVarP(
|
||||
&resType,
|
||||
"type",
|
||||
"t",
|
||||
"resource",
|
||||
"resource type (data-source or resource [default])",
|
||||
)
|
||||
}
|
||||
|
|
@ -35,36 +35,27 @@ type GpgPublicKey struct {
|
|||
}
|
||||
|
||||
func (p *Provider) CreateArchitectureFiles() error {
|
||||
// var namespace, provider, distPath, repoName, version, gpgFingerprint, gpgPubKeyFile, domain string
|
||||
|
||||
log.Println("* Creating architecture files in target directories")
|
||||
|
||||
// filename = terraform-provider-[provider]_0.0.1_darwin_amd64.zip - provider_name + version + target + architecture + .zip
|
||||
// prefix := fmt.Sprintf("v1/providers/%s/%s/%s/", namespace, provider, version)
|
||||
prefix := path.Join("v1", "providers", p.Namespace, p.Provider, p.Version)
|
||||
|
||||
// pathPrefix := fmt.Sprintf("release/%s", prefix)
|
||||
pathPrefix := path.Join("release", prefix)
|
||||
|
||||
// urlPrefix := fmt.Sprintf("https://%s/%s", domain, prefix)
|
||||
urlPrefix, err := url.JoinPath("https://", p.Domain, prefix)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error creating base url: %w", err)
|
||||
}
|
||||
|
||||
// download url = https://example.com/v1/providers/namespace/provider/0.0.1/download/terraform-provider_0.0.1_darwin_amd64.zip
|
||||
downloadUrlPrefix, err := url.JoinPath(urlPrefix, "download")
|
||||
if err != nil {
|
||||
return fmt.Errorf("error crearting download url: %w", err)
|
||||
}
|
||||
downloadPathPrefix := path.Join(pathPrefix, "download")
|
||||
|
||||
// shasums url = https://example.com/v1/providers/namespace/provider/0.0.1/terraform-provider_0.0.1_SHA256SUMS
|
||||
shasumsUrl, err := url.JoinPath(urlPrefix, fmt.Sprintf("%s_%s_SHA256SUMS", p.RepoName, p.Version))
|
||||
if err != nil {
|
||||
return fmt.Errorf("error creating shasums url: %w", err)
|
||||
}
|
||||
// shasums_signature_url = https://example.com/v1/providers/namespace/provider/0.0.1/terraform-provider_0.0.1_SHA256SUMS.sig
|
||||
shasumsSigUrl := shasumsUrl + ".sig"
|
||||
|
||||
gpgAsciiPub, err := p.ReadGpgFile()
|
||||
|
|
@ -116,33 +107,6 @@ func (p *Provider) CreateArchitectureFiles() error {
|
|||
},
|
||||
},
|
||||
}
|
||||
// var architectureTemplate = []byte(fmt.Sprintf(`
|
||||
//{
|
||||
// "protocols": [
|
||||
// "4.0",
|
||||
// "5.1",
|
||||
// "6.0"
|
||||
// ],
|
||||
// "os": "%s",
|
||||
// "arch": "%s",
|
||||
// "filename": "%s",
|
||||
// "download_url": "%s",
|
||||
// "shasums_url": "%s",
|
||||
// "shasums_signature_url": "%s",
|
||||
// "shasum": "%s",
|
||||
// "signing_keys": {
|
||||
// "gpg_public_keys": [
|
||||
// {
|
||||
// "key_id": "%s",
|
||||
// "ascii_armor": "%s",
|
||||
// "trust_signature": "",
|
||||
// "source": "",
|
||||
// "source_url": ""
|
||||
// }
|
||||
// ]
|
||||
// }
|
||||
//}
|
||||
//`, target, arch, fileName, downloadUrl, shasumsUrl, shasumsSigUrl, shasum, gpgFingerprint, gpgAsciiPub))
|
||||
|
||||
log.Printf(" - Arch file: %s", archFileName)
|
||||
|
||||
|
|
@ -160,8 +124,12 @@ func WriteArchitectureFile(filePath string, arch Architecture) error {
|
|||
if err != nil {
|
||||
return fmt.Errorf("error encoding data: %w", err)
|
||||
}
|
||||
|
||||
err = os.WriteFile(filePath, jsonString, os.ModePerm)
|
||||
//nolint:gosec // this file is not sensitive, so we can use os.ModePerm
|
||||
err = os.WriteFile(
|
||||
filePath,
|
||||
jsonString,
|
||||
os.ModePerm,
|
||||
)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error writing data: %w", err)
|
||||
}
|
||||
|
|
@ -143,7 +143,7 @@ func (p *Provider) createVersionsFile() error {
|
|||
// Build the versions file...
|
||||
version := Version{
|
||||
Version: p.Version,
|
||||
Protocols: []string{"5.1"},
|
||||
Protocols: []string{"5.1", "6.1"},
|
||||
Platforms: nil,
|
||||
}
|
||||
for _, sum := range shasums {
|
||||
|
|
@ -161,10 +161,12 @@ func (p *Provider) createVersionsFile() error {
|
|||
target := fileNameSplit[2]
|
||||
arch := fileNameSplit[3]
|
||||
|
||||
version.Platforms = append(version.Platforms, Platform{
|
||||
OS: target,
|
||||
Arch: arch,
|
||||
})
|
||||
version.Platforms = append(
|
||||
version.Platforms, Platform{
|
||||
OS: target,
|
||||
Arch: arch,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
data := Data{}
|
||||
|
|
@ -206,16 +208,19 @@ func (p *Provider) CreateWellKnown() error {
|
|||
log.Println("* Creating .well-known directory")
|
||||
pathString := path.Join(p.RootPath, "release", ".well-known")
|
||||
|
||||
//nolint:gosec // this file is not sensitive, so we can use ModePerm
|
||||
err := os.MkdirAll(pathString, os.ModePerm)
|
||||
if err != nil && !errors.Is(err, fs.ErrExist) {
|
||||
return fmt.Errorf("error creating '%s' dir: %w", pathString, err)
|
||||
}
|
||||
|
||||
log.Println(" - Writing to .well-known/terraform.json file")
|
||||
|
||||
//nolint:gosec // this file is not sensitive, so we can use 0644
|
||||
err = os.WriteFile(
|
||||
fmt.Sprintf("%s/terraform.json", pathString),
|
||||
[]byte(`{"providers.v1": "/v1/providers/"}`),
|
||||
0644,
|
||||
0o644,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
@ -224,9 +229,10 @@ func (p *Provider) CreateWellKnown() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func CreateDir(path string) error {
|
||||
log.Printf("* Creating %s directory", path)
|
||||
err := os.MkdirAll(path, os.ModePerm)
|
||||
func CreateDir(pathValue string) error {
|
||||
log.Printf("* Creating %s directory", pathValue)
|
||||
//nolint:gosec // this file is not sensitive, so we can use ModePerm
|
||||
err := os.MkdirAll(pathValue, os.ModePerm)
|
||||
if errors.Is(err, fs.ErrExist) {
|
||||
return nil
|
||||
}
|
||||
|
|
@ -269,13 +275,23 @@ func CopyFile(src, dst string) (int64, error) {
|
|||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
defer source.Close()
|
||||
defer func(source *os.File) {
|
||||
err := source.Close()
|
||||
if err != nil {
|
||||
slog.Error("error closing source file", slog.Any("err", err))
|
||||
}
|
||||
}(source)
|
||||
|
||||
destination, err := os.Create(dst)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
defer destination.Close()
|
||||
defer func(destination *os.File) {
|
||||
err := destination.Close()
|
||||
if err != nil {
|
||||
slog.Error("error closing destination file", slog.Any("err", err))
|
||||
}
|
||||
}(destination)
|
||||
nBytes, err := io.Copy(destination, source)
|
||||
return nBytes, err
|
||||
}
|
||||
38
generator/cmd/publish/templates/Caddyfile
Normal file
38
generator/cmd/publish/templates/Caddyfile
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
{
|
||||
log {
|
||||
level debug
|
||||
}
|
||||
|
||||
|
||||
filesystem tf s3 {
|
||||
bucket "terraform-provider-privatepreview"
|
||||
region eu01
|
||||
endpoint https://object.storage.eu01.onstackit.cloud
|
||||
use_path_style
|
||||
}
|
||||
}
|
||||
|
||||
tfregistry.sysops.stackit.rocks {
|
||||
encode zstd gzip
|
||||
|
||||
handle_path /docs/* {
|
||||
root /srv/www
|
||||
templates
|
||||
|
||||
@md {
|
||||
file {path}
|
||||
path *.md
|
||||
}
|
||||
|
||||
rewrite @md /markdown.html
|
||||
|
||||
file_server {
|
||||
browse
|
||||
}
|
||||
}
|
||||
|
||||
file_server {
|
||||
fs tf
|
||||
browse
|
||||
}
|
||||
}
|
||||
|
|
@ -22,16 +22,25 @@ type Platform struct {
|
|||
}
|
||||
|
||||
type Data struct {
|
||||
Id string `json:"id,omitempty"`
|
||||
Versions []Version `json:"versions"`
|
||||
}
|
||||
|
||||
func (d *Data) WriteToFile(filePath string) error {
|
||||
// TODO: make it variable
|
||||
d.Id = "tfregistry.sysops.stackit.rocks/mhenselin/stackitprivatepreview"
|
||||
|
||||
jsonString, err := json.Marshal(d)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error encoding data: %w", err)
|
||||
}
|
||||
|
||||
err = os.WriteFile(filePath, jsonString, os.ModePerm)
|
||||
//nolint:gosec // this file is not sensitive, so we can use os.ModePerm
|
||||
err = os.WriteFile(
|
||||
filePath,
|
||||
jsonString,
|
||||
os.ModePerm,
|
||||
)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error writing data: %w", err)
|
||||
}
|
||||
|
|
@ -82,7 +91,13 @@ func (d *Data) LoadFromUrl(uri string) error {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer os.Remove(file.Name()) // Clean up
|
||||
defer func(name string) {
|
||||
//nolint:gosec // The file path is generated by os.CreateTemp and is not user-controllable
|
||||
err := os.Remove(name)
|
||||
if err != nil {
|
||||
slog.Error("failed to remove temporary file", slog.Any("err", err))
|
||||
}
|
||||
}(file.Name()) // Clean up
|
||||
|
||||
err = DownloadFile(
|
||||
u.String(),
|
||||
|
|
@ -119,20 +134,30 @@ func (v *Version) AddProtocol(p string) error {
|
|||
// DownloadFile will download a url and store it in local filepath.
|
||||
// It writes to the destination file as it downloads it, without
|
||||
// loading the entire file into memory.
|
||||
func DownloadFile(url string, filepath string) error {
|
||||
func DownloadFile(urlValue, filepath string) error {
|
||||
// Create the file
|
||||
//nolint:gosec // path traversal is not a concern here, as the filepath is generated by us and not user input
|
||||
out, err := os.Create(filepath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer out.Close()
|
||||
defer func(out *os.File) {
|
||||
err := out.Close()
|
||||
if err != nil {
|
||||
slog.Error("failed to close file", slog.Any("err", err))
|
||||
}
|
||||
}(out)
|
||||
|
||||
// Get the data
|
||||
resp, err := http.Get(url)
|
||||
|
||||
//nolint:gosec,bodyclose // this is a controlled URL, not user input
|
||||
resp, err := http.Get(urlValue)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
defer func(Body io.ReadCloser) {
|
||||
_ = Body.Close()
|
||||
}(resp.Body)
|
||||
|
||||
// Write the body to file
|
||||
_, err = io.Copy(out, resp.Body)
|
||||
|
|
@ -10,7 +10,8 @@ import (
|
|||
"path/filepath"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
publish2 "tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/cmd/cmd/publish"
|
||||
|
||||
publish2 "tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/generator/cmd/publish"
|
||||
)
|
||||
|
||||
var (
|
||||
|
|
@ -28,20 +29,32 @@ var publishCmd = &cobra.Command{
|
|||
Use: "publish",
|
||||
Short: "Publish terraform provider",
|
||||
Long: `...`,
|
||||
RunE: func(_ *cobra.Command, args []string) error {
|
||||
RunE: func(_ *cobra.Command, _ []string) error {
|
||||
return publish()
|
||||
},
|
||||
}
|
||||
|
||||
func init() { // nolint: gochecknoinits
|
||||
func init() { //nolint:gochecknoinits //this is the standard way to set up cobra commands
|
||||
publishCmd.Flags().StringVarP(&namespace, "namespace", "n", "", "Namespace for the Terraform registry.")
|
||||
publishCmd.Flags().StringVarP(&domain, "domain", "d", "", "Domain for the Terraform registry.")
|
||||
publishCmd.Flags().StringVarP(&providerName, "providerName", "p", "", "ProviderName for the Terraform registry.")
|
||||
publishCmd.Flags().StringVarP(&distPath, "distPath", "x", "dist", "Dist Path for the Terraform registry.")
|
||||
publishCmd.Flags().StringVarP(&repoName, "repoName", "r", "", "RepoName for the Terraform registry.")
|
||||
publishCmd.Flags().StringVarP(&version, "version", "v", "", "Version for the Terraform registry.")
|
||||
publishCmd.Flags().StringVarP(&gpgFingerprint, "gpgFingerprint", "f", "", "GPG Fingerprint for the Terraform registry.")
|
||||
publishCmd.Flags().StringVarP(&gpgPubKeyFile, "gpgPubKeyFile", "k", "", "GPG PubKey file name for the Terraform registry.")
|
||||
publishCmd.Flags().StringVarP(
|
||||
&gpgFingerprint,
|
||||
"gpgFingerprint",
|
||||
"f",
|
||||
"",
|
||||
"GPG Fingerprint for the Terraform registry.",
|
||||
)
|
||||
publishCmd.Flags().StringVarP(
|
||||
&gpgPubKeyFile,
|
||||
"gpgPubKeyFile",
|
||||
"k",
|
||||
"",
|
||||
"GPG PubKey file name for the Terraform registry.",
|
||||
)
|
||||
|
||||
err := publishCmd.MarkFlagRequired("namespace")
|
||||
if err != nil {
|
||||
|
|
@ -104,6 +117,7 @@ func publish() error {
|
|||
|
||||
// Create release dir - only the contents of this need to be uploaded to S3
|
||||
log.Printf("* Creating release directory")
|
||||
//nolint:gosec // this directory is not sensitive, so we can use 0750
|
||||
err = os.MkdirAll(path.Join(p.RootPath, "release"), os.ModePerm)
|
||||
if err != nil && !errors.Is(err, fs.ErrExist) {
|
||||
return fmt.Errorf("error creating '%s' dir: %w", path.Join(p.RootPath, "release"), err)
|
||||
|
|
@ -6,7 +6,7 @@ import (
|
|||
|
||||
func NewRootCmd() *cobra.Command {
|
||||
return &cobra.Command{
|
||||
Use: "build-tools",
|
||||
Use: "generator",
|
||||
Short: "...",
|
||||
Long: "...",
|
||||
SilenceErrors: true, // Error is beautified in a custom way before being printed
|
||||
20
generator/cmd/tools/tools.go
Normal file
20
generator/cmd/tools/tools.go
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
package tools
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os/exec"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func GetGitRoot() (string, error) {
|
||||
cmd := exec.Command("git", "rev-parse", "--show-toplevel")
|
||||
out, err := cmd.Output()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
lines := strings.Split(string(out), "\n")
|
||||
if lines[0] == "" {
|
||||
return "", fmt.Errorf("unable to determine root directory from git")
|
||||
}
|
||||
return lines[0], nil
|
||||
}
|
||||
|
|
@ -5,9 +5,10 @@ import (
|
|||
"log/slog"
|
||||
"os"
|
||||
|
||||
"github.com/MatusOllah/slogcolor"
|
||||
"github.com/SladkyCitron/slogcolor"
|
||||
cc "github.com/ivanpirog/coloredcobra"
|
||||
"tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/cmd/cmd"
|
||||
|
||||
"tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/generator/cmd"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
|
@ -29,6 +30,8 @@ func main() {
|
|||
cmd.NewBuildCmd(),
|
||||
cmd.NewPublishCmd(),
|
||||
cmd.NewGetFieldsCmd(),
|
||||
cmd.NewExamplesCmd(),
|
||||
cmd.NewDocsCmd(),
|
||||
)
|
||||
|
||||
err := rootCmd.Execute()
|
||||
257
go.mod
257
go.mod
|
|
@ -3,85 +3,286 @@ module tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stac
|
|||
go 1.25.6
|
||||
|
||||
require (
|
||||
github.com/MatusOllah/slogcolor v1.7.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/uuid v1.6.0
|
||||
github.com/hashicorp/terraform-plugin-framework v1.17.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-go v0.29.0
|
||||
github.com/hashicorp/terraform-plugin-go v0.30.0
|
||||
github.com/hashicorp/terraform-plugin-log v0.10.0
|
||||
github.com/hashicorp/terraform-plugin-testing v1.14.0
|
||||
github.com/iancoleman/strcase v0.3.0
|
||||
github.com/ivanpirog/coloredcobra v1.0.1
|
||||
github.com/jarcoal/httpmock v1.4.1
|
||||
github.com/joho/godotenv v1.5.1
|
||||
github.com/ldez/go-git-cmd-wrapper/v2 v2.9.1
|
||||
github.com/spf13/cobra v1.10.2
|
||||
github.com/stackitcloud/stackit-sdk-go/core v0.21.0
|
||||
github.com/stackitcloud/stackit-sdk-go/services/iaasalpha v0.1.23-alpha
|
||||
github.com/stackitcloud/stackit-sdk-go/services/sqlserverflex v1.4.1
|
||||
github.com/stackitcloud/stackit-sdk-go/core v0.22.0
|
||||
github.com/stackitcloud/stackit-sdk-go/services/postgresflex v1.4.0
|
||||
github.com/stackitcloud/stackit-sdk-go/services/sqlserverflex v1.5.0
|
||||
github.com/teambition/rrule-go v1.8.2
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/hashicorp/go-retryablehttp v0.7.8 // indirect
|
||||
golang.org/x/telemetry v0.0.0-20260116145544-c6413dc483f5 // indirect
|
||||
)
|
||||
require github.com/hashicorp/go-retryablehttp v0.7.8 // indirect
|
||||
|
||||
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
|
||||
github.com/ProtonMail/go-crypto v1.3.0 // 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/Masterminds/goutils v1.1.1 // indirect
|
||||
github.com/Masterminds/semver/v3 v3.4.0 // indirect
|
||||
github.com/Masterminds/sprig/v3 v3.2.3 // 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/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/cloudflare/circl v1.6.2 // 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/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/curioswitch/go-reassign v0.3.0 // 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/golang-jwt/jwt/v5 v5.3.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/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/errwrap v1.1.0 // indirect
|
||||
github.com/hashicorp/go-checkpoint v0.5.0 // indirect
|
||||
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
|
||||
github.com/hashicorp/go-cty v1.5.0 // 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-plugin v1.7.0 // indirect
|
||||
github.com/hashicorp/go-uuid v1.0.3 // indirect
|
||||
github.com/hashicorp/go-version v1.8.0 // indirect
|
||||
github.com/hashicorp/hc-install v0.9.2 // 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/logutils v1.0.0 // indirect
|
||||
github.com/hashicorp/terraform-exec v0.24.0 // indirect
|
||||
github.com/hashicorp/terraform-exec v0.25.0 // indirect
|
||||
github.com/hashicorp/terraform-json v0.27.2 // indirect
|
||||
github.com/hashicorp/terraform-plugin-sdk/v2 v2.38.1 // indirect
|
||||
github.com/hashicorp/terraform-plugin-docs v0.24.0 // 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-svchost v0.2.0 // indirect
|
||||
github.com/hashicorp/terraform-svchost v0.2.1 // 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/imdario/mergo v0.3.15 // 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-isatty v0.0.20 // 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/go-homedir v1.1.0 // indirect
|
||||
github.com/mitchellh/go-testing-interface v1.14.1 // indirect
|
||||
github.com/mitchellh/go-wordwrap v1.0.1 // indirect
|
||||
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
||||
github.com/mitchellh/reflectwalk v1.0.2 // indirect
|
||||
github.com/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/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/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/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/jwalterweatherman v1.1.0 // 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/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/v5 v5.4.1 // indirect
|
||||
github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect
|
||||
github.com/zclconf/go-cty v1.17.0 // indirect
|
||||
golang.org/x/crypto v0.47.0 // indirect
|
||||
golang.org/x/mod v0.32.0 // indirect
|
||||
golang.org/x/net v0.49.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-meta v1.1.0 // 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.augendre.info/arangolint v0.4.0 // indirect
|
||||
go.augendre.info/fatcontext v0.9.0 // indirect
|
||||
go.uber.org/multierr v1.10.0 // indirect
|
||||
go.uber.org/zap v1.27.0 // indirect
|
||||
go.yaml.in/yaml/v3 v3.0.4 // indirect
|
||||
golang.org/x/crypto v0.48.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b // 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.40.0 // indirect
|
||||
golang.org/x/text v0.33.0 // indirect
|
||||
golang.org/x/tools v0.41.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/genproto/googleapis/rpc v0.0.0-20260120221211-b8f7ae30c516 // indirect
|
||||
google.golang.org/grpc v1.78.0 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260226221140-a57be14db171 // indirect
|
||||
google.golang.org/grpc v1.79.2 // 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
|
||||
honnef.co/go/tools v0.7.0 // indirect
|
||||
mvdan.cc/gofumpt v0.9.2 // indirect
|
||||
mvdan.cc/unparam v0.0.0-20251027182757-5beb8c8f8f15 // indirect
|
||||
)
|
||||
|
||||
tool golang.org/x/tools/cmd/goimports
|
||||
|
|
|
|||
97
golang-ci.yaml.bak
Normal file
97
golang-ci.yaml.bak
Normal file
|
|
@ -0,0 +1,97 @@
|
|||
|
||||
version: "2"
|
||||
run:
|
||||
concurrency: 4
|
||||
output:
|
||||
formats:
|
||||
text:
|
||||
print-linter-name: true
|
||||
print-issued-lines: true
|
||||
colors: true
|
||||
path: stdout
|
||||
linters:
|
||||
enable:
|
||||
- bodyclose
|
||||
- depguard
|
||||
- errorlint
|
||||
- forcetypeassert
|
||||
- gochecknoinits
|
||||
- gocritic
|
||||
- gosec
|
||||
- misspell
|
||||
- nakedret
|
||||
- revive
|
||||
- sqlclosecheck
|
||||
- wastedassign
|
||||
disable:
|
||||
- noctx
|
||||
- unparam
|
||||
settings:
|
||||
depguard:
|
||||
rules:
|
||||
main:
|
||||
list-mode: lax
|
||||
allow:
|
||||
- tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview
|
||||
- github.com/hashicorp/terraform-plugin-framework
|
||||
- github.com/hashicorp/terraform-plugin-log
|
||||
- github.com/stackitcloud/stackit-sdk-go
|
||||
deny:
|
||||
- pkg: github.com/stretchr/testify
|
||||
desc: Do not use a testing framework
|
||||
gocritic:
|
||||
disabled-checks:
|
||||
- wrapperFunc
|
||||
- typeDefFirst
|
||||
- ifElseChain
|
||||
- dupImport
|
||||
- hugeParam
|
||||
enabled-tags:
|
||||
- performance
|
||||
- style
|
||||
- experimental
|
||||
gosec:
|
||||
excludes:
|
||||
- G104
|
||||
- G102
|
||||
- G304
|
||||
- G307
|
||||
misspell:
|
||||
locale: US
|
||||
nakedret:
|
||||
max-func-lines: 0
|
||||
revive:
|
||||
severity: error
|
||||
rules:
|
||||
- name: errorf
|
||||
- name: context-as-argument
|
||||
- name: error-return
|
||||
- name: increment-decrement
|
||||
- name: indent-error-flow
|
||||
- name: superfluous-else
|
||||
- name: unused-parameter
|
||||
- name: unreachable-code
|
||||
- name: atomic
|
||||
- name: empty-lines
|
||||
- name: early-return
|
||||
exclusions:
|
||||
paths:
|
||||
- stackit-sdk-generator/
|
||||
- generated/
|
||||
- pkg_gen/
|
||||
generated: lax
|
||||
warn-unused: true
|
||||
# Excluding configuration per-path, per-linter, per-text and per-source.
|
||||
rules:
|
||||
# Exclude some linters from running on tests files.
|
||||
- path: _test\.go
|
||||
linters:
|
||||
- gochecknoinits
|
||||
formatters:
|
||||
enable:
|
||||
- gofmt
|
||||
- goimports
|
||||
settings:
|
||||
goimports:
|
||||
local-prefixes:
|
||||
- tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview
|
||||
39
internal/testutils/activateMocks.go
Normal file
39
internal/testutils/activateMocks.go
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
package testutils
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
"github.com/jarcoal/httpmock"
|
||||
)
|
||||
|
||||
func TestName() string {
|
||||
pc, _, _, _ := runtime.Caller(1)
|
||||
nameFull := runtime.FuncForPC(pc).Name()
|
||||
nameEnd := filepath.Ext(nameFull)
|
||||
name := strings.TrimPrefix(nameEnd, ".")
|
||||
return name
|
||||
}
|
||||
|
||||
func ActivateEnvironmentHttpMocks() {
|
||||
httpmock.RegisterNoResponder(
|
||||
func(req *http.Request) (*http.Response, error) {
|
||||
return nil, fmt.Errorf("no responder found for %s %s, please check your http mocks", req.Method, req.URL)
|
||||
},
|
||||
)
|
||||
|
||||
httpmock.RegisterRegexpResponder(
|
||||
"GET",
|
||||
regexp.MustCompile(`^https://api\.bap\.microsoft\.com/providers/Microsoft\.BusinessAppPlatform/locations/(europe|unitedstates)/environmentLanguages\?api-version=2023-06-01$`),
|
||||
func(_ *http.Request) (*http.Response, error) {
|
||||
return httpmock.NewStringResponse(
|
||||
http.StatusOK,
|
||||
httpmock.File("../../services/languages/tests/datasource/Validate_Read/get_languages.json").String(),
|
||||
), nil
|
||||
},
|
||||
)
|
||||
}
|
||||
129
internal/testutils/functions.go
Normal file
129
internal/testutils/functions.go
Normal file
|
|
@ -0,0 +1,129 @@
|
|||
package testutils
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
"testing"
|
||||
"text/template"
|
||||
)
|
||||
|
||||
// GetHomeEnvVariableName Helper function to obtain the home directory on different systems.
|
||||
// Based on os.UserHomeDir().
|
||||
func GetHomeEnvVariableName() string {
|
||||
env := "HOME"
|
||||
switch runtime.GOOS {
|
||||
case "windows":
|
||||
env = "USERPROFILE"
|
||||
case "plan9":
|
||||
env = "home"
|
||||
}
|
||||
return env
|
||||
}
|
||||
|
||||
// CreateTemporaryHome create temporary home and initialize the credentials file as well
|
||||
func CreateTemporaryHome(createValidCredentialsFile bool, t *testing.T) string {
|
||||
// create a temporary file
|
||||
tempHome, err := os.MkdirTemp("", "tempHome")
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create temporary home directory: %v", err)
|
||||
}
|
||||
|
||||
// create credentials file in temp directory
|
||||
stackitFolder := path.Join(tempHome, ".stackit")
|
||||
if err := os.Mkdir(stackitFolder, 0o750); err != nil {
|
||||
t.Fatalf("Failed to create stackit folder: %v", err)
|
||||
}
|
||||
|
||||
filePath := path.Join(stackitFolder, "credentials.json")
|
||||
file, err := os.Create(filePath)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create credentials file: %v", err)
|
||||
}
|
||||
defer func() {
|
||||
if err := file.Close(); err != nil {
|
||||
t.Fatalf("Error while closing the file: %v", err)
|
||||
}
|
||||
}()
|
||||
|
||||
// Define content, default = invalid token
|
||||
token := "foo_token"
|
||||
// if createValidCredentialsFile {
|
||||
// token = GetTestProjectServiceAccountJson("")
|
||||
//}
|
||||
if _, err = file.WriteString(token); err != nil {
|
||||
t.Fatalf("Error writing to file: %v", err)
|
||||
}
|
||||
|
||||
return tempHome
|
||||
}
|
||||
|
||||
// SetTemporaryHome Function to overwrite the home folder
|
||||
func SetTemporaryHome(tempHomePath string) {
|
||||
env := GetHomeEnvVariableName()
|
||||
if err := os.Setenv(env, tempHomePath); err != nil {
|
||||
fmt.Printf("Error setting temporary home directory %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// CleanupTemporaryHome cleanup the temporary home and reset the environment variable
|
||||
func CleanupTemporaryHome(tempHomePath string, t *testing.T) {
|
||||
if err := os.RemoveAll(tempHomePath); err != nil {
|
||||
t.Fatalf("Error cleaning up temporary folder: %v", err)
|
||||
}
|
||||
originalHomeDir, err := os.UserHomeDir()
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to restore home directory back to normal: %v", err)
|
||||
}
|
||||
// revert back to original home folder
|
||||
env := GetHomeEnvVariableName()
|
||||
if err := os.Setenv(env, originalHomeDir); err != nil {
|
||||
fmt.Printf("Error resetting temporary home directory %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func ucFirst(s string) string {
|
||||
if s == "" {
|
||||
return ""
|
||||
}
|
||||
return strings.ToUpper(s[:1]) + s[1:]
|
||||
}
|
||||
|
||||
func StringFromTemplateMust(tplFile string, data any) string {
|
||||
res, err := StringFromTemplate(tplFile, data)
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
func StringFromTemplate(tplFile string, data any) (string, error) {
|
||||
fn := template.FuncMap{
|
||||
"ucfirst": ucFirst,
|
||||
}
|
||||
|
||||
file := filepath.Base(tplFile)
|
||||
|
||||
tmpl, err := template.New(file).Funcs(fn).ParseFiles(tplFile)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
tplBuf := &bytes.Buffer{}
|
||||
|
||||
err = tmpl.Execute(tplBuf, data)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return tplBuf.String(), nil
|
||||
}
|
||||
|
||||
func ResStr(prefix, resource, name string) string {
|
||||
return fmt.Sprintf("%s_%s.%s", prefix, resource, name)
|
||||
}
|
||||
|
|
@ -1,73 +1,11 @@
|
|||
// Copyright (c) STACKIT
|
||||
|
||||
package testutil
|
||||
package testutils
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/terraform-plugin-framework/providerserver"
|
||||
"github.com/hashicorp/terraform-plugin-go/tfprotov6"
|
||||
"github.com/hashicorp/terraform-plugin-testing/config"
|
||||
"github.com/hashicorp/terraform-plugin-testing/echoprovider"
|
||||
|
||||
"tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit"
|
||||
)
|
||||
|
||||
const (
|
||||
// Default location of credentials JSON
|
||||
// credentialsFilePath = ".stackit/credentials.json" //nolint:gosec // linter false positive
|
||||
serviceAccountFilePath = ".stackit/service_account.json"
|
||||
)
|
||||
|
||||
var (
|
||||
// TestAccProtoV6ProviderFactories is used to instantiate a provider during
|
||||
// acceptance testing. The factory function will be invoked for every Terraform
|
||||
// CLI command executed to create a provider server to which the CLI can
|
||||
// reattach.
|
||||
TestAccProtoV6ProviderFactories = map[string]func() (tfprotov6.ProviderServer, error){
|
||||
"stackitprivatepreview": providerserver.NewProtocol6WithError(stackit.New("test-version")()),
|
||||
}
|
||||
|
||||
// TestEphemeralAccProtoV6ProviderFactories is used to instantiate a provider during
|
||||
// acceptance testing. The factory function will be invoked for every Terraform
|
||||
// CLI command executed to create a provider server to which the CLI can
|
||||
// reattach.
|
||||
//
|
||||
// See the Terraform acceptance test documentation on ephemeral resources for more information:
|
||||
// https://developer.hashicorp.com/terraform/plugin/testing/acceptance-tests/ephemeral-resources
|
||||
TestEphemeralAccProtoV6ProviderFactories = map[string]func() (tfprotov6.ProviderServer, error){
|
||||
"stackitprivatepreview": providerserver.NewProtocol6WithError(stackit.New("test-version")()),
|
||||
"echo": echoprovider.NewProviderServer(),
|
||||
}
|
||||
|
||||
// E2ETestsEnabled checks if end-to-end tests should be run.
|
||||
// It is enabled when the TF_ACC environment variable is set to "1".
|
||||
E2ETestsEnabled = os.Getenv("TF_ACC") == "1"
|
||||
// OrganizationId is the id of organization used for tests
|
||||
OrganizationId = os.Getenv("TF_ACC_ORGANIZATION_ID")
|
||||
// ProjectId is the id of project used for tests
|
||||
ProjectId = os.Getenv("TF_ACC_PROJECT_ID")
|
||||
Region = os.Getenv("TF_ACC_REGION")
|
||||
// ServiceAccountFile is the json file of the service account
|
||||
ServiceAccountFile = os.Getenv("TF_ACC_SERVICE_ACCOUNT_FILE")
|
||||
// ServerId is the id of a server used for some tests
|
||||
ServerId = getenv("TF_ACC_SERVER_ID", "")
|
||||
// TestProjectParentContainerID is the container id of the parent resource under which projects are created as part of the resource-manager acceptance tests
|
||||
TestProjectParentContainerID = os.Getenv("TF_ACC_TEST_PROJECT_PARENT_CONTAINER_ID")
|
||||
// TestProjectParentUUID is the uuid of the parent resource under which projects are created as part of the resource-manager acceptance tests
|
||||
TestProjectParentUUID = os.Getenv("TF_ACC_TEST_PROJECT_PARENT_UUID")
|
||||
// TestProjectServiceAccountEmail is the e-mail of a service account with admin permissions on the organization under which projects are created as part of the resource-manager acceptance tests
|
||||
TestProjectServiceAccountEmail = os.Getenv("TF_ACC_TEST_PROJECT_SERVICE_ACCOUNT_EMAIL")
|
||||
// TestProjectUserEmail is the e-mail of a user for the project created as part of the resource-manager acceptance tests
|
||||
// Default email: acc-test@sa.stackit.cloud
|
||||
TestProjectUserEmail = getenv("TF_ACC_TEST_PROJECT_USER_EMAIL", "acc-test@sa.stackit.cloud")
|
||||
// TestImageLocalFilePath is the local path to an image file used for image acceptance tests
|
||||
TestImageLocalFilePath = getenv("TF_ACC_TEST_IMAGE_LOCAL_FILE_PATH", "default")
|
||||
|
||||
CdnCustomEndpoint = os.Getenv("TF_ACC_CDN_CUSTOM_ENDPOINT")
|
||||
DnsCustomEndpoint = os.Getenv("TF_ACC_DNS_CUSTOM_ENDPOINT")
|
||||
GitCustomEndpoint = os.Getenv("TF_ACC_GIT_CUSTOM_ENDPOINT")
|
||||
|
|
@ -95,8 +33,6 @@ var (
|
|||
SKECustomEndpoint = os.Getenv("TF_ACC_SKE_CUSTOM_ENDPOINT")
|
||||
)
|
||||
|
||||
// Provider config helper functions
|
||||
|
||||
func ObservabilityProviderConfig() string {
|
||||
if ObservabilityCustomEndpoint == "" {
|
||||
return `provider "stackitprivatepreview" {
|
||||
|
|
@ -357,25 +293,24 @@ func RedisProviderConfig() string {
|
|||
)
|
||||
}
|
||||
|
||||
func ResourceManagerProviderConfig() string {
|
||||
key := GetTestProjectServiceAccountJson("")
|
||||
func ResourceManagerProviderConfig(saKeyPath string) string {
|
||||
if ResourceManagerCustomEndpoint == "" || AuthorizationCustomEndpoint == "" {
|
||||
return fmt.Sprintf(`
|
||||
provider "stackitprivatepreview" {
|
||||
service_account_key = "%s"
|
||||
service_account_key_path = "%s"
|
||||
}`,
|
||||
key,
|
||||
saKeyPath,
|
||||
)
|
||||
}
|
||||
return fmt.Sprintf(`
|
||||
provider "stackitprivatepreview" {
|
||||
resourcemanager_custom_endpoint = "%s"
|
||||
authorization_custom_endpoint = "%s"
|
||||
service_account_token = "%s"
|
||||
service_account_key_path = "%s"
|
||||
}`,
|
||||
ResourceManagerCustomEndpoint,
|
||||
AuthorizationCustomEndpoint,
|
||||
key,
|
||||
saKeyPath,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -527,127 +462,3 @@ func ScfProviderConfig() string {
|
|||
ScfCustomEndpoint,
|
||||
)
|
||||
}
|
||||
|
||||
func ResourceNameWithDateTime(name string) string {
|
||||
dateTime := time.Now().Format(time.RFC3339)
|
||||
// Remove timezone to have a smaller datetime
|
||||
dateTimeTrimmed, _, _ := strings.Cut(dateTime, "+")
|
||||
return fmt.Sprintf("tf-acc-%s-%s", name, dateTimeTrimmed)
|
||||
}
|
||||
|
||||
func GetTestProjectServiceAccountJson(path string) string {
|
||||
var err error
|
||||
token, tokenSet := os.LookupEnv("TF_ACC_TEST_PROJECT_SERVICE_ACCOUNT_JSON")
|
||||
if !tokenSet || token == "" {
|
||||
token, err = readTestServiceAccountJsonFromFile(path)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
}
|
||||
return token
|
||||
}
|
||||
|
||||
//func GetTestProjectServiceAccountToken(path string) string {
|
||||
// var err error
|
||||
// token, tokenSet := os.LookupEnv("TF_ACC_TEST_PROJECT_SERVICE_ACCOUNT_TOKEN")
|
||||
// if !tokenSet || token == "" {
|
||||
// token, err = readTestTokenFromCredentialsFile(path)
|
||||
// if err != nil {
|
||||
// return ""
|
||||
// }
|
||||
// }
|
||||
// return token
|
||||
//}
|
||||
//
|
||||
//func readTestTokenFromCredentialsFile(path string) (string, error) {
|
||||
// if path == "" {
|
||||
// customPath, customPathSet := os.LookupEnv("STACKIT_CREDENTIALS_PATH")
|
||||
// if !customPathSet || customPath == "" {
|
||||
// path = credentialsFilePath
|
||||
// home, err := os.UserHomeDir()
|
||||
// if err != nil {
|
||||
// return "", fmt.Errorf("getting home directory: %w", err)
|
||||
// }
|
||||
// path = filepath.Join(home, path)
|
||||
// } else {
|
||||
// path = customPath
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// credentialsRaw, err := os.ReadFile(path)
|
||||
// if err != nil {
|
||||
// return "", fmt.Errorf("opening file: %w", err)
|
||||
// }
|
||||
//
|
||||
// var credentials struct {
|
||||
// TF_ACC_TEST_PROJECT_SERVICE_ACCOUNT_TOKEN string `json:"TF_ACC_TEST_PROJECT_SERVICE_ACCOUNT_TOKEN"`
|
||||
// }
|
||||
// err = json.Unmarshal(credentialsRaw, &credentials)
|
||||
// if err != nil {
|
||||
// return "", fmt.Errorf("unmarshalling credentials: %w", err)
|
||||
// }
|
||||
// return credentials.TF_ACC_TEST_PROJECT_SERVICE_ACCOUNT_TOKEN, nil
|
||||
//}
|
||||
|
||||
func readTestServiceAccountJsonFromFile(path string) (string, error) {
|
||||
if path == "" {
|
||||
customPath, customPathSet := os.LookupEnv("STACKIT_SERVICE_ACCOUNT_PATH")
|
||||
if !customPathSet || customPath == "" {
|
||||
path = serviceAccountFilePath
|
||||
home, err := os.UserHomeDir()
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("getting home directory: %w", err)
|
||||
}
|
||||
path = filepath.Join(home, path)
|
||||
} else {
|
||||
path = customPath
|
||||
}
|
||||
}
|
||||
|
||||
credentialsRaw, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("opening file: %w", err)
|
||||
}
|
||||
return string(credentialsRaw), nil
|
||||
}
|
||||
|
||||
func getenv(key, defaultValue string) string {
|
||||
val := os.Getenv(key)
|
||||
if val == "" {
|
||||
return defaultValue
|
||||
}
|
||||
return val
|
||||
}
|
||||
|
||||
// CreateDefaultLocalFile is a helper for local_file_path. No real data is created
|
||||
func CreateDefaultLocalFile() os.File {
|
||||
// Define the file name and size
|
||||
fileName := "test-512k.img"
|
||||
size := 512 * 1024 // 512 KB
|
||||
|
||||
// Create the file
|
||||
file, err := os.Create(fileName)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// Seek to the desired position (512 KB)
|
||||
_, err = file.Seek(int64(size), 0)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return *file
|
||||
}
|
||||
|
||||
func ConvertConfigVariable(variable config.Variable) string {
|
||||
tmpByteArray, _ := variable.MarshalJSON()
|
||||
// In case the variable is a string, the quotes should be removed
|
||||
if tmpByteArray[0] == '"' && tmpByteArray[len(tmpByteArray)-1] == '"' {
|
||||
result := string(tmpByteArray[1 : len(tmpByteArray)-1])
|
||||
// Replace escaped quotes which where added MarshalJSON
|
||||
rawString := strings.ReplaceAll(result, `\"`, `"`)
|
||||
return rawString
|
||||
}
|
||||
return string(tmpByteArray)
|
||||
}
|
||||
220
internal/testutils/testutils.go
Normal file
220
internal/testutils/testutils.go
Normal file
|
|
@ -0,0 +1,220 @@
|
|||
package testutils
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"log/slog"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/terraform-plugin-framework/providerserver"
|
||||
"github.com/hashicorp/terraform-plugin-go/tfprotov6"
|
||||
"github.com/hashicorp/terraform-plugin-testing/config"
|
||||
"github.com/hashicorp/terraform-plugin-testing/echoprovider"
|
||||
"github.com/joho/godotenv"
|
||||
|
||||
"tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit"
|
||||
)
|
||||
|
||||
const (
|
||||
// Default location of service account JSON
|
||||
serviceAccountFilePath = "service_account.json"
|
||||
)
|
||||
|
||||
var (
|
||||
// TestAccProtoV6ProviderFactories is used to instantiate a provider during
|
||||
// acceptance testing. The factory function will be invoked for every Terraform
|
||||
// CLI command executed to create a provider server to which the CLI can
|
||||
// reattach.
|
||||
TestAccProtoV6ProviderFactories = map[string]func() (tfprotov6.ProviderServer, error){
|
||||
"stackitprivatepreview": providerserver.NewProtocol6WithError(stackit.New("test-version")()),
|
||||
}
|
||||
|
||||
// TestEphemeralAccProtoV6ProviderFactories is used to instantiate a provider during
|
||||
// acceptance testing. The factory function will be invoked for every Terraform
|
||||
// CLI command executed to create a provider server to which the CLI can
|
||||
// reattach.
|
||||
//
|
||||
// See the Terraform acceptance test documentation on ephemeral resources for more information:
|
||||
// https://developer.hashicorp.com/terraform/plugin/testing/acceptance-tests/ephemeral-resources
|
||||
TestEphemeralAccProtoV6ProviderFactories = map[string]func() (tfprotov6.ProviderServer, error){
|
||||
"stackitprivatepreview": providerserver.NewProtocol6WithError(stackit.New("test-version")()),
|
||||
"echo": echoprovider.NewProviderServer(),
|
||||
}
|
||||
|
||||
// E2ETestsEnabled checks if end-to-end tests should be run.
|
||||
// It is enabled when the TF_ACC environment variable is set to "1".
|
||||
E2ETestsEnabled = os.Getenv("TF_ACC") == "1"
|
||||
// OrganizationId is the id of organization used for tests
|
||||
OrganizationId = os.Getenv("TF_ACC_ORGANIZATION_ID")
|
||||
// ProjectId is the id of project used for tests
|
||||
ProjectId = os.Getenv("TF_ACC_PROJECT_ID")
|
||||
Region = os.Getenv("TF_ACC_REGION")
|
||||
// ServiceAccountFile is the json file of the service account
|
||||
ServiceAccountFile = os.Getenv("TF_ACC_SERVICE_ACCOUNT_FILE")
|
||||
// ServerId is the id of a server used for some tests
|
||||
ServerId = getenv("TF_ACC_SERVER_ID", "")
|
||||
// TestProjectParentContainerID is the container id of the parent resource under which projects are created as part of the resource-manager acceptance tests
|
||||
TestProjectParentContainerID = os.Getenv("TF_ACC_TEST_PROJECT_PARENT_CONTAINER_ID")
|
||||
// TestProjectParentUUID is the uuid of the parent resource under which projects are created as part of the resource-manager acceptance tests
|
||||
TestProjectParentUUID = os.Getenv("TF_ACC_TEST_PROJECT_PARENT_UUID")
|
||||
// TestProjectServiceAccountEmail is the e-mail of a service account with admin permissions on the organization under which projects are created as part of the resource-manager acceptance tests
|
||||
TestProjectServiceAccountEmail = os.Getenv("TF_ACC_TEST_PROJECT_SERVICE_ACCOUNT_EMAIL")
|
||||
// TestProjectUserEmail is the e-mail of a user for the project created as part of the resource-manager acceptance tests
|
||||
// Default email: acc-test@sa.stackit.cloud
|
||||
TestProjectUserEmail = getenv("TF_ACC_TEST_PROJECT_USER_EMAIL", "acc-test@sa.stackit.cloud")
|
||||
// TestImageLocalFilePath is the local path to an image file used for image acceptance tests
|
||||
TestImageLocalFilePath = getenv("TF_ACC_TEST_IMAGE_LOCAL_FILE_PATH", "default")
|
||||
)
|
||||
|
||||
func Setup() {
|
||||
root, err := getRoot()
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
err = godotenv.Load(fmt.Sprintf("%s/.env", *root))
|
||||
if err != nil {
|
||||
slog.Info("could not find .env file - not loading .env")
|
||||
return
|
||||
}
|
||||
slog.Info("loaded .env file", "path", *root)
|
||||
}
|
||||
|
||||
func getRoot() (*string, error) {
|
||||
cmd := exec.Command("git", "rev-parse", "--show-toplevel")
|
||||
out, err := cmd.Output()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
lines := strings.Split(string(out), "\n")
|
||||
return &lines[0], nil
|
||||
}
|
||||
|
||||
func ResourceNameWithDateTime(name string) string {
|
||||
dateTime := time.Now().Format(time.RFC3339)
|
||||
// Remove timezone to have a smaller datetime
|
||||
dateTimeTrimmed, _, _ := strings.Cut(dateTime, "+")
|
||||
return fmt.Sprintf("tf-acc-%s-%s", name, dateTimeTrimmed)
|
||||
}
|
||||
|
||||
// func GetTestProjectServiceAccountJson(path string) string {
|
||||
// var err error
|
||||
// json, ok := os.LookupEnv("TF_ACC_SERVICE_ACCOUNT_JSON_CONTENT")
|
||||
// if !ok || json == "" {
|
||||
// json, err = readTestServiceAccountJsonFromFile(path)
|
||||
// if err != nil {
|
||||
// return ""
|
||||
// }
|
||||
// }
|
||||
// return json
|
||||
//}
|
||||
|
||||
// func GetTestProjectServiceAccountToken(path string) string {
|
||||
// var err error
|
||||
// token, tokenSet := os.LookupEnv("TF_ACC_TEST_PROJECT_SERVICE_ACCOUNT_TOKEN")
|
||||
// if !tokenSet || token == "" {
|
||||
// token, err = readTestTokenFromCredentialsFile(path)
|
||||
// if err != nil {
|
||||
// return ""
|
||||
// }
|
||||
// }
|
||||
// return token
|
||||
//}
|
||||
//
|
||||
// func readTestTokenFromCredentialsFile(path string) (string, error) {
|
||||
// if path == "" {
|
||||
// customPath, customPathSet := os.LookupEnv("STACKIT_CREDENTIALS_PATH")
|
||||
// if !customPathSet || customPath == "" {
|
||||
// path = credentialsFilePath
|
||||
// home, err := os.UserHomeDir()
|
||||
// if err != nil {
|
||||
// return "", fmt.Errorf("getting home directory: %w", err)
|
||||
// }
|
||||
// path = filepath.Join(home, path)
|
||||
// } else {
|
||||
// path = customPath
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// credentialsRaw, err := os.ReadFile(path)
|
||||
// if err != nil {
|
||||
// return "", fmt.Errorf("opening file: %w", err)
|
||||
// }
|
||||
//
|
||||
// var credentials struct {
|
||||
// TF_ACC_TEST_PROJECT_SERVICE_ACCOUNT_TOKEN string `json:"TF_ACC_TEST_PROJECT_SERVICE_ACCOUNT_TOKEN"`
|
||||
// }
|
||||
// err = json.Unmarshal(credentialsRaw, &credentials)
|
||||
// if err != nil {
|
||||
// return "", fmt.Errorf("unmarshalling credentials: %w", err)
|
||||
// }
|
||||
// return credentials.TF_ACC_TEST_PROJECT_SERVICE_ACCOUNT_TOKEN, nil
|
||||
//}
|
||||
|
||||
// func readTestServiceAccountJsonFromFile(path string) (string, error) {
|
||||
// if path == "" {
|
||||
// customPath, ok := os.LookupEnv("TF_ACC_SERVICE_ACCOUNT_FILE")
|
||||
// if !ok || customPath == "" {
|
||||
// path = serviceAccountFilePath
|
||||
// // TODO: check if we want to handle this with a home dir
|
||||
// /*
|
||||
// home, err := os.UserHomeDir()
|
||||
// if err != nil {
|
||||
// return "", fmt.Errorf("getting home directory: %w", err)
|
||||
// }
|
||||
// path = filepath.Join(home, path)
|
||||
// */
|
||||
// } else {
|
||||
// path = customPath
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// credentialsRaw, err := os.ReadFile(path)
|
||||
// if err != nil {
|
||||
// return "", fmt.Errorf("opening file: %w", err)
|
||||
// }
|
||||
// return string(credentialsRaw), nil
|
||||
//}
|
||||
|
||||
func getenv(key, defaultValue string) string {
|
||||
val := os.Getenv(key)
|
||||
if val == "" {
|
||||
return defaultValue
|
||||
}
|
||||
return val
|
||||
}
|
||||
|
||||
// CreateDefaultLocalFile is a helper for local_file_path. No real data is created
|
||||
func CreateDefaultLocalFile() os.File {
|
||||
// Define the file name and size
|
||||
fileName := "test-512k.img"
|
||||
size := 512 * 1024 // 512 KB
|
||||
|
||||
// Create the file
|
||||
file, err := os.Create(fileName)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// Seek to the desired position (512 KB)
|
||||
_, err = file.Seek(int64(size), 0)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return *file
|
||||
}
|
||||
|
||||
func ConvertConfigVariable(variable config.Variable) string {
|
||||
tmpByteArray, _ := variable.MarshalJSON()
|
||||
// In case the variable is a string, the quotes should be removed
|
||||
if tmpByteArray[0] == '"' && tmpByteArray[len(tmpByteArray)-1] == '"' {
|
||||
result := string(tmpByteArray[1 : len(tmpByteArray)-1])
|
||||
// Replace escaped quotes which where added MarshalJSON
|
||||
rawString := strings.ReplaceAll(result, `\"`, `"`)
|
||||
return rawString
|
||||
}
|
||||
return string(tmpByteArray)
|
||||
}
|
||||
|
|
@ -1,6 +1,4 @@
|
|||
// Copyright (c) STACKIT
|
||||
|
||||
package testutil
|
||||
package testutils
|
||||
|
||||
import (
|
||||
"testing"
|
||||
1
main.go
1
main.go
|
|
@ -6,6 +6,7 @@ import (
|
|||
"log"
|
||||
|
||||
"github.com/hashicorp/terraform-plugin-framework/providerserver"
|
||||
|
||||
"tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit"
|
||||
)
|
||||
|
||||
|
|
|
|||
38
sample/alpha-from-registry/key.tf
Normal file
38
sample/alpha-from-registry/key.tf
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
resource "stackit_kms_keyring" "mshalpha-keyring" {
|
||||
project_id = var.project_id
|
||||
display_name = "msh-alpha-tests"
|
||||
description = "This is a test keyring for private endpoints"
|
||||
}
|
||||
|
||||
resource "stackit_kms_key" "mshalpha-key01" {
|
||||
project_id = var.project_id
|
||||
keyring_id = stackit_kms_keyring.mshalpha-keyring.keyring_id
|
||||
display_name = "mshalpha-key01"
|
||||
protection = "software"
|
||||
algorithm = "aes_256_gcm"
|
||||
purpose = "symmetric_encrypt_decrypt"
|
||||
access_scope = "SNA"
|
||||
}
|
||||
|
||||
output "keyid" {
|
||||
value = stackit_kms_key.mshalpha-key01.key_id
|
||||
}
|
||||
|
||||
# (because stackit_kms_key.key001 is not in configuration)
|
||||
resource "stackit_kms_key" "key001" {
|
||||
access_scope = "SNA"
|
||||
algorithm = "aes_256_gcm"
|
||||
display_name = "msh-key-sna01"
|
||||
keyring_id = stackit_kms_keyring.keyring001.keyring_id
|
||||
project_id = var.project_id
|
||||
protection = "software"
|
||||
purpose = "symmetric_encrypt_decrypt"
|
||||
}
|
||||
|
||||
# stackit_kms_keyring.keyring001 will be destroyed
|
||||
# (because stackit_kms_keyring.keyring001 is not in configuration)
|
||||
resource "stackit_kms_keyring" "keyring001" {
|
||||
description = "This is a test keyring for private endpoints"
|
||||
display_name = "msh-keyring-sna01"
|
||||
project_id = var.project_id
|
||||
}
|
||||
96
sample/alpha-from-registry/postresql.tf
Normal file
96
sample/alpha-from-registry/postresql.tf
Normal file
|
|
@ -0,0 +1,96 @@
|
|||
|
||||
data "stackitprivatepreview_postgresflexalpha_flavor" "pgsql_flavor" {
|
||||
project_id = var.project_id
|
||||
region = "eu01"
|
||||
cpu = 2
|
||||
ram = 4
|
||||
node_type = "Single"
|
||||
storage_class = "premium-perf2-stackit"
|
||||
}
|
||||
|
||||
resource "stackitprivatepreview_postgresflexalpha_instance" "msh-alpha-sna-enc" {
|
||||
project_id = var.project_id
|
||||
name = "msh-alpha-sna-enc"
|
||||
backup_schedule = "0 0 * * *"
|
||||
retention_days = 45
|
||||
flavor_id = data.stackitprivatepreview_postgresflexalpha_flavor.pgsql_flavor.flavor_id
|
||||
replicas = 1
|
||||
storage = {
|
||||
performance_class = "premium-perf2-stackit"
|
||||
size = 10
|
||||
}
|
||||
encryption = {
|
||||
kek_key_id = stackit_kms_key.mshalpha-key01.key_id
|
||||
kek_key_ring_id = stackit_kms_keyring.mshalpha-keyring.keyring_id
|
||||
kek_key_version = 1
|
||||
service_account = var.sa_email
|
||||
}
|
||||
network = {
|
||||
acl = ["0.0.0.0/0", "193.148.160.0/19", "170.85.2.177/32"]
|
||||
access_scope = "SNA"
|
||||
}
|
||||
version = 17
|
||||
}
|
||||
|
||||
resource "stackitprivatepreview_postgresflexalpha_instance" "msh-alpha-nosna-noenc" {
|
||||
project_id = var.project_id
|
||||
name = "msh-alpha-nosna-enc"
|
||||
backup_schedule = "0 0 * * *"
|
||||
retention_days = 45
|
||||
flavor_id = data.stackitprivatepreview_postgresflexalpha_flavor.pgsql_flavor.flavor_id
|
||||
replicas = 1
|
||||
storage = {
|
||||
performance_class = "premium-perf2-stackit"
|
||||
size = 10
|
||||
}
|
||||
network = {
|
||||
acl = ["0.0.0.0/0", "193.148.160.0/19", "170.85.2.177/32"]
|
||||
access_scope = "PUBLIC"
|
||||
}
|
||||
version = 16
|
||||
}
|
||||
|
||||
resource "stackitprivatepreview_postgresflexalpha_user" "ptlsdbadminuser" {
|
||||
project_id = var.project_id
|
||||
instance_id = stackitprivatepreview_postgresflexalpha_instance.msh-alpha-sna-enc.instance_id
|
||||
name = var.db_admin_username
|
||||
roles = ["createdb", "login"]
|
||||
# roles = ["createdb", "login", "createrole"]
|
||||
}
|
||||
|
||||
resource "stackitprivatepreview_postgresflexalpha_user" "ptlsdbuser" {
|
||||
project_id = var.project_id
|
||||
instance_id = stackitprivatepreview_postgresflexalpha_instance.msh-alpha-sna-enc.instance_id
|
||||
name = var.db_username
|
||||
roles = ["login"]
|
||||
# roles = ["createdb", "login", "createrole"]
|
||||
}
|
||||
|
||||
resource "stackitprivatepreview_postgresflexalpha_database" "example" {
|
||||
count = 5
|
||||
depends_on = [stackitprivatepreview_postgresflexalpha_user.ptlsdbadminuser]
|
||||
project_id = var.project_id
|
||||
instance_id = stackitprivatepreview_postgresflexalpha_instance.msh-alpha-sna-enc.instance_id
|
||||
name = "${var.db_name}${count.index}"
|
||||
owner = var.db_admin_username
|
||||
}
|
||||
|
||||
# data "stackitprivatepreview_postgresflexalpha_instance" "datapsql" {
|
||||
# project_id = var.project_id
|
||||
# instance_id = var.instance_id
|
||||
# region = "eu01"
|
||||
# }
|
||||
|
||||
# output "psql_instance_id" {
|
||||
# value = data.stackitprivatepreview_postgresflexalpha_instance.datapsql.instance_id
|
||||
# }
|
||||
|
||||
output "psql_user_password" {
|
||||
value = stackitprivatepreview_postgresflexalpha_user.ptlsdbuser.password
|
||||
sensitive = true
|
||||
}
|
||||
|
||||
# output "psql_user_conn" {
|
||||
# value = stackitprivatepreview_postgresflexalpha_user.ptlsdbuser.connection_string
|
||||
# sensitive = true
|
||||
# }
|
||||
24
sample/alpha-from-registry/providers.tf
Normal file
24
sample/alpha-from-registry/providers.tf
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
|
||||
terraform {
|
||||
required_providers {
|
||||
stackit = {
|
||||
source = "registry.terraform.io/stackitcloud/stackit"
|
||||
version = "~> 0.70"
|
||||
}
|
||||
stackitprivatepreview = {
|
||||
source = "tfregistry.sysops.stackit.rocks/mhenselin/stackitprivatepreview"
|
||||
version = ">=0.1.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
provider "stackit" {
|
||||
default_region = "eu01"
|
||||
enable_beta_resources = true
|
||||
service_account_key_path = "../service_account.json"
|
||||
}
|
||||
|
||||
provider "stackitprivatepreview" {
|
||||
default_region = "eu01"
|
||||
service_account_key_path = "../service_account.json"
|
||||
}
|
||||
101
sample/alpha-from-registry/sqlserver.tf
Normal file
101
sample/alpha-from-registry/sqlserver.tf
Normal 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##"]
|
||||
}
|
||||
|
||||
57
sample/kms/kms.tf
Normal file
57
sample/kms/kms.tf
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
resource "stackit_kms_keyring" "keyring001" {
|
||||
project_id = var.project_id
|
||||
display_name = "msh-keyring-sna01"
|
||||
description = "This is a test keyring for private endpoints"
|
||||
}
|
||||
|
||||
resource "stackit_kms_key" "key001" {
|
||||
project_id = var.project_id
|
||||
keyring_id = stackit_kms_keyring.keyring001.keyring_id
|
||||
display_name = "msh-key-sna01"
|
||||
protection = "software"
|
||||
algorithm = "aes_256_gcm"
|
||||
purpose = "symmetric_encrypt_decrypt"
|
||||
access_scope = "SNA"
|
||||
}
|
||||
|
||||
|
||||
# data "stackitprivatepreview_sqlserverflexalpha_instance" "test" {
|
||||
# project_id = var.project_id
|
||||
# instance_id = var.instance_id
|
||||
# region = "eu01"
|
||||
# }
|
||||
|
||||
output "key_ring_id" {
|
||||
value = stackit_kms_keyring.keyring001.id
|
||||
}
|
||||
|
||||
resource "stackit_kms_keyring" "keyring001yy" {
|
||||
project_id = var.project_id
|
||||
display_name = "msh-kr-sna01"
|
||||
description = "This is a test keyring for private endpoints"
|
||||
}
|
||||
|
||||
resource "stackit_kms_key" "key001yy" {
|
||||
project_id = var.project_id
|
||||
keyring_id = stackit_kms_keyring.keyring001yy.keyring_id
|
||||
display_name = "msh-k-001"
|
||||
protection = "software"
|
||||
algorithm = "aes_256_gcm"
|
||||
purpose = "symmetric_encrypt_decrypt"
|
||||
access_scope = "SNA"
|
||||
}
|
||||
|
||||
|
||||
# data "stackitprivatepreview_sqlserverflexalpha_instance" "test" {
|
||||
# project_id = var.project_id
|
||||
# instance_id = var.instance_id
|
||||
# region = "eu01"
|
||||
# }
|
||||
|
||||
output "key_ring_idxx" {
|
||||
value = stackit_kms_keyring.keyring001yy.id
|
||||
}
|
||||
|
||||
output "key_id" {
|
||||
value = stackit_kms_key.key001yy.id
|
||||
}
|
||||
25
sample/kms/providers.tf
Normal file
25
sample/kms/providers.tf
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
|
||||
terraform {
|
||||
required_providers {
|
||||
stackit = {
|
||||
source = "registry.terraform.io/stackitcloud/stackit"
|
||||
version = "~> 0.70"
|
||||
}
|
||||
# stackitprivatepreview = {
|
||||
# source = "tfregistry.sysops.stackit.rocks/mhenselin/stackitprivatepreview"
|
||||
# version = "= 0.0.2-alpha"
|
||||
# }
|
||||
}
|
||||
}
|
||||
|
||||
provider "stackit" {
|
||||
default_region = "eu01"
|
||||
enable_beta_resources = true
|
||||
service_account_key_path = "../service_account.json"
|
||||
}
|
||||
|
||||
# provider "stackitprivatepreview" {
|
||||
# default_region = "eu01"
|
||||
# enable_beta_resources = true
|
||||
# service_account_key_path = "../service_account.json"
|
||||
# }
|
||||
4
sample/pg_import/outputs.tf
Normal file
4
sample/pg_import/outputs.tf
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
#
|
||||
# output "postgres_flavor" {
|
||||
# value = data.stackitprivatepreview_postgresflexalpha_flavor.pgsql_flavor.flavor_id
|
||||
# }
|
||||
45
sample/pg_import/postresql.tf
Normal file
45
sample/pg_import/postresql.tf
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
|
||||
data "stackitprivatepreview_postgresflexalpha_flavor" "pgsql_flavor" {
|
||||
project_id = var.project_id
|
||||
region = "eu01"
|
||||
cpu = 2
|
||||
ram = 4
|
||||
node_type = "Single"
|
||||
storage_class = "premium-perf2-stackit"
|
||||
}
|
||||
|
||||
resource "stackitprivatepreview_postgresflexalpha_instance" "import_for_deletion" {
|
||||
project_id = var.project_id
|
||||
name = "mshpetest2"
|
||||
backup_schedule = "0 0 * * *"
|
||||
retention_days = 45
|
||||
flavor_id = data.stackitprivatepreview_postgresflexalpha_flavor.pgsql_flavor.flavor_id
|
||||
replicas = 1
|
||||
storage = {
|
||||
# class = "premium-perf2-stackit"
|
||||
performance_class = "premium-perf2-stackit"
|
||||
size = 10
|
||||
}
|
||||
encryption = {
|
||||
# key_id = stackit_kms_key.key.key_id
|
||||
# keyring_id = stackit_kms_keyring.keyring.keyring_id
|
||||
kek_key_id = var.key_id
|
||||
kek_key_ring_id = var.keyring_id
|
||||
kek_key_version = var.key_version
|
||||
service_account = var.sa_email
|
||||
}
|
||||
network = {
|
||||
acl = ["0.0.0.0/0", "193.148.160.0/19", "170.85.2.177/32"]
|
||||
access_scope = "PUBLIC"
|
||||
}
|
||||
version = 14
|
||||
}
|
||||
|
||||
import {
|
||||
to = stackitprivatepreview_postgresflexalpha_instance.import_for_deletion
|
||||
identity = {
|
||||
project_id = var.project_id
|
||||
region = "eu01"
|
||||
instance_id = "d52b5d4c-be3f-4c14-a107-330dab99fd2e"
|
||||
}
|
||||
}
|
||||
25
sample/pg_import/providers.tf
Normal file
25
sample/pg_import/providers.tf
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
|
||||
terraform {
|
||||
required_providers {
|
||||
# stackit = {
|
||||
# source = "registry.terraform.io/stackitcloud/stackit"
|
||||
# version = "~> 0.70"
|
||||
# }
|
||||
stackitprivatepreview = {
|
||||
source = "tfregistry.sysops.stackit.rocks/mhenselin/stackitprivatepreview"
|
||||
version = "> 0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# provider "stackit" {
|
||||
# default_region = "eu01"
|
||||
# enable_beta_resources = true
|
||||
# service_account_key_path = "./service_account.json"
|
||||
# }
|
||||
|
||||
provider "stackitprivatepreview" {
|
||||
default_region = "eu01"
|
||||
enable_beta_resources = true
|
||||
service_account_key_path = "../service_account.json"
|
||||
}
|
||||
11
sample/pg_import/variables.tf.example
Normal file
11
sample/pg_import/variables.tf.example
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
variable "project_id" {
|
||||
default = "<PROJECT ID UUID>"
|
||||
}
|
||||
|
||||
variable "sa_email" {
|
||||
default = "<SERVICE ACCOUNT EMAIL>"
|
||||
}
|
||||
|
||||
variable "db_username" {
|
||||
default = "<DB USERNAME>"
|
||||
}
|
||||
0
sample/pg_instance/outputs.tf
Normal file
0
sample/pg_instance/outputs.tf
Normal file
17
sample/pg_instance/postresql.tf
Normal file
17
sample/pg_instance/postresql.tf
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
|
||||
data "stackitprivatepreview_postgresflexalpha_flavor" "pgsql_flavor" {
|
||||
project_id = var.project_id
|
||||
region = "eu01"
|
||||
cpu = 2
|
||||
ram = 4
|
||||
node_type = "Single"
|
||||
storage_class = "premium-perf2-stackit"
|
||||
}
|
||||
data "stackitprivatepreview_postgresflexalpha_flavor" "pgsql_flavor2"{
|
||||
project_id = var.project_id
|
||||
region = "eu01"
|
||||
cpu = 2
|
||||
ram = 4
|
||||
node_type = "Single"
|
||||
storage_class = "premium-perf2-stackit"
|
||||
}
|
||||
25
sample/pg_instance/providers.tf
Normal file
25
sample/pg_instance/providers.tf
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
|
||||
terraform {
|
||||
required_providers {
|
||||
# stackit = {
|
||||
# source = "registry.terraform.io/stackitcloud/stackit"
|
||||
# version = "~> 0.70"
|
||||
# }
|
||||
stackitprivatepreview = {
|
||||
source = "tfregistry.sysops.stackit.rocks/mhenselin/stackitprivatepreview"
|
||||
version = "> 0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# provider "stackit" {
|
||||
# default_region = "eu01"
|
||||
# enable_beta_resources = true
|
||||
# service_account_key_path = "./service_account.json"
|
||||
# }
|
||||
|
||||
provider "stackitprivatepreview" {
|
||||
default_region = "eu01"
|
||||
enable_beta_resources = true
|
||||
service_account_key_path = "/home/henselinm/Development/PTLS/terraform-provider-stackit-MSH/sample/pg_instance/service_account.json"
|
||||
}
|
||||
11
sample/pg_instance/variables.tf.example
Normal file
11
sample/pg_instance/variables.tf.example
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
variable "project_id" {
|
||||
default = "<PROJECT ID UUID>"
|
||||
}
|
||||
|
||||
variable "sa_email" {
|
||||
default = "<SERVICE ACCOUNT EMAIL>"
|
||||
}
|
||||
|
||||
variable "db_username" {
|
||||
default = "<DB USERNAME>"
|
||||
}
|
||||
|
|
@ -65,15 +65,15 @@ resource "stackitprivatepreview_postgresflexalpha_instance" "msh-sna-pe-example2
|
|||
resource "stackitprivatepreview_postgresflexalpha_user" "ptlsdbadminuser" {
|
||||
project_id = var.project_id
|
||||
instance_id = stackitprivatepreview_postgresflexalpha_instance.msh-sna-pe-example.instance_id
|
||||
username = var.db_admin_username
|
||||
roles = ["createdb", "login"]
|
||||
name = var.db_admin_username
|
||||
roles = ["createdb", "login", "login"]
|
||||
# roles = ["createdb", "login", "createrole"]
|
||||
}
|
||||
|
||||
resource "stackitprivatepreview_postgresflexalpha_user" "ptlsdbadminuser2" {
|
||||
project_id = var.project_id
|
||||
instance_id = stackitprivatepreview_postgresflexalpha_instance.msh-sna-pe-example2.instance_id
|
||||
username = var.db_admin_username
|
||||
name = var.db_admin_username
|
||||
roles = ["createdb", "login"]
|
||||
# roles = ["createdb", "login", "createrole"]
|
||||
}
|
||||
|
|
@ -81,7 +81,7 @@ resource "stackitprivatepreview_postgresflexalpha_user" "ptlsdbadminuser2" {
|
|||
resource "stackitprivatepreview_postgresflexalpha_user" "ptlsdbuser" {
|
||||
project_id = var.project_id
|
||||
instance_id = stackitprivatepreview_postgresflexalpha_instance.msh-sna-pe-example.instance_id
|
||||
username = var.db_username
|
||||
name = var.db_name
|
||||
roles = ["login"]
|
||||
# roles = ["createdb", "login", "createrole"]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
|
||||
data "stackitprivatepreview_sqlserverflexalpha_flavor" "sqlserver_flavor" {
|
||||
data "stackitprivatepreview_sqlserverflexbeta_flavor" "sqlserver_flavor" {
|
||||
project_id = var.project_id
|
||||
region = "eu01"
|
||||
cpu = 4
|
||||
|
|
@ -9,5 +9,5 @@ data "stackitprivatepreview_sqlserverflexalpha_flavor" "sqlserver_flavor" {
|
|||
}
|
||||
|
||||
output "sqlserver_flavor" {
|
||||
value = data.stackitprivatepreview_sqlserverflexalpha_flavor.sqlserver_flavor.flavor_id
|
||||
value = data.stackitprivatepreview_sqlserverflexbeta_flavor.sqlserver_flavor.flavor_id
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,15 +18,15 @@
|
|||
# value = stackit_kms_key.key.key_id
|
||||
# }
|
||||
|
||||
resource "stackitprivatepreview_sqlserverflexalpha_instance" "msh-sna-001" {
|
||||
resource "stackitprivatepreview_sqlserverflexbeta_instance" "msh-beta-sna-001" {
|
||||
project_id = var.project_id
|
||||
name = "msh-sna-001"
|
||||
name = "msh-beta-sna-001"
|
||||
backup_schedule = "0 3 * * *"
|
||||
retention_days = 31
|
||||
flavor_id = data.stackitprivatepreview_sqlserverflexalpha_flavor.sqlserver_flavor.flavor_id
|
||||
flavor_id = data.stackitprivatepreview_sqlserverflexbeta_flavor.sqlserver_flavor.flavor_id
|
||||
storage = {
|
||||
class = "premium-perf2-stackit"
|
||||
size = 50
|
||||
size = 10
|
||||
}
|
||||
version = 2022
|
||||
encryption = {
|
||||
|
|
@ -34,9 +34,11 @@ resource "stackitprivatepreview_sqlserverflexalpha_instance" "msh-sna-001" {
|
|||
#keyring_id = stackit_kms_keyring.keyring.keyring_id
|
||||
#key_version = 1
|
||||
# key with scope public
|
||||
kek_key_id = "fe039bcf-8d7b-431a-801d-9e81371a6b7b"
|
||||
# kek_key_id = "fe039bcf-8d7b-431a-801d-9e81371a6b7b"
|
||||
kek_key_id = "c6878f92-ce55-4b79-8236-ba9d001d7967" # msh-k-001
|
||||
# key_id = var.key_id
|
||||
kek_key_ring_id = var.keyring_id
|
||||
# kek_key_ring_id = var.keyring_id
|
||||
kek_key_ring_id = "0dea3f5f-9947-4dda-a9d3-18418832cefe" # msh-kr-sna01
|
||||
kek_key_version = var.key_version
|
||||
service_account = var.sa_email
|
||||
}
|
||||
|
|
@ -46,83 +48,16 @@ resource "stackitprivatepreview_sqlserverflexalpha_instance" "msh-sna-001" {
|
|||
}
|
||||
}
|
||||
|
||||
resource "stackitprivatepreview_sqlserverflexalpha_instance" "msh-sna-101" {
|
||||
project_id = var.project_id
|
||||
name = "msh-sna-101"
|
||||
backup_schedule = "0 3 * * *"
|
||||
retention_days = 31
|
||||
flavor_id = data.stackitprivatepreview_sqlserverflexalpha_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 with scope public
|
||||
kek_key_id = "fe039bcf-8d7b-431a-801d-9e81371a6b7b"
|
||||
# key_id = var.key_id
|
||||
kek_key_ring_id = var.keyring_id
|
||||
kek_key_version = var.key_version
|
||||
service_account = var.sa_email
|
||||
}
|
||||
network = {
|
||||
acl = ["0.0.0.0/0", "193.148.160.0/19"]
|
||||
access_scope = "SNA"
|
||||
}
|
||||
resource "stackitprivatepreview_sqlserverflexbeta_user" "betauser" {
|
||||
project_id = var.project_id
|
||||
instance_id = stackitprivatepreview_sqlserverflexbeta_instance.msh-beta-sna-001.instance_id
|
||||
username = "betauser"
|
||||
roles = ["##STACKIT_DatabaseManager##", "##STACKIT_LoginManager##"]
|
||||
}
|
||||
|
||||
resource "stackitprivatepreview_sqlserverflexalpha_instance" "msh-nosna-001" {
|
||||
project_id = var.project_id
|
||||
name = "msh-nosna-001"
|
||||
backup_schedule = "0 3 * * *"
|
||||
retention_days = 31
|
||||
flavor_id = data.stackitprivatepreview_sqlserverflexalpha_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"
|
||||
}
|
||||
resource "stackitprivatepreview_sqlserverflexbeta_database" "betadb" {
|
||||
project_id = var.project_id
|
||||
instance_id = stackitprivatepreview_sqlserverflexbeta_instance.msh-beta-sna-001.instance_id
|
||||
name = "mshtest002"
|
||||
owner = stackitprivatepreview_sqlserverflexbeta_user.betauser.username
|
||||
}
|
||||
|
||||
# data "stackitprivatepreview_sqlserverflexalpha_instance" "test" {
|
||||
# project_id = var.project_id
|
||||
# instance_id = var.instance_id
|
||||
# region = "eu01"
|
||||
# }
|
||||
|
||||
# output "test" {
|
||||
# value = data.stackitprivatepreview_sqlserverflexalpha_instance.test
|
||||
# }
|
||||
|
||||
# resource "stackitprivatepreview_sqlserverflexalpha_user" "ptlsdbadminuser" {
|
||||
# project_id = var.project_id
|
||||
# instance_id = stackitprivatepreview_sqlserverflexalpha_instance.sqlsrv.instance_id
|
||||
# username = var.db_admin_username
|
||||
# roles = ["##STACKIT_LoginManager##", "##STACKIT_DatabaseManager##"]
|
||||
# }
|
||||
|
||||
# resource "stackitprivatepreview_sqlserverflexalpha_user" "ptlsdbuser" {
|
||||
# project_id = var.project_id
|
||||
# instance_id = stackitprivatepreview_sqlserverflexalpha_instance.sqlsrv.instance_id
|
||||
# username = var.db_username
|
||||
# roles = ["##STACKIT_LoginManager##"]
|
||||
# }
|
||||
|
||||
|
|
|
|||
13
sample/sqlserver_beta/flavor.tf
Normal file
13
sample/sqlserver_beta/flavor.tf
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
#
|
||||
# data "stackitprivatepreview_sqlserverflexalpha_flavor" "sqlserver_flavor" {
|
||||
# project_id = var.project_id
|
||||
# region = "eu01"
|
||||
# cpu = 4
|
||||
# ram = 16
|
||||
# node_type = "Single"
|
||||
# storage_class = "premium-perf2-stackit"
|
||||
# }
|
||||
#
|
||||
# output "sqlserver_flavor" {
|
||||
# value = data.stackitprivatepreview_sqlserverflexalpha_flavor.sqlserver_flavor.flavor_id
|
||||
# }
|
||||
9
sample/sqlserver_beta/postgres.tf
Normal file
9
sample/sqlserver_beta/postgres.tf
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
|
||||
data "stackitprivatepreview_postgresflexalpha_flavor" "pgsql_flavor" {
|
||||
project_id = var.project_id
|
||||
region = "eu01"
|
||||
cpu = 2
|
||||
ram = 4
|
||||
node_type = "Single"
|
||||
storage_class = "premium-perf2-stackit"
|
||||
}
|
||||
25
sample/sqlserver_beta/providers.tf
Normal file
25
sample/sqlserver_beta/providers.tf
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
|
||||
terraform {
|
||||
required_providers {
|
||||
# stackit = {
|
||||
# source = "registry.terraform.io/stackitcloud/stackit"
|
||||
# version = "~> 0.70"
|
||||
# }
|
||||
stackitprivatepreview = {
|
||||
source = "tfregistry.sysops.stackit.rocks/mhenselin/stackitprivatepreview"
|
||||
version = "> 0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# provider "stackit" {
|
||||
# default_region = "eu01"
|
||||
# enable_beta_resources = true
|
||||
# service_account_key_path = "../service_account.json"
|
||||
# }
|
||||
|
||||
provider "stackitprivatepreview" {
|
||||
default_region = "eu01"
|
||||
enable_beta_resources = true
|
||||
service_account_key_path = "../service_account.json"
|
||||
}
|
||||
116
sample/sqlserver_beta/sqlserver.tf
Normal file
116
sample/sqlserver_beta/sqlserver.tf
Normal file
|
|
@ -0,0 +1,116 @@
|
|||
data "stackitprivatepreview_sqlserverflexbeta_flavor" "sqlserver_flavor" {
|
||||
project_id = var.project_id
|
||||
region = "eu01"
|
||||
cpu = 4
|
||||
ram = 16
|
||||
node_type = "Single"
|
||||
storage_class = "premium-perf2-stackit"
|
||||
}
|
||||
|
||||
data "stackitprivatepreview_sqlserverflexbeta_flavor" "sqlserver_flavor_2" {
|
||||
project_id = var.project_id
|
||||
region = "eu01"
|
||||
cpu = 4
|
||||
ram = 32
|
||||
node_type = "Replica"
|
||||
storage_class = "premium-perf2-stackit"
|
||||
}
|
||||
|
||||
resource "stackitprivatepreview_sqlserverflexbeta_instance" "msh-beta-nosna-001" {
|
||||
project_id = var.project_id
|
||||
name = "msh-beta-nosna-001-renamed"
|
||||
backup_schedule = "0 3 * * *"
|
||||
retention_days = 31
|
||||
flavor_id = data.stackitprivatepreview_sqlserverflexbeta_flavor.sqlserver_flavor.flavor_id
|
||||
storage = {
|
||||
class = "premium-perf2-stackit"
|
||||
size = 50
|
||||
}
|
||||
version = 2022
|
||||
network = {
|
||||
acl = ["0.0.0.0/0", "193.148.160.0/19"]
|
||||
access_scope = "PUBLIC"
|
||||
}
|
||||
}
|
||||
|
||||
resource "stackitprivatepreview_sqlserverflexbeta_instance" "msh-beta-sna-001" {
|
||||
project_id = var.project_id
|
||||
name = "msh-beta-sna-001"
|
||||
backup_schedule = "0 3 * * *"
|
||||
retention_days = 31
|
||||
flavor_id = data.stackitprivatepreview_sqlserverflexbeta_flavor.sqlserver_flavor.flavor_id
|
||||
storage = {
|
||||
class = "premium-perf2-stackit"
|
||||
size = 5
|
||||
}
|
||||
version = 2022
|
||||
encryption = {
|
||||
#key_id = stackit_kms_key.key.key_id
|
||||
#keyring_id = stackit_kms_keyring.keyring.keyring_id
|
||||
#key_version = 1
|
||||
# key with scope public
|
||||
kek_key_id = "fe039bcf-8d7b-431a-801d-9e81371a6b7b"
|
||||
# key_id = var.key_id
|
||||
kek_key_ring_id = var.keyring_id
|
||||
kek_key_version = var.key_version
|
||||
service_account = var.sa_email
|
||||
}
|
||||
network = {
|
||||
acl = ["0.0.0.0/0", "193.148.160.0/19"]
|
||||
access_scope = "SNA"
|
||||
}
|
||||
}
|
||||
|
||||
resource "stackitprivatepreview_sqlserverflexbeta_user" "exampleuseruno" {
|
||||
project_id = var.project_id
|
||||
instance_id = stackitprivatepreview_sqlserverflexbeta_instance.msh-beta-nosna-001.instance_id
|
||||
username = "exampleuserdue"
|
||||
roles = ["##STACKIT_ProcessManager##", "##STACKIT_LoginManager##", "##STACKIT_ServerManager##"]
|
||||
}
|
||||
|
||||
resource "stackitprivatepreview_sqlserverflexbeta_user" "exampleuser" {
|
||||
project_id = var.project_id
|
||||
instance_id = stackitprivatepreview_sqlserverflexbeta_instance.msh-beta-nosna-001.instance_id
|
||||
username = "exampleuser"
|
||||
roles = ["##STACKIT_LoginManager##"]
|
||||
}
|
||||
|
||||
|
||||
resource "stackitprivatepreview_sqlserverflexbeta_database" "mshtest002" {
|
||||
project_id = var.project_id
|
||||
instance_id = stackitprivatepreview_sqlserverflexbeta_instance.msh-beta-nosna-001.instance_id
|
||||
name = "mshtest002"
|
||||
# owner = "dbuser"
|
||||
owner = stackitprivatepreview_sqlserverflexbeta_user.exampleuseruno.username
|
||||
}
|
||||
|
||||
|
||||
# data "stackitprivatepreview_sqlserverflexbeta_database" "example" {
|
||||
# project_id = var.project_id
|
||||
# region = "eu01"
|
||||
# instance_id = "b3b63d0c-35bf-4804-84ea-5abec2a8ae58"
|
||||
# database_name = "mshtest001"
|
||||
# }
|
||||
|
||||
# output "dbdetails" {
|
||||
# value = data.stackitprivatepreview_sqlserverflexbeta_database.example
|
||||
# }
|
||||
#
|
||||
|
||||
|
||||
# resource "stackitprivatepreview_sqlserverflexbeta_database" "mshtest" {
|
||||
# project_id = var.project_id
|
||||
# instance_id = "b3b63d0c-35bf-4804-84ea-5abec2a8ae58"
|
||||
# name = "mshtest"
|
||||
# owner = "dbuser"
|
||||
# }
|
||||
#
|
||||
# import {
|
||||
# to = stackitprivatepreview_sqlserverflexbeta_database.mshtest
|
||||
# identity = {
|
||||
# project_id = var.project_id
|
||||
# region = "eu01"
|
||||
# instance_id = "b3b63d0c-35bf-4804-84ea-5abec2a8ae58"
|
||||
# database_name = "mshtest"
|
||||
# }
|
||||
# }
|
||||
11
sample/sqlserver_beta/variables.tf.example
Normal file
11
sample/sqlserver_beta/variables.tf.example
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
variable "project_id" {
|
||||
default = "<PROJECT ID UUID>"
|
||||
}
|
||||
|
||||
variable "sa_email" {
|
||||
default = "<SERVICE ACCOUNT EMAIL>"
|
||||
}
|
||||
|
||||
variable "db_username" {
|
||||
default = "<DB USERNAME>"
|
||||
}
|
||||
|
|
@ -1,19 +0,0 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
# This script lints the SDK modules and the internal examples
|
||||
# Pre-requisites: golangci-lint
|
||||
set -eo pipefail
|
||||
|
||||
ROOT_DIR=$(git rev-parse --show-toplevel)
|
||||
GOLANG_CI_YAML_PATH="${ROOT_DIR}/golang-ci.yaml"
|
||||
GOLANG_CI_ARGS="--allow-parallel-runners --timeout=5m --config=${GOLANG_CI_YAML_PATH}"
|
||||
|
||||
if type -p golangci-lint >/dev/null; then
|
||||
:
|
||||
else
|
||||
echo "golangci-lint not installed, unable to proceed."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
cd ${ROOT_DIR}
|
||||
golangci-lint run ${GOLANG_CI_ARGS}
|
||||
|
|
@ -17,11 +17,7 @@ elif [ "$action" = "tools" ]; then
|
|||
|
||||
go mod download
|
||||
|
||||
# go install github.com/golangci/golangci-lint/cmd/golangci-lint@v1.62.0
|
||||
go install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@v2.7.2
|
||||
|
||||
# go install github.com/hashicorp/terraform-plugin-docs/cmd/tfplugindocs@v0.21.0
|
||||
go install github.com/hashicorp/terraform-plugin-docs/cmd/tfplugindocs@v0.24.0
|
||||
go install golang.org/x/tools/cmd/goimports@v0.42.0
|
||||
else
|
||||
echo "Invalid action: '$action', please use $0 help for help"
|
||||
fi
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue