diff --git a/azurerm/resource_arm_postgresql_database.go b/azurerm/resource_arm_postgresql_database.go index a331e0257985..d05cce28919b 100644 --- a/azurerm/resource_arm_postgresql_database.go +++ b/azurerm/resource_arm_postgresql_database.go @@ -3,6 +3,7 @@ package azurerm import ( "fmt" "log" + "strings" "github.com/Azure/azure-sdk-for-go/services/postgresql/mgmt/2017-12-01/postgresql" "github.com/hashicorp/terraform/helper/schema" @@ -35,15 +36,17 @@ func resourceArmPostgreSQLDatabase() *schema.Resource { }, "charset": { - Type: schema.TypeString, - Required: true, - ForceNew: true, + Type: schema.TypeString, + Required: true, + DiffSuppressFunc: ignoreCaseDiffSuppressFunc, + ForceNew: true, }, "collation": { - Type: schema.TypeString, - Required: true, - ForceNew: true, + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validateCollation(), }, }, } @@ -118,8 +121,15 @@ func resourceArmPostgreSQLDatabaseRead(d *schema.ResourceData, meta interface{}) d.Set("name", resp.Name) d.Set("resource_group_name", resGroup) d.Set("server_name", serverName) - d.Set("charset", resp.Charset) - d.Set("collation", resp.Collation) + + if props := resp.DatabaseProperties; props != nil { + d.Set("charset", props.Charset) + + if collation := props.Collation; collation != nil { + v := strings.Replace(*collation, "-", "_", -1) + d.Set("collation", v) + } + } return nil } diff --git a/azurerm/resource_arm_postgresql_database_test.go b/azurerm/resource_arm_postgresql_database_test.go index 2f59a69d82a9..ccc438b05314 100644 --- a/azurerm/resource_arm_postgresql_database_test.go +++ b/azurerm/resource_arm_postgresql_database_test.go @@ -24,7 +24,50 @@ func TestAccAzureRMPostgreSQLDatabase_basic(t *testing.T) { Config: config, Check: resource.ComposeTestCheckFunc( testCheckAzureRMPostgreSQLDatabaseExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "charset", "UTF8"), + resource.TestCheckResourceAttr(resourceName, "collation", "English_United States.1252"), + ), + }, + }, + }) +} +func TestAccAzureRMPostgreSQLDatabase_charsetLowercase(t *testing.T) { + resourceName := "azurerm_postgresql_database.test" + ri := acctest.RandInt() + config := testAccAzureRMPostgreSQLDatabase_charsetLowercase(ri, testLocation()) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testCheckAzureRMPostgreSQLDatabaseDestroy, + Steps: []resource.TestStep{ + { + Config: config, + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMPostgreSQLDatabaseExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "charset", "UTF8"), + resource.TestCheckResourceAttr(resourceName, "collation", "English_United States.1252"), + ), + }, + }, + }) +} + +func TestAccAzureRMPostgreSQLDatabase_charsetMixedcase(t *testing.T) { + resourceName := "azurerm_postgresql_database.test" + ri := acctest.RandInt() + config := testAccAzureRMPostgreSQLDatabase_charsetMixedcase(ri, testLocation()) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testCheckAzureRMPostgreSQLDatabaseDestroy, + Steps: []resource.TestStep{ + { + Config: config, + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMPostgreSQLDatabaseExists(resourceName), resource.TestCheckResourceAttr(resourceName, "charset", "UTF8"), resource.TestCheckResourceAttr(resourceName, "collation", "English_United States.1252"), ), @@ -132,3 +175,85 @@ resource "azurerm_postgresql_database" "test" { } `, rInt, location, rInt, rInt) } + +func testAccAzureRMPostgreSQLDatabase_charsetLowercase(rInt int, location string) string { + return fmt.Sprintf(` +resource "azurerm_resource_group" "test" { + name = "acctestRG-%d" + location = "%s" +} + +resource "azurerm_postgresql_server" "test" { + name = "acctestpsqlsvr-%d" + location = "${azurerm_resource_group.test.location}" + resource_group_name = "${azurerm_resource_group.test.name}" + + sku { + name = "B_Gen4_2" + capacity = 2 + tier = "Basic" + family = "Gen4" + } + + storage_profile { + storage_mb = 51200 + backup_retention_days = 7 + geo_redundant_backup = "Disabled" + } + + administrator_login = "acctestun" + administrator_login_password = "H@Sh1CoR3!" + version = "9.6" + ssl_enforcement = "Enabled" +} + +resource "azurerm_postgresql_database" "test" { + name = "acctestdb_%d" + resource_group_name = "${azurerm_resource_group.test.name}" + server_name = "${azurerm_postgresql_server.test.name}" + charset = "utf8" + collation = "English_United States.1252" +} +`, rInt, location, rInt, rInt) +} + +func testAccAzureRMPostgreSQLDatabase_charsetMixedcase(rInt int, location string) string { + return fmt.Sprintf(` +resource "azurerm_resource_group" "test" { + name = "acctestRG-%d" + location = "%s" +} + +resource "azurerm_postgresql_server" "test" { + name = "acctestpsqlsvr-%d" + location = "${azurerm_resource_group.test.location}" + resource_group_name = "${azurerm_resource_group.test.name}" + + sku { + name = "B_Gen4_2" + capacity = 2 + tier = "Basic" + family = "Gen4" + } + + storage_profile { + storage_mb = 51200 + backup_retention_days = 7 + geo_redundant_backup = "Disabled" + } + + administrator_login = "acctestun" + administrator_login_password = "H@Sh1CoR3!" + version = "9.6" + ssl_enforcement = "Enabled" +} + +resource "azurerm_postgresql_database" "test" { + name = "acctestdb_%d" + resource_group_name = "${azurerm_resource_group.test.name}" + server_name = "${azurerm_postgresql_server.test.name}" + charset = "Utf8" + collation = "English_United States.1252" +} +`, rInt, location, rInt, rInt) +} diff --git a/azurerm/validators.go b/azurerm/validators.go index 5b567160f0c9..708cdaf2940b 100644 --- a/azurerm/validators.go +++ b/azurerm/validators.go @@ -99,3 +99,22 @@ func validateIntBetweenDivisibleBy(min, max, divisor int) schema.SchemaValidateF return } } + +func validateCollation() schema.SchemaValidateFunc { + return func(i interface{}, k string) (s []string, es []error) { + v, ok := i.(string) + if !ok { + es = append(es, fmt.Errorf("expected type of %s to be string", k)) + return + } + + matched, _ := regexp.MatchString(`^[A-Za-z0-9_. ]+$`, v) + + if !matched { + es = append(es, fmt.Errorf("%s contains invalid characters, only underscores are supported, got %s", k, v)) + return + } + + return + } +} diff --git a/azurerm/validators_test.go b/azurerm/validators_test.go index a6b379ee3160..0f130f48f388 100644 --- a/azurerm/validators_test.go +++ b/azurerm/validators_test.go @@ -178,7 +178,38 @@ func TestValidateIntBetweenDivisibleBy(t *testing.T) { for _, tc := range cases { _, errors := validateIntBetweenDivisibleBy(tc.Min, tc.Max, tc.Div)(tc.Value, strconv.Itoa(tc.Value.(int))) if len(errors) != tc.Errors { - t.Fatalf("Expected intBetweenDivisibleBy to trigger '%d' errors for '%s' - got '%d' ['%s']", tc.Errors, tc.Value, len(errors), errors[0]) + t.Fatalf("Expected intBetweenDivisibleBy to trigger '%d' errors for '%s' - got '%d'", tc.Errors, tc.Value, len(errors)) + } + } +} + +func TestValidateCollation(t *testing.T) { + cases := []struct { + Value string + Errors int + }{ + { + Value: "en-US", + Errors: 1, + }, + { + Value: "en_US", + Errors: 0, + }, + { + Value: "en US", + Errors: 0, + }, + { + Value: "English_United States.1252", + Errors: 0, + }, + } + + for _, tc := range cases { + _, errors := validateCollation()(tc.Value, "collation") + if len(errors) != tc.Errors { + t.Fatalf("Expected validateCollation to trigger '%d' errors for '%s' - got '%d'", tc.Errors, tc.Value, len(errors)) } } } diff --git a/website/docs/r/postgresql_server.html.markdown b/website/docs/r/postgresql_server.html.markdown index 695b6c830e21..a27378716e53 100644 --- a/website/docs/r/postgresql_server.html.markdown +++ b/website/docs/r/postgresql_server.html.markdown @@ -73,7 +73,7 @@ The following arguments are supported: `sku` supports the following: * `name` - (Required) Specifies the SKU Name for this PostgreSQL Server. The name of the SKU, follows the `tier` + `family` + `cores` pattern (e.g. B_Gen4_1, GP_Gen5_8). For more information see the [product documentation](https://docs.microsoft.com/en-us/rest/api/postgresql/servers/create#sku). - + * `capacity` - (Required) The scale up/out capacity, representing server's compute units. * `tier` - (Required) The tier of the particular SKU. Possible values are `Basic`, `GeneralPurpose`, and `MemoryOptimized`. For more information see the [product documentation](https://docs.microsoft.com/en-us/azure/postgresql/concepts-pricing-tiers).