Skip to content

Commit b4bbd64

Browse files
authored
feat: block unsupported Gen 2 plans with helpful validation message (IBM-Cloud#6571)
* feat: block unsupported Gen 2 plans with helpful validation message * Add tests * Match any gen2 plans
1 parent a444928 commit b4bbd64

File tree

3 files changed

+108
-2
lines changed

3 files changed

+108
-2
lines changed

ibm/service/database/resource_ibm_database.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -897,7 +897,7 @@ func ResourceIBMICDValidator() *validate.ResourceValidator {
897897
validateSchema = append(validateSchema,
898898
validate.ValidateSchema{
899899
Identifier: "plan",
900-
ValidateFunctionIdentifier: validate.ValidateAllowedStringValue,
900+
ValidateFunctionIdentifier: validate.ValidateAllowedICDPlanValue,
901901
Type: validate.TypeString,
902902
AllowedValues: "standard, enterprise, enterprise-sharding, platinum",
903903
Required: true})

ibm/service/database/resource_ibm_database_postgresql_test.go

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ package database_test
55

66
import (
77
"fmt"
8+
"regexp"
89
"testing"
910

1011
acc "github.com/IBM-Cloud/terraform-provider-ibm/ibm/acctest"
@@ -66,6 +67,25 @@ func TestAccIBMDatabaseInstancePostgresBasic(t *testing.T) {
6667
})
6768
}
6869

70+
func TestAccIBMDatabaseInstancePostgresGen2(t *testing.T) {
71+
t.Parallel()
72+
databaseResourceGroup := "default"
73+
rnd := fmt.Sprintf("tf-Pgress-%d", acctest.RandIntRange(10, 100))
74+
testName := rnd
75+
76+
resource.Test(t, resource.TestCase{
77+
PreCheck: func() { acc.TestAccPreCheck(t) },
78+
Providers: acc.TestAccProviders,
79+
CheckDestroy: testAccCheckIBMDatabaseInstanceDestroy,
80+
Steps: []resource.TestStep{
81+
{
82+
Config: testAccCheckIBMDatabaseInstancePostgreGen2(databaseResourceGroup, testName),
83+
ExpectError: regexp.MustCompile(`The plan "standard-gen2" corresponds to a Gen 2 database\. Gen 2 instances are not supported by the ibm_database resource\.`),
84+
},
85+
},
86+
})
87+
}
88+
6989
func TestAccIBMDatabaseInstancePostgresGroup(t *testing.T) {
7090
t.Parallel()
7191
databaseResourceGroup := "default"
@@ -348,6 +368,58 @@ func testAccCheckIBMDatabaseInstancePostgresBasic(databaseResourceGroup string,
348368
`, databaseResourceGroup, name, acc.Region())
349369
}
350370

371+
func testAccCheckIBMDatabaseInstancePostgreGen2(databaseResourceGroup string, name string) string {
372+
return fmt.Sprintf(`
373+
data "ibm_resource_group" "test_acc" {
374+
name = "%[1]s"
375+
}
376+
377+
resource "ibm_database" "%[2]s" {
378+
resource_group_id = data.ibm_resource_group.test_acc.id
379+
name = "%[2]s"
380+
service = "databases-for-postgresql"
381+
plan = "standard-gen2"
382+
location = "%[3]s"
383+
adminpassword = "secure-Password12345"
384+
service_endpoints = "public"
385+
group {
386+
group_id = "member"
387+
388+
memory {
389+
allocation_mb = 4096
390+
}
391+
host_flavor {
392+
id = "multitenant"
393+
}
394+
disk {
395+
allocation_mb = 10240
396+
}
397+
}
398+
tags = ["one:two"]
399+
users {
400+
name = "user123"
401+
password = "secure-Password12345"
402+
}
403+
allowlist {
404+
address = "172.168.1.2/32"
405+
description = "desc1"
406+
}
407+
configuration = <<CONFIGURATION
408+
{
409+
"wal_level": "logical",
410+
"max_replication_slots": 21,
411+
"max_wal_senders": 21
412+
}
413+
CONFIGURATION
414+
logical_replication_slot {
415+
name = "wj123"
416+
database_name = "ibmclouddb"
417+
plugin_type = "wal2json"
418+
}
419+
}
420+
`, databaseResourceGroup, name, acc.Region())
421+
}
422+
351423
func testAccCheckIBMDatabaseInstancePostgresFullyspecified(databaseResourceGroup string, name string) string {
352424
return fmt.Sprintf(`
353425
data "ibm_resource_group" "test_acc" {

ibm/validate/validators.go

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,36 @@ func validateServiceTags(v interface{}, k string) (ws []string, errors []error)
4848
return
4949
}
5050

51+
func validateAllowedICDPlanValues(validValues []string) schema.SchemaValidateFunc {
52+
return func(v interface{}, k string) (ws []string, errors []error) {
53+
input := v.(string)
54+
gen2Pattern := regexp.MustCompile(`-gen2($|-.+)`)
55+
if gen2Pattern.MatchString(input) {
56+
errors = append(errors, fmt.Errorf(
57+
"The plan %q corresponds to a Gen 2 database. Gen 2 instances are not supported by the ibm_database resource. "+
58+
"Use the ibm_resource_instance resource instead for provisioning and management. "+
59+
"More info: ibm.biz/Gen2-overview",
60+
input,
61+
))
62+
return
63+
}
64+
65+
existed := false
66+
for _, s := range validValues {
67+
if s == input {
68+
existed = true
69+
break
70+
}
71+
}
72+
if !existed {
73+
errors = append(errors, fmt.Errorf(
74+
"%q must contain a value from %#v, got %q",
75+
k, validValues, input))
76+
}
77+
return
78+
}
79+
}
80+
5181
func ValidateAllowedStringValues(validValues []string) schema.SchemaValidateFunc {
5282
return func(v interface{}, k string) (ws []string, errors []error) {
5383
input := v.(string)
@@ -1076,6 +1106,7 @@ const (
10761106
IntAtLeast
10771107
IntAtMost
10781108
ValidateAllowedStringValue
1109+
ValidateAllowedICDPlanValue
10791110
StringLenBetween
10801111
ValidateIPorCIDR
10811112
ValidateCIDRAddress
@@ -1100,7 +1131,7 @@ func (f FunctionIdentifier) MarshalText() ([]byte, error) {
11001131

11011132
// Use stringer tool to generate this later.
11021133
func (i FunctionIdentifier) String() string {
1103-
return [...]string{"IntBetween", "IntAtLeast", "IntAtMost", "ValidateAllowedStringValue", "StringLenBetween", "ValidateIPorCIDR", "ValidateCIDRAddress", "ValidateAllowedIntValue", "ValidateRegexpLen", "ValidateRegexp", "ValidateNoZeroValues", "ValidateJSONString", "ValidateJSONParam", "ValidateBindedPackageName", "ValidateOverlappingAddress", "ValidateCloudData"}[i]
1134+
return [...]string{"IntBetween", "IntAtLeast", "IntAtMost", "ValidateAllowedStringValue", "ValidateAllowedICDPlanValue", "StringLenBetween", "ValidateIPorCIDR", "ValidateCIDRAddress", "ValidateAllowedIntValue", "ValidateRegexpLen", "ValidateRegexp", "ValidateNoZeroValues", "ValidateJSONString", "ValidateJSONParam", "ValidateBindedPackageName", "ValidateOverlappingAddress", "ValidateCloudData"}[i]
11041135
}
11051136

11061137
// ValueType -- Copied from Terraform for now. You can refer to Terraform ValueType directly.
@@ -1276,6 +1307,9 @@ func invokeValidatorInternal(schema ValidateSchema) schema.SchemaValidateFunc {
12761307
case ValidateAllowedStringValue:
12771308
allowedValues := schema.GetValue(AllowedValues)
12781309
return ValidateAllowedStringValues(allowedValues.([]string))
1310+
case ValidateAllowedICDPlanValue:
1311+
allowedValues := schema.GetValue(AllowedValues)
1312+
return validateAllowedICDPlanValues(allowedValues.([]string))
12791313
case StringLenBetween:
12801314
return validation.StringLenBetween(schema.MinValueLength, schema.MaxValueLength)
12811315
case ValidateIPorCIDR:

0 commit comments

Comments
 (0)