terraform-provider-stackitp.../stackit/internal/services/postgresflexalpha/postgresflex_acc_test.go
2026-05-20 21:29:25 +02:00

990 lines
31 KiB
Go

package postgresflexalpha_test
import (
"context"
_ "embed"
"fmt"
"log"
"math"
"os"
"regexp"
"strconv"
"strings"
"testing"
"time"
"github.com/hashicorp/terraform-plugin-testing/compare"
"github.com/hashicorp/terraform-plugin-testing/helper/acctest"
"github.com/hashicorp/terraform-plugin-testing/helper/resource"
"github.com/hashicorp/terraform-plugin-testing/knownvalue"
"github.com/hashicorp/terraform-plugin-testing/plancheck"
"github.com/hashicorp/terraform-plugin-testing/statecheck"
"github.com/hashicorp/terraform-plugin-testing/terraform"
"github.com/hashicorp/terraform-plugin-testing/tfjsonpath"
"github.com/stackitcloud/stackit-sdk-go/core/config"
"github.com/stackitcloud/stackit-sdk-go/core/utils"
"github.com/stackitcloud/stackit-sdk-go/services/postgresflex/v3alpha1api"
"tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit/internal/core"
postgresflexalphaInstance "tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit/internal/services/postgresflexalpha/instance"
"tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit/internal/wait/postgresflexalpha"
"tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/internal/testutils"
// The fwresource import alias is so there is no collision
// with the more typical acceptance testing import:
// "github.com/hashicorp/terraform-plugin-testing/helper/resource"
fwresource "github.com/hashicorp/terraform-plugin-framework/resource"
)
const (
pfx = "stackitprivatepreview_postgresflexalpha"
dataPfx = "data.stackitprivatepreview_postgresflexalpha"
singleFlavorID = "2.4"
replicasFlavorID = "2.4-replica"
)
func TestInstanceResourceSchema(t *testing.T) {
// t.Parallel()
ctx := context.Background()
schemaRequest := fwresource.SchemaRequest{}
schemaResponse := &fwresource.SchemaResponse{}
// Instantiate the resource.Resource and call its Schema method
postgresflexalphaInstance.NewInstanceResource().Schema(ctx, schemaRequest, schemaResponse)
if schemaResponse.Diagnostics.HasError() {
t.Fatalf("Schema method diagnostics: %+v", schemaResponse.Diagnostics)
}
// Validate the schema
diagnostics := schemaResponse.Schema.ValidateImplementation(ctx)
if diagnostics.HasError() {
t.Fatalf("Schema validation diagnostics: %+v", diagnostics)
}
}
func TestMain(m *testing.M) {
testutils.Setup()
code := m.Run()
// shutdown()
os.Exit(code)
}
func testAccPreCheck(t *testing.T) {
if _, ok := os.LookupEnv("TF_ACC_PROJECT_ID"); !ok {
t.Fatalf("could not find env var TF_ACC_PROJECT_ID")
}
}
type resData struct {
ServiceAccountFilePath string
ProjectID string
Region string
Name string
TfName string
FlavorID *string
BackupSchedule string
UseEncryption bool
KekKeyID string
KekKeyRingID string
KekKeyVersion uint8
KekServiceAccount string
PerformanceClass string
Replicas uint32
Size uint32
ACLStrings []string
AccessScope string
RetentionDays uint32
Version string
Users []User
Databases []Database
DataSourceTest bool
}
type User struct {
Name string
ProjectID string
Roles []string
}
type Database struct {
Name string
ProjectID string
Owner string
}
func getExample() resData {
name := acctest.RandomWithPrefix("tf-acc")
return resData{
Region: os.Getenv("TF_ACC_REGION"),
ServiceAccountFilePath: os.Getenv("TF_ACC_SERVICE_ACCOUNT_FILE"),
ProjectID: os.Getenv("TF_ACC_PROJECT_ID"),
Name: name,
TfName: name,
FlavorID: utils.Ptr(singleFlavorID),
BackupSchedule: "0 0 * * *",
UseEncryption: false,
RetentionDays: 33,
Replicas: 1,
PerformanceClass: "premium-perf2-stackit",
Size: 10,
ACLStrings: []string{"0.0.0.0/0"},
AccessScope: "PUBLIC",
Version: "17",
}
}
func TestAccInstance(t *testing.T) {
exData := getExample()
exData.Version = "16"
updNameData := exData
updNameData.Name = "name-updated"
updSizeData := exData
updSizeData.Size = 25
updBackupSched := updSizeData
// api should complain about more than one daily backup
updBackupSched.BackupSchedule = "30 3 * * *"
updNetACL := updBackupSched
updNetACL.ACLStrings = append(updNetACL.ACLStrings, "192.168.0.0/24")
updVersion := updNetACL
updVersion.Version = "17"
testItemID := testutils.ResStr(pfx, "instance", exData.TfName)
compareValuesSame := statecheck.CompareValue(compare.ValuesSame())
resource.ParallelTest(
t, resource.TestCase{
PreCheck: func() {
testAccPreCheck(t)
t.Logf(" ... %s - %s", t.Name(), exData.TfName)
},
CheckDestroy: testAccCheckPostgresFlexDestroy,
ProtoV6ProviderFactories: testutils.TestAccProtoV6ProviderFactories,
Steps: []resource.TestStep{
// Create and verify
{
PreConfig: func() {
t.Logf("testing: %s - %s", t.Name(), "create and verify")
},
Config: testutils.StringFromTemplateMust(
"testdata/instance_template.gompl",
exData,
),
ConfigStateChecks: []statecheck.StateCheck{
compareValuesSame.AddStateValue(
testItemID,
tfjsonpath.New("id"),
),
statecheck.ExpectKnownValue(
testItemID,
tfjsonpath.New("is_deletable"),
knownvalue.Bool(true),
),
statecheck.ExpectKnownValue(
testItemID,
tfjsonpath.New("connection_info"),
knownvalue.MapExact(map[string]knownvalue.Check{
"write": knownvalue.MapExact(map[string]knownvalue.Check{
"host": knownvalue.StringRegexp(regexp.MustCompile("[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}.postgresql.[a-z0-9]+.onstackit.cloud")),
"port": knownvalue.Int32Func(func(v int32) error {
if v < 0 {
return fmt.Errorf("value is negative")
}
if v <= 1024 {
return fmt.Errorf("value uses protected port range")
}
return nil
}),
}),
}),
),
},
Check: defaultNoEncInstanceTestChecks(testItemID, exData),
},
// Second apply should not have changes
{
PreConfig: func() {
t.Logf(" ... %s - %s", t.Name(), "second apply")
},
Config: testutils.StringFromTemplateMust(
"testdata/instance_template.gompl",
exData,
),
ConfigPlanChecks: resource.ConfigPlanChecks{
PreApply: []plancheck.PlanCheck{
plancheck.ExpectEmptyPlan(),
},
},
ConfigStateChecks: []statecheck.StateCheck{
compareValuesSame.AddStateValue(
testItemID,
tfjsonpath.New("id"),
),
statecheck.ExpectKnownValue(
testItemID,
tfjsonpath.New("is_deletable"),
knownvalue.Bool(true),
),
},
},
// Refresh state test
{
PreConfig: func() {
t.Logf(" ... %s - %s", t.Name(), "refresh state")
},
RefreshState: true,
},
// Update name and verify
{
PreConfig: func() {
t.Logf(" ... %s - %s", t.Name(), "update name")
},
Config: testutils.StringFromTemplateMust(
"testdata/instance_template.gompl",
updNameData,
),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(
testItemID,
"name",
updNameData.Name,
),
),
ConfigPlanChecks: resource.ConfigPlanChecks{
PreApply: []plancheck.PlanCheck{
plancheck.ExpectNonEmptyPlan(),
},
},
},
// Update size and verify
{
PreConfig: func() {
t.Logf(" ... %s - %s", t.Name(), "update storage.size")
},
Config: testutils.StringFromTemplateMust(
"testdata/instance_template.gompl",
updSizeData,
),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(
testItemID,
"storage.size",
strconv.Itoa(int(updSizeData.Size)),
),
// network should contain 4 sub entries
resource.TestCheckResourceAttr(testItemID, "network.acl.#", "1"),
),
},
// Update backup schedule
{
PreConfig: func() {
t.Logf(" ... %s - %s", t.Name(), "update backup schedule")
},
Config: testutils.StringFromTemplateMust(
"testdata/instance_template.gompl",
updBackupSched,
),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(
testItemID,
"backup_schedule",
updBackupSched.BackupSchedule,
),
// network should contain 4 sub entries
resource.TestCheckResourceAttr(testItemID, "network.acl.#", "1"),
),
},
// Update network ACL
{
PreConfig: func() {
t.Logf(" ... %s - %s", t.Name(), "update network.acl")
},
Config: testutils.StringFromTemplateMust(
"testdata/instance_template.gompl",
updNetACL,
),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(
testItemID,
"backup_schedule",
updBackupSched.BackupSchedule,
),
// network should contain 4 sub entries
resource.TestCheckResourceAttr(testItemID, "network.acl.#", "2"),
),
},
// Update version
{
PreConfig: func() {
t.Logf(" ... %s - %s", t.Name(), "update version")
},
Config: testutils.StringFromTemplateMust(
"testdata/instance_template.gompl",
updVersion,
),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(
testItemID,
"version",
updVersion.Version,
),
),
},
// Import test
// test instance imports
{
PreConfig: func() {
t.Logf(" ... %s - %s", t.Name(), "import instance")
},
ResourceName: testItemID,
// ImportStateIdPrefix: "",
// ImportStateVerifyIdentifierAttribute: "id",
ImportStateIdFunc: getInstanceTestID(exData.TfName),
ImportStateKind: resource.ImportCommandWithID,
ImportState: true,
ImportStateVerify: true,
},
},
},
)
}
func TestAccInstanceHA(t *testing.T) {
data := getExample()
data.FlavorID = utils.Ptr(replicasFlavorID)
data.Replicas = 3
testItemID := testutils.ResStr(pfx, "instance", data.TfName)
resource.ParallelTest(
t, resource.TestCase{
PreCheck: func() {
testAccPreCheck(t)
t.Logf(" ... %s - %s", t.Name(), data.TfName)
},
CheckDestroy: testAccCheckPostgresFlexDestroy,
ProtoV6ProviderFactories: testutils.TestAccProtoV6ProviderFactories,
Steps: []resource.TestStep{
// Create and verify
{
PreConfig: func() {
t.Logf(" ... %s - %s", t.Name(), "create and verify")
},
Config: testutils.StringFromTemplateMust(
"testdata/instance_template.gompl",
data,
),
Check: defaultNoEncInstanceTestChecks(testItemID, data),
},
},
},
)
}
func TestAccInstanceWithUsers(t *testing.T) {
data := getExample()
userName := "testUser"
data.Users = []User{
{
Name: userName,
ProjectID: os.Getenv("TF_ACC_PROJECT_ID"),
Roles: []string{"login"},
},
}
testItemID := testutils.ResStr(pfx, "instance", data.TfName)
// TODO : implement check multiple users
testUserItemID := testutils.ResStr(pfx, "user", userName)
resource.ParallelTest(
t, resource.TestCase{
PreCheck: func() {
testAccPreCheck(t)
t.Logf(" ... %s - %s", t.Name(), data.TfName)
},
CheckDestroy: testAccCheckPostgresFlexDestroy,
ProtoV6ProviderFactories: testutils.TestAccProtoV6ProviderFactories,
Steps: []resource.TestStep{
// Create and verify
{
PreConfig: func() {
t.Logf(" ... %s - %s", t.Name(), "create and verify")
},
Config: testutils.StringFromTemplateMust(
"testdata/instance_template.gompl",
data,
),
Check: resource.ComposeAggregateTestCheckFunc(
defaultNoEncInstanceTestChecks(testItemID, data),
resource.TestCheckResourceAttr(testUserItemID, "name", userName),
resource.TestCheckResourceAttrSet(testUserItemID, "id"),
resource.TestCheckResourceAttr(testUserItemID, "roles.#", "1"),
),
},
},
},
)
}
func TestAccInstanceWithDatabases(t *testing.T) {
data := getExample()
dbName := "testdb"
userName := "testUser"
data.Users = []User{
{
Name: userName,
ProjectID: os.Getenv("TF_ACC_PROJECT_ID"),
Roles: []string{"login"},
},
}
data.Databases = []Database{
{
Name: dbName,
ProjectID: os.Getenv("TF_ACC_PROJECT_ID"),
Owner: userName,
},
}
data.DataSourceTest = true
testItemID := testutils.ResStr(pfx, "instance", data.TfName)
resource.ParallelTest(
t, resource.TestCase{
PreCheck: func() {
testAccPreCheck(t)
t.Logf(" ... %s - %s", t.Name(), data.TfName)
},
CheckDestroy: testAccCheckPostgresFlexDestroy,
ProtoV6ProviderFactories: testutils.TestAccProtoV6ProviderFactories,
Steps: []resource.TestStep{
// Create and verify
{
PreConfig: func() {
t.Logf(" ... %s - %s", t.Name(), "create and verify")
},
Config: testutils.StringFromTemplateMust(
"testdata/instance_template.gompl",
data,
),
Check: resource.ComposeAggregateTestCheckFunc(
defaultNoEncInstanceTestChecks(testItemID, data),
// TODO - extract also to functions
resource.TestCheckResourceAttr(testutils.ResStr(pfx, "user", userName), "name", userName),
resource.TestCheckResourceAttrSet(testutils.ResStr(pfx, "user", userName), "id"),
resource.TestCheckResourceAttrPair(
testItemID, "project_id",
testutils.ResStr(pfx, "user", userName), "project_id",
),
resource.TestCheckResourceAttrPair(
testItemID, "instance_id",
testutils.ResStr(pfx, "user", userName), "instance_id",
),
// TODO - extract also to functions
resource.TestCheckResourceAttr(testutils.ResStr(pfx, "database", dbName), "name", dbName),
resource.TestCheckResourceAttr(testutils.ResStr(pfx, "database", dbName), "owner", userName),
resource.TestCheckResourceAttrSet(testutils.ResStr(pfx, "database", dbName), "id"),
resource.TestCheckResourceAttrPair(
testItemID, "project_id",
testutils.ResStr(pfx, "database", dbName), "project_id",
),
resource.TestCheckResourceAttrPair(
testItemID, "instance_id",
testutils.ResStr(pfx, "database", dbName), "instance_id",
),
),
},
// data source
{
PreConfig: func() {
t.Logf(" ... %s - %s", t.Name(), "datasource")
},
Config: testutils.StringFromTemplateMust(
"testdata/instance_template.gompl",
data,
),
Check: resource.ComposeAggregateTestCheckFunc(
// Instance data
resource.TestCheckResourceAttr(
testutils.ResStr(dataPfx, "instance", data.TfName),
"project_id",
data.ProjectID,
),
resource.TestCheckResourceAttr(
testutils.ResStr(dataPfx, "instance", data.TfName),
"name",
data.Name,
),
resource.TestCheckResourceAttrPair(
testutils.ResStr(dataPfx, "instance", data.TfName), "project_id",
testutils.ResStr(pfx, "instance", data.TfName), "project_id",
),
resource.TestCheckResourceAttrPair(
testutils.ResStr(dataPfx, "database", dbName), "instance_id",
testutils.ResStr(pfx, "instance", data.TfName), "instance_id",
),
resource.TestCheckResourceAttrPair(
testutils.ResStr(dataPfx, "user", userName), "instance_id",
testutils.ResStr(pfx, "instance", data.TfName), "instance_id",
),
resource.TestCheckResourceAttrPair(
testutils.ResStr(dataPfx, "user", userName), "instance_id",
testutils.ResStr(pfx, "user", userName), "instance_id",
),
// User data
resource.TestCheckResourceAttr(
testutils.ResStr(dataPfx, "user", userName),
"project_id",
data.ProjectID,
),
resource.TestCheckResourceAttrSet(
testutils.ResStr(dataPfx, "user", userName),
"user_id",
),
resource.TestCheckResourceAttr(
testutils.ResStr(dataPfx, "user", userName),
"name",
data.Users[0].Name,
),
resource.TestCheckResourceAttr(
testutils.ResStr(dataPfx, "user", userName),
"roles.#",
"1",
),
resource.TestCheckResourceAttr(
testutils.ResStr(dataPfx, "user", userName),
"roles.0",
data.Users[0].Roles[0],
),
// Database data
resource.TestCheckResourceAttr(
testutils.ResStr(dataPfx, "database", dbName),
"project_id",
data.ProjectID,
),
resource.TestCheckResourceAttr(
testutils.ResStr(dataPfx, "database", dbName),
"name",
dbName,
),
resource.TestCheckResourceAttrPair(
testutils.ResStr(dataPfx, "database", dbName),
"instance_id",
testutils.ResStr(pfx, "database", dbName),
"instance_id",
),
resource.TestCheckResourceAttrPair(
testutils.ResStr(dataPfx, "database", dbName),
"owner",
testutils.ResStr(dataPfx, "user", userName),
"name",
),
),
},
// test instance imports
{
PreConfig: func() {
t.Logf(" ... %s - %s", t.Name(), "import instance")
},
ResourceName: testItemID,
// ImportStateIdPrefix: "",
ImportStateVerifyIdentifierAttribute: "id",
ImportStateIdFunc: getInstanceTestID(data.TfName),
ImportStateKind: resource.ImportCommandWithID,
ImportState: true,
ImportStateVerify: true,
},
// test database imports
{
PreConfig: func() {
t.Logf(" ... %s - %s", t.Name(), "import database")
},
ResourceName: testutils.ResStr(pfx, "database", dbName),
// ImportStateIdPrefix: "",
// ImportStateVerifyIdentifierAttribute: "id",
ImportStateIdFunc: getDatabaseTestID(dbName),
ImportStateKind: resource.ImportCommandWithID,
ImportState: true,
ImportStateVerify: true,
},
// test user imports
{
PreConfig: func() {
t.Logf(" ... %s - %s", t.Name(), "import user")
},
ResourceName: testutils.ResStr(pfx, "user", userName),
// ImportStateIdPrefix: "",
// ImportStateVerifyIdentifierAttribute: "id",
ImportStateIdFunc: getUserTestID(userName),
ImportStateKind: resource.ImportCommandWithID,
ImportState: true,
ImportStateVerify: true,
ImportStateVerifyIgnore: []string{"password"},
},
},
},
)
}
func TestAccEncryptedInstanceWithDatabases(t *testing.T) {
encKekKeyID, ok := os.LookupEnv("TF_ACC_KEK_KEY_ID")
if !ok || encKekKeyID == "" {
t.Skip("env var TF_ACC_KEK_KEY_ID needed for encryption test")
}
encKekKeyRingID, ok := os.LookupEnv("TF_ACC_KEK_KEY_RING_ID")
if !ok || encKekKeyRingID == "" {
t.Skip("env var TF_ACC_KEK_KEY_RING_ID needed for encryption test")
}
encKekKeyVersion, ok := os.LookupEnv("TF_ACC_KEK_KEY_VERSION")
if !ok || encKekKeyVersion == "" {
t.Skip("env var TF_ACC_KEK_KEY_VERSION needed for encryption test")
}
encSvcAcc, ok := os.LookupEnv("TF_ACC_KEK_SERVICE_ACCOUNT")
if !ok || encSvcAcc == "" {
t.Skip("env var TF_ACC_KEK_SERVICE_ACCOUNT needed for encryption test")
}
data := getExample()
data.UseEncryption = true
data.KekKeyID = encKekKeyID
data.KekKeyRingID = encKekKeyRingID
data.KekServiceAccount = encSvcAcc
encKekKeyVersionInt, err := strconv.Atoi(encKekKeyVersion)
if err != nil {
t.Errorf("error converting string to int")
}
if encKekKeyVersionInt > math.MaxUint8 {
t.Errorf("value too large to convert to uint8")
}
data.KekKeyVersion = uint8(encKekKeyVersionInt) //nolint:gosec // handled above
dbName := "testdb"
userName := "testUser"
data.Users = []User{
{
Name: userName,
ProjectID: os.Getenv("TF_ACC_PROJECT_ID"),
Roles: []string{"login"},
},
}
data.Databases = []Database{
{
Name: dbName,
ProjectID: os.Getenv("TF_ACC_PROJECT_ID"),
Owner: userName,
},
}
testItemID := testutils.ResStr(pfx, "instance", data.TfName)
resource.ParallelTest(
t, resource.TestCase{
PreCheck: func() {
testAccPreCheck(t)
t.Logf(" ... %s - %s", t.Name(), data.TfName)
},
CheckDestroy: testAccCheckPostgresFlexDestroy,
ProtoV6ProviderFactories: testutils.TestAccProtoV6ProviderFactories,
Steps: []resource.TestStep{
// Create and verify
{
PreConfig: func() {
t.Logf(" ... %s - %s", t.Name(), "create and verify")
},
Config: testutils.StringFromTemplateMust(
"testdata/instance_template.gompl",
data,
),
Check: resource.ComposeAggregateTestCheckFunc(
defaultEncInstanceTestChecks(testItemID, data),
resource.TestCheckResourceAttr(testutils.ResStr(pfx, "user", userName), "name", userName),
resource.TestCheckResourceAttrSet(testutils.ResStr(pfx, "user", userName), "id"),
resource.TestCheckResourceAttr(testutils.ResStr(pfx, "database", dbName), "name", dbName),
resource.TestCheckResourceAttr(testutils.ResStr(pfx, "database", dbName), "owner", userName),
resource.TestCheckResourceAttrSet(testutils.ResStr(pfx, "database", dbName), "id"),
),
},
},
},
)
}
func testAccCheckPostgresFlexDestroy(s *terraform.State) error {
testutils.Setup()
pID, ok := os.LookupEnv("TF_ACC_PROJECT_ID")
if !ok {
log.Fatalln("unable to read TF_ACC_PROJECT_ID")
}
ctx := context.Background()
var client *v3alpha1api.APIClient
var err error
var region, projectID string
region = testutils.Region
if region == "" {
region = "eu01"
}
projectID = pID
if projectID == "" {
return fmt.Errorf("projectID could not be determined in destroy function")
}
apiClientConfigOptions := []config.ConfigurationOption{
config.WithServiceAccountKeyPath(os.Getenv("TF_ACC_SERVICE_ACCOUNT_FILE")),
config.WithRegion(region),
}
if testutils.PostgresFlexCustomEndpoint != "" {
apiClientConfigOptions = append(
apiClientConfigOptions,
config.WithEndpoint(testutils.PostgresFlexCustomEndpoint),
)
}
client, err = v3alpha1api.NewAPIClient(apiClientConfigOptions...)
if err != nil {
log.Fatalln(err)
}
instancesToDestroy := []string{}
for _, rs := range s.RootModule().Resources {
if rs.Type != "stackitprivatepreview_postgresflexalpha_instance" &&
rs.Type != "stackitprivatepreview_postgresflexbeta_instance" {
continue
}
// instance terraform ID: = "[project_id],[region],[instance_id]"
instanceID := strings.Split(rs.Primary.ID, core.Separator)[2]
instancesToDestroy = append(instancesToDestroy, instanceID)
}
instancesResp, err := client.DefaultAPI.ListInstancesRequest(ctx, projectID, region).
Size(100).
Execute()
if err != nil {
return fmt.Errorf("getting instancesResp: %w", err)
}
items := instancesResp.GetInstances()
for i := range items {
if items[i].Id == "" {
continue
}
if utils.Contains(instancesToDestroy, items[i].Id) {
err := client.DefaultAPI.DeleteInstanceRequest(ctx, testutils.ProjectId, region, items[i].Id).Execute()
if err != nil {
return fmt.Errorf("deleting instance %s during CheckDestroy: %w", items[i].Id, err)
}
err = postgresflexalpha.DeleteInstanceWaitHandler(
ctx,
client.DefaultAPI,
testutils.ProjectId,
testutils.Region,
items[i].Id,
30*time.Minute,
10*time.Second,
)
if err != nil {
return fmt.Errorf("deleting instance %s during CheckDestroy: waiting for deletion %w", items[i].Id, err)
}
}
}
return nil
}
func defaultNoEncInstanceTestChecks(testItemID string, data resData) resource.TestCheckFunc {
return resource.ComposeAggregateTestCheckFunc(
defaultInstanceTestChecks(testItemID, data),
// check absent attr
resource.TestCheckNoResourceAttr(testItemID, "encryption"),
resource.TestCheckNoResourceAttr(testItemID, "encryption.kek_key_id"),
resource.TestCheckNoResourceAttr(testItemID, "encryption.kek_key_ring_id"),
resource.TestCheckNoResourceAttr(testItemID, "encryption.kek_key_version"),
resource.TestCheckNoResourceAttr(testItemID, "encryption.service_account"),
)
}
func defaultEncInstanceTestChecks(testItemID string, data resData) resource.TestCheckFunc {
return resource.ComposeAggregateTestCheckFunc(
defaultInstanceTestChecks(testItemID, data),
// check absent attr
resource.TestCheckResourceAttr(testItemID, "encryption.%", "4"),
resource.TestCheckResourceAttrSet(testItemID, "encryption.kek_key_id"),
resource.TestCheckResourceAttr(testItemID, "encryption.kek_key_id", data.KekKeyID),
resource.TestCheckResourceAttrSet(testItemID, "encryption.kek_key_ring_id"),
resource.TestCheckResourceAttr(testItemID, "encryption.kek_key_ring_id", data.KekKeyRingID),
resource.TestCheckResourceAttrSet(testItemID, "encryption.kek_key_version"),
resource.TestCheckResourceAttr(testItemID, "encryption.kek_key_version", strconv.Itoa(int(data.KekKeyVersion))),
resource.TestCheckResourceAttrSet(testItemID, "encryption.service_account"),
resource.TestCheckResourceAttr(testItemID, "encryption.service_account", data.KekServiceAccount),
)
}
func defaultInstanceTestChecks(testItemID string, data resData) resource.TestCheckFunc {
// if AccessScope == SNA these are set
if data.AccessScope == "SNA" {
return resource.ComposeAggregateTestCheckFunc(
basicInstanceTestChecks(testItemID, data),
resource.TestCheckResourceAttrSet(testItemID, "network.instance_address"),
resource.TestCheckResourceAttrSet(testItemID, "network.router_address"),
)
}
// if AccessScope == PUBLIC these are empty - but they are set
return resource.ComposeAggregateTestCheckFunc(
basicInstanceTestChecks(testItemID, data),
resource.TestCheckResourceAttr(testItemID, "network.instance_address", ""),
resource.TestCheckResourceAttr(testItemID, "network.router_address", ""),
)
}
func basicInstanceTestChecks(testItemID string, data resData) resource.TestCheckFunc {
return resource.ComposeAggregateTestCheckFunc(
resource.TestCheckResourceAttrSet(testItemID, "backup_schedule"),
resource.TestCheckResourceAttr(testItemID, "backup_schedule", data.BackupSchedule),
resource.TestCheckResourceAttr(testItemID, "connection_info.%", "1"),
resource.TestCheckResourceAttr(testItemID, "connection_info.write.%", "2"),
resource.TestCheckResourceAttrSet(testItemID, "connection_info.write.host"),
resource.TestCheckResourceAttrSet(testItemID, "connection_info.write.port"),
resource.TestCheckResourceAttrSet(testItemID, "flavor_id"),
resource.TestCheckResourceAttr(testItemID, "flavor_id", data.FlavorID),
resource.TestCheckResourceAttrSet(testItemID, "id"),
resource.TestCheckResourceAttrSet(testItemID, "instance_id"),
resource.TestCheckResourceAttrSet(testItemID, "is_deletable"),
resource.TestCheckResourceAttr(testItemID, "is_deletable", "true"),
resource.TestCheckResourceAttrSet(testItemID, "name"),
resource.TestCheckResourceAttr(testItemID, "name", data.Name),
// network params check
resource.TestCheckResourceAttr(testItemID, "network.%", "4"),
resource.TestCheckResourceAttrSet(testItemID, "network.access_scope"),
resource.TestCheckResourceAttr(testItemID, "network.access_scope", data.AccessScope),
// resource.TestCheckResourceAttrSet(testItemID, "network.acl"),
resource.TestCheckResourceAttr(testItemID, "network.acl.#", strconv.Itoa(len(data.ACLStrings))),
// instance_address and router_address are only checked in enc
resource.TestCheckResourceAttrSet(testItemID, "project_id"),
resource.TestCheckResourceAttr(testItemID, "project_id", data.ProjectID),
resource.TestCheckResourceAttrSet(testItemID, "region"),
resource.TestCheckResourceAttr(testItemID, "region", data.Region),
resource.TestCheckResourceAttrSet(testItemID, "replicas"),
resource.TestCheckResourceAttr(testItemID, "replicas", strconv.Itoa(int(data.Replicas))),
resource.TestCheckResourceAttrSet(testItemID, "retention_days"),
resource.TestCheckResourceAttr(testItemID, "retention_days", strconv.Itoa(int(data.RetentionDays))),
resource.TestCheckResourceAttrSet(testItemID, "status"),
resource.TestCheckResourceAttr(testItemID, "status", "READY"),
// storage params check
resource.TestCheckResourceAttr(testItemID, "storage.%", "2"),
resource.TestCheckResourceAttrSet(testItemID, "storage.performance_class"),
resource.TestCheckResourceAttr(testItemID, "storage.performance_class", data.PerformanceClass),
resource.TestCheckResourceAttrSet(testItemID, "storage.size"),
resource.TestCheckResourceAttr(testItemID, "storage.size", strconv.Itoa(int(data.Size))),
resource.TestCheckResourceAttrSet(testItemID, "version"),
resource.TestCheckResourceAttr(testItemID, "version", data.Version),
)
}
func getInstanceTestID(name string) func(s *terraform.State) (string, error) {
return func(s *terraform.State) (string, error) {
r, ok := s.RootModule().Resources[testutils.ResStr(pfx, "instance", name)]
if !ok {
return "", fmt.Errorf("couldn't find resource stackitprivatepreview_postgresflexalpha_instance.%s", name)
}
projectID, ok := r.Primary.Attributes["project_id"]
if !ok {
return "", fmt.Errorf("couldn't find attribute project_id")
}
region, ok := r.Primary.Attributes["region"]
if !ok {
return "", fmt.Errorf("couldn't find attribute region")
}
instanceID, ok := r.Primary.Attributes["instance_id"]
if !ok {
return "", fmt.Errorf("couldn't find attribute instance_id")
}
return fmt.Sprintf("%s,%s,%s", projectID, region, instanceID), nil
}
}
func getDatabaseTestID(name string) func(s *terraform.State) (string, error) {
return func(s *terraform.State) (string, error) {
r, ok := s.RootModule().Resources[testutils.ResStr(pfx, "database", name)]
if !ok {
return "", fmt.Errorf("couldn't find resource stackitprivatepreview_postgresflexalpha_instance.%s", name)
}
projectID, ok := r.Primary.Attributes["project_id"]
if !ok {
return "", fmt.Errorf("couldn't find attribute project_id")
}
region, ok := r.Primary.Attributes["region"]
if !ok {
return "", fmt.Errorf("couldn't find attribute region")
}
instanceID, ok := r.Primary.Attributes["instance_id"]
if !ok {
return "", fmt.Errorf("couldn't find attribute instance_id")
}
databaseID, ok := r.Primary.Attributes["database_id"]
if !ok {
return "", fmt.Errorf("couldn't find attribute database_id")
}
return fmt.Sprintf("%s,%s,%s,%s", projectID, region, instanceID, databaseID), nil
}
}
func getUserTestID(name string) func(s *teraform.State) (string, error) {
return func(s *terraform.State) (string, error) {
r, ok := s.RootModule().Resources[testutils.ResStr(pfx, "user", name)]
if !ok {
return "", fmt.Errorf("couldn't find resource stackitprivatepreview_postgresflexalpha_instance.%s", name)
}
projectID, ok := r.Primary.Attributes["project_id"]
if !ok {
return "", fmt.Errorf("couldn't find attribute project_id")
}
region, ok := r.Primary.Attributes["region"]
if !ok {
return "", fmt.Errorf("couldn't find attribute region")
}
instanceID, ok := r.Primary.Attributes["instance_id"]
if !ok {
return "", fmt.Errorf("couldn't find attribute instance_id")
}
userID, ok := r.Primary.Attributes["user_id"]
if !ok {
return "", fmt.Errorf("couldn't find attribute user_id")
}
return fmt.Sprintf("%s,%s,%s,%s", projectID, region, instanceID, userID), nil
}
}