diff --git a/.github/actions/acc_test/action.yaml b/.github/actions/acc_test/action.yaml index 9405440a..828e1011 100644 --- a/.github/actions/acc_test/action.yaml +++ b/.github/actions/acc_test/action.yaml @@ -53,9 +53,9 @@ runs: - name: Install Go ${{ inputs.go-version }} uses: actions/setup-go@v6 with: - # go-version: ${{ env.GO_VERSION }} + go-version: ${{ inputs.go-version }} + check-latest: true go-version-file: 'go.mod' - cache-dependency-path: "**/*.sum" - name: Install go tools shell: bash diff --git a/.github/actions/build/action.yaml b/.github/actions/build/action.yaml index 836094c8..1fa83ee1 100644 --- a/.github/actions/build/action.yaml +++ b/.github/actions/build/action.yaml @@ -26,9 +26,9 @@ runs: - name: Install Go ${{ inputs.go-version }} uses: actions/setup-go@v6 with: - # go-version: ${{ env.GO_VERSION }} + go-version: ${{ inputs.go-version }} + check-latest: true go-version-file: 'go.mod' - cache-dependency-path: "**/*.sum" - name: Install go tools shell: bash diff --git a/.github/actions/setup-cache-go/action.yaml b/.github/actions/setup-cache-go/action.yaml index 1e3fb7a4..81f0d17d 100644 --- a/.github/actions/setup-cache-go/action.yaml +++ b/.github/actions/setup-cache-go/action.yaml @@ -26,15 +26,11 @@ runs: 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: ${{ 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 - # go-version: ${{ env.GO_VERSION }} - go-version-file: 'go.mod' - cache-dependency-path: "**/*.sum" - + cache: false - name: "Get go environment information" shell: bash diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 0150e007..e747e730 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -22,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 @@ -37,15 +70,10 @@ 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-file: 'go.mod' - cache-dependency-path: "**/*.sum" + go-version: ${{ env.GO_VERSION }} - name: Install go tools run: | @@ -59,6 +87,9 @@ jobs: 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 @@ -228,6 +259,7 @@ jobs: # path: "stackit/${{ env.CODE_COVERAGE_FILE_NAME }}" config: + if: ${{ github.event_name != 'schedule' }} name: Check GoReleaser config runs-on: ubuntu-latest steps: diff --git a/.github/workflows/publish.yaml b/.github/workflows/publish.yaml index 55d2f2ac..b86dba35 100644 --- a/.github/workflows/publish.yaml +++ b/.github/workflows/publish.yaml @@ -46,9 +46,7 @@ jobs: - name: Setup Go uses: actions/setup-go@v6 with: - # go-version: ${{ env.GO_VERSION }} - go-version-file: 'go.mod' - cache-dependency-path: "**/*.sum" + go-version: ${{ env.GO_VERSION }} - name: Install go tools run: | diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index a1d38462..7d7106ed 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -22,11 +22,10 @@ jobs: with: # Allow goreleaser to access older tag information. fetch-depth: 0 - - uses: actions/setup-go@v6 + - uses: actions/setup-go@v5 with: - # go-version: ${{ env.GO_VERSION }} - go-version-file: 'go.mod' - cache-dependency-path: "**/*.sum" + go-version-file: "go.mod" + cache: true - name: Import GPG key uses: crazy-max/ghaction-import-gpg@v6 id: import_gpg diff --git a/.github/workflows/runnerstats.yaml b/.github/workflows/runnerstats.yaml new file mode 100644 index 00000000..08190d4c --- /dev/null +++ b/.github/workflows/runnerstats.yaml @@ -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 diff --git a/cmd/cmd/build/templates/resource_scaffold.gotmpl b/cmd/cmd/build/templates/resource_scaffold.gotmpl index fec7ee98..3fafc10c 100644 --- a/cmd/cmd/build/templates/resource_scaffold.gotmpl +++ b/cmd/cmd/build/templates/resource_scaffold.gotmpl @@ -14,7 +14,7 @@ import ( "github.com/stackitcloud/stackit-sdk-go/core/config" "tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit/internal/conversion" - {{.PackageName}}PkgGen "tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/pkg_gen/{{.PackageName}}" + "tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/pkg_gen/{{.PackageName}}" "tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit/internal/core" "tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit/internal/utils" @@ -35,12 +35,12 @@ func New{{.NamePascal}}Resource() resource.Resource { } type {{.NameCamel}}Resource struct{ - client *{{.PackageName}}PkgGen.APIClient + client *{{.PackageName}}.APIClient providerData core.ProviderData } // resourceModel represents the Terraform resource state -type resourceModel = {{.PackageName}}ResGen.{{.NamePascal}}Model +type resourceModel = {{.PackageName}}.{{.NamePascal}}Model type {{.NamePascal}}ResourceIdentityModel struct { ProjectID types.String `tfsdk:"project_id"` @@ -59,15 +59,15 @@ 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) + schema = {{.PackageName}}ResGen.{{.NamePascal}}ResourceSchema(ctx) - fields, err := utils.ReadModifiersConfig(modifiersFileByte) + fields, err := {{.PackageName}}Utils.ReadModifiersConfig(modifiersFileByte) if err != nil { resp.Diagnostics.AddError("error during read modifiers config file", err.Error()) return } - err = utils.AddPlanModifiersToResourceSchema(fields, &schema) + err = {{.PackageName}}Utils.AddPlanModifiersToResourceSchema(fields, &schema) if err != nil { resp.Diagnostics.AddError("error adding plan modifiers", err.Error()) return @@ -109,14 +109,12 @@ func (r *{{.NameCamel}}Resource) Configure( config.WithCustomAuth(r.providerData.RoundTripper), utils.UserAgentConfigOption(r.providerData.Version), } - /* if r.providerData.{{.PackageNamePascal}}CustomEndpoint != "" { apiClientConfigOptions = append(apiClientConfigOptions, config.WithEndpoint(r.providerData.{{.PackageName}}CustomEndpoint)) } else { apiClientConfigOptions = append(apiClientConfigOptions, config.WithRegion(r.providerData.GetRegion())) } - */ - apiClient, err := {{.PackageName}}PkgGen.NewAPIClient(apiClientConfigOptions...) + apiClient, err := {{.PackageName}}.NewAPIClient(apiClientConfigOptions...) if err != nil { resp.Diagnostics.AddError( "Error configuring API client", @@ -295,11 +293,18 @@ func (r *{{.NameCamel}}Resource) Read(ctx context.Context, req resource.ReadRequ 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 := data.ProjectID.ValueString() - region := data.Region.ValueString() + projectId := identityData.ProjectID.ValueString() + region := identityData.Region.ValueString() ctx = tflog.SetField(ctx, "project_id", projectId) ctx = tflog.SetField(ctx, "region", region) @@ -325,6 +330,12 @@ func (r *{{.NameCamel}}Resource) Read(ctx context.Context, req resource.ReadRequ func (r *{{.NameCamel}}Resource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { var data {{.PackageName}}ResGen.{{.NamePascal}}Model + // Read Terraform prior state data into the model + resp.Diagnostics.Append(req.State.Get(ctx, &data)...) + if resp.Diagnostics.HasError() { + return + } + ctx = core.InitProviderContext(ctx) projectId := data.ProjectId.ValueString() diff --git a/internal/testutils/testutils.go b/internal/testutils/testutils.go index ca308f53..933dab0e 100644 --- a/internal/testutils/testutils.go +++ b/internal/testutils/testutils.go @@ -3,6 +3,7 @@ package testutils import ( "fmt" "log" + "log/slog" "os" "os/exec" "path/filepath" @@ -77,10 +78,10 @@ func Setup() { } err = godotenv.Load(fmt.Sprintf("%s/.env", *root)) if err != nil { - log.Println("could not find .env file - not loading .env") + slog.Info("could not find .env file - not loading .env") return } - log.Println("loaded .env file", "path", *root) + slog.Info("loaded .env file", "path", *root) } func getRoot() (*string, error) { diff --git a/stackit/internal/services/postgresflexalpha/instance/resource.go b/stackit/internal/services/postgresflexalpha/instance/resource.go index ddcd67c6..d4049fb5 100644 --- a/stackit/internal/services/postgresflexalpha/instance/resource.go +++ b/stackit/internal/services/postgresflexalpha/instance/resource.go @@ -7,7 +7,6 @@ import ( "math" "net/http" "strings" - "time" "github.com/hashicorp/terraform-plugin-framework/path" "github.com/hashicorp/terraform-plugin-framework/resource" @@ -245,9 +244,6 @@ func (r *instanceResource) Create( } waitResp, err := wait.CreateInstanceWaitHandler(ctx, r.client, projectId, region, instanceId). - // Sleep before wait is set because sometimes API returns 404 right after creation request - SetTimeout(90 * time.Minute). - SetSleepBeforeWait(30 * time.Second). WaitWithContext(ctx) if err != nil { core.LogAndAddError( @@ -490,10 +486,7 @@ func (r *instanceResource) Update( projectId, region, instanceId, - ). - SetTimeout(45 * time.Minute). - SetSleepBeforeWait(30 * time.Second). - WaitWithContext(ctx) + ).WaitWithContext(ctx) if err != nil { core.LogAndAddError( ctx, diff --git a/stackit/internal/services/postgresflexalpha/postgresflex_acc_test.go b/stackit/internal/services/postgresflexalpha/postgresflex_acc_test.go index a9c81f0e..d5ffd00c 100644 --- a/stackit/internal/services/postgresflexalpha/postgresflex_acc_test.go +++ b/stackit/internal/services/postgresflexalpha/postgresflex_acc_test.go @@ -110,9 +110,6 @@ func TestMain(m *testing.M) { } func testAccPreCheck(t *testing.T) { - if _, ok := os.LookupEnv("TF_ACC"); !ok { - t.Skip("TF_ACC is not set") - } if _, ok := os.LookupEnv("TF_ACC_PROJECT_ID"); !ok { t.Fatalf("could not find env var TF_ACC_PROJECT_ID") } diff --git a/stackit/internal/services/sqlserverflexalpha/instance/resource.go b/stackit/internal/services/sqlserverflexalpha/instance/resource.go index 06f379e5..3b1f4fd3 100644 --- a/stackit/internal/services/sqlserverflexalpha/instance/resource.go +++ b/stackit/internal/services/sqlserverflexalpha/instance/resource.go @@ -479,9 +479,7 @@ func (r *instanceResource) Delete(ctx context.Context, req resource.DeleteReques ctx = core.LogResponse(ctx) - delResp, err := wait.DeleteInstanceWaitHandler(ctx, r.client, projectId, instanceId, region). - SetTimeout(30 * time.Minute). - WaitWithContext(ctx) + delResp, err := wait.DeleteInstanceWaitHandler(ctx, r.client, projectId, instanceId, region).WaitWithContext(ctx) if err != nil { core.LogAndAddError( ctx, diff --git a/stackit/internal/services/sqlserverflexalpha/user/resource.go b/stackit/internal/services/sqlserverflexalpha/user/resource.go index 0b5f5494..ee322fab 100644 --- a/stackit/internal/services/sqlserverflexalpha/user/resource.go +++ b/stackit/internal/services/sqlserverflexalpha/user/resource.go @@ -468,8 +468,6 @@ func (r *userResource) Delete( } // Delete existing record set _, err = sqlserverflexalphaWait.DeleteUserWaitHandler(ctx, r.client, projectId, region, instanceId, userId). - SetTimeout(15 * time.Minute). - SetSleepBeforeWait(15 * time.Second). WaitWithContext(ctx) if err != nil { core.LogAndAddError(ctx, &resp.Diagnostics, "User Delete Error", fmt.Sprintf("Calling API: %v", err)) diff --git a/stackit/internal/services/sqlserverflexbeta/instance/functions_test.go b/stackit/internal/services/sqlserverflexbeta/instance/functions_test.go index 202f4426..0c6f6147 100644 --- a/stackit/internal/services/sqlserverflexbeta/instance/functions_test.go +++ b/stackit/internal/services/sqlserverflexbeta/instance/functions_test.go @@ -40,7 +40,6 @@ func Test_handleDSEncryption(t *testing.T) { } func Test_handleEncryption(t *testing.T) { - ctx := context.Background() type args struct { m *sqlserverflexbetaRs.InstanceModel resp *sqlserverflexbetaPkgGen.GetInstanceResponse @@ -81,23 +80,19 @@ func Test_handleEncryption(t *testing.T) { }, }, }, - want: sqlserverflexbetaRs.NewEncryptionValueMust( - sqlserverflexbetaRs.EncryptionValue{}.AttributeTypes(ctx), - map[string]attr.Value{ - "kek_key_id": types.StringValue("kek_key_id"), - "kek_key_ring_id": types.StringValue("kek_key_ring_id"), - "kek_key_version": types.StringValue("kek_key_version"), - "service_account": types.StringValue("kek_svc_acc"), - }, - ), + want: sqlserverflexbetaRs.EncryptionValue{ + KekKeyId: types.StringValue("kek_key_id"), + KekKeyRingId: types.StringValue("kek_key_ring_id"), + KekKeyVersion: types.StringValue("kek_key_version"), + ServiceAccount: types.StringValue("kek_svc_acc"), + }, }, } for _, tt := range tests { t.Run( tt.name, func(t *testing.T) { - got := handleEncryption(t.Context(), tt.args.m, tt.args.resp) - if diff := cmp.Diff(tt.want, got); diff != "" { - t.Errorf("string mismatch (-want +got):\n%s", diff) + if got := handleEncryption(t.Context(), tt.args.m, tt.args.resp); !reflect.DeepEqual(got, tt.want) { + t.Errorf("handleEncryption() = %v, want %v", got, tt.want) } }, ) diff --git a/stackit/internal/services/sqlserverflexbeta/instance/resource.go b/stackit/internal/services/sqlserverflexbeta/instance/resource.go index e0e969af..044b4b43 100644 --- a/stackit/internal/services/sqlserverflexbeta/instance/resource.go +++ b/stackit/internal/services/sqlserverflexbeta/instance/resource.go @@ -473,9 +473,7 @@ func (r *instanceResource) Delete(ctx context.Context, req resource.DeleteReques ctx = core.LogResponse(ctx) - delResp, err := wait.DeleteInstanceWaitHandler(ctx, r.client, projectId, instanceId, region). - SetTimeout(30 * time.Minute). - WaitWithContext(ctx) + delResp, err := wait.DeleteInstanceWaitHandler(ctx, r.client, projectId, instanceId, region).WaitWithContext(ctx) if err != nil { core.LogAndAddError( ctx, diff --git a/stackit/internal/services/sqlserverflexbeta/user/resource.go b/stackit/internal/services/sqlserverflexbeta/user/resource.go index ac3263a5..efaf3fc1 100644 --- a/stackit/internal/services/sqlserverflexbeta/user/resource.go +++ b/stackit/internal/services/sqlserverflexbeta/user/resource.go @@ -492,8 +492,6 @@ func (r *userResource) Delete( } // Delete existing record set _, err = sqlserverflexbetaWait.DeleteUserWaitHandler(ctx, r.client, projectId, region, instanceId, userId). - SetTimeout(15 * time.Minute). - SetSleepBeforeWait(15 * time.Second). WaitWithContext(ctx) if err != nil { core.LogAndAddError(ctx, &resp.Diagnostics, "User Delete Error", fmt.Sprintf("Calling API: %v", err)) diff --git a/stackit/internal/wait/postgresflexalpha/wait.go b/stackit/internal/wait/postgresflexalpha/wait.go index 9e8cd345..4aea71e8 100644 --- a/stackit/internal/wait/postgresflexalpha/wait.go +++ b/stackit/internal/wait/postgresflexalpha/wait.go @@ -173,7 +173,8 @@ func CreateInstanceWaitHandler( return false, nil, nil }, ) - + // Sleep before wait is set because sometimes API returns 404 right after creation request + handler.SetTimeout(90 * time.Minute).SetSleepBeforeWait(30 * time.Second) return handler } @@ -211,6 +212,7 @@ func PartialUpdateInstanceWaitHandler( } }, ) + handler.SetTimeout(45 * time.Minute).SetSleepBeforeWait(30 * time.Second) return handler } diff --git a/stackit/internal/wait/sqlserverflexalpha/wait.go b/stackit/internal/wait/sqlserverflexalpha/wait.go index 1999d89a..712347d1 100644 --- a/stackit/internal/wait/sqlserverflexalpha/wait.go +++ b/stackit/internal/wait/sqlserverflexalpha/wait.go @@ -244,6 +244,7 @@ func DeleteInstanceWaitHandler( return true, nil, nil }, ) + handler.SetTimeout(30 * time.Minute) return handler } @@ -385,5 +386,7 @@ func DeleteUserWaitHandler( } }, ) + handler.SetTimeout(15 * time.Minute) + handler.SetSleepBeforeWait(15 * time.Second) return handler } diff --git a/stackit/internal/wait/sqlserverflexbeta/wait.go b/stackit/internal/wait/sqlserverflexbeta/wait.go index ac85bc8d..2660cac5 100644 --- a/stackit/internal/wait/sqlserverflexbeta/wait.go +++ b/stackit/internal/wait/sqlserverflexbeta/wait.go @@ -264,6 +264,7 @@ func DeleteInstanceWaitHandler( return true, nil, nil }, ) + handler.SetTimeout(30 * time.Minute) return handler } @@ -405,5 +406,7 @@ func DeleteUserWaitHandler( } }, ) + handler.SetTimeout(15 * time.Minute) + handler.SetSleepBeforeWait(15 * time.Second) return handler } diff --git a/stackit/provider_acc_test.go b/stackit/provider_acc_test.go index d98bbace..2230d731 100644 --- a/stackit/provider_acc_test.go +++ b/stackit/provider_acc_test.go @@ -63,7 +63,6 @@ func TestMain(m *testing.M) { } func TestMshTest(t *testing.T) { - t.Skip("currently failing because of null pointer") httpmock.Activate() defer httpmock.DeactivateAndReset() @@ -75,7 +74,7 @@ func TestMshTest(t *testing.T) { token := jwt.NewWithClaims( jwt.SigningMethodHS256, jwt.MapClaims{ "foo": "bar", - "nbf": time.Date(2026, 12, 31, 12, 0, 0, 0, time.UTC).Unix(), + "nbf": time.Date(2015, 10, 10, 12, 0, 0, 0, time.UTC).Unix(), }, ) // Sign and get the complete encoded token as a string using the secret @@ -86,7 +85,7 @@ func TestMshTest(t *testing.T) { tR := clients.TokenResponseBody{ AccessToken: tokenString, - ExpiresIn: 36000, + ExpiresIn: 3600, RefreshToken: "", Scope: "", TokenType: "",