diff --git a/internal/services/postgres/postgresql_flexible_server_resource.go b/internal/services/postgres/postgresql_flexible_server_resource.go index 01973ce64ae2..8128d710c189 100644 --- a/internal/services/postgres/postgresql_flexible_server_resource.go +++ b/internal/services/postgres/postgresql_flexible_server_resource.go @@ -70,7 +70,6 @@ func resourcePostgresqlFlexibleServer() *pluginsdk.Resource { Type: pluginsdk.TypeString, Optional: true, Computed: true, - ForceNew: true, ValidateFunc: validation.All(validation.StringIsNotWhiteSpace, validate.AdminUsernames), }, @@ -288,7 +287,7 @@ func resourcePostgresqlFlexibleServer() *pluginsdk.Resource { "tags": commonschema.Tags(), }, - CustomizeDiff: pluginsdk.CustomizeDiffShim(func(ctx context.Context, d *pluginsdk.ResourceDiff, v interface{}) error { + CustomizeDiff: pluginsdk.CustomDiffWithAll(func(ctx context.Context, d *pluginsdk.ResourceDiff, v interface{}) error { createModeVal := d.Get("create_mode").(string) if createModeVal == string(servers.CreateModeUpdate) { @@ -315,7 +314,14 @@ func resourcePostgresqlFlexibleServer() *pluginsdk.Resource { d.ForceNew("version") return nil - }), + }, func(ctx context.Context, diff *pluginsdk.ResourceDiff, v interface{}) error { + oldLoginName, _ := diff.GetChange("administrator_login") + if oldLoginName != "" { + diff.ForceNew("administrator_login") + } + return nil + }, + ), } } @@ -362,12 +368,28 @@ func resourcePostgresqlFlexibleServerCreate(d *pluginsdk.ResourceData, meta inte } if createMode == "" || servers.CreateMode(createMode) == servers.CreateModeDefault { - if _, ok := d.GetOk("administrator_login"); !ok { - return fmt.Errorf("`administrator_login` is required when `create_mode` is `Default`") + _, adminLoginSet := d.GetOk("administrator_login") + _, adminPwdSet := d.GetOk("administrator_password") + + pwdEnabled := true // it defaults to true + if authRaw, authExist := d.GetOk("authentication"); authExist { + authConfig := expandFlexibleServerAuthConfig(authRaw.([]interface{})) + if authConfig.PasswordAuth != nil { + pwdEnabled = *authConfig.PasswordAuth == servers.PasswordAuthEnumEnabled + } } - if _, ok := d.GetOk("administrator_password"); !ok { - return fmt.Errorf("`administrator_password` is required when `create_mode` is `Default`") + + if pwdEnabled { + if !adminLoginSet { + return fmt.Errorf("`administrator_login` is required when `create_mode` is `Default` and `authentication.password_auth_enabled` is set to `true`") + } + if !adminPwdSet { + return fmt.Errorf("`administrator_password` is required when `create_mode` is `Default` and `authentication.password_auth_enabled` is set to `true`") + } + } else if adminLoginSet || adminPwdSet { + return fmt.Errorf("`administrator_login` and `administrator_password` cannot be set when `authentication.password_auth_enabled` is set to `false`") } + if _, ok := d.GetOk("sku_name"); !ok { return fmt.Errorf("`sku_name` is required when `create_mode` is `Default`") } @@ -432,12 +454,8 @@ func resourcePostgresqlFlexibleServerCreate(d *pluginsdk.ResourceData, meta inte parameters.Properties.PointInTimeUTC = utils.String(v.Format(time.RFC3339)) } - // if create with `password_auth_enabled` set to `false`, the service will not accept `administrator_login`. - // so we create it with `password_auth_enabled` set to `true`, then set it to `false` in an additional update. if authRaw, ok := d.GetOk("authentication"); ok { authConfig := expandFlexibleServerAuthConfig(authRaw.([]interface{})) - passwordAuthEnabled := servers.PasswordAuthEnumEnabled - authConfig.PasswordAuth = &passwordAuthEnabled parameters.Properties.AuthConfig = authConfig } @@ -453,14 +471,6 @@ func resourcePostgresqlFlexibleServerCreate(d *pluginsdk.ResourceData, meta inte requireAdditionalUpdate := false updateProperties := servers.ServerPropertiesForUpdate{} - if authRaw, ok := d.GetOk("authentication"); ok { - authConfig := expandFlexibleServerAuthConfig(authRaw.([]interface{})) - if authConfig != nil && authConfig.PasswordAuth != nil && *authConfig.PasswordAuth == servers.PasswordAuthEnumDisabled { - requireAdditionalUpdate = true - updateProperties.AuthConfig = authConfig - } - } - // `maintenance_window` could only be updated with, could not be created with if v, ok := d.GetOk("maintenance_window"); ok { requireAdditionalUpdate = true @@ -596,6 +606,38 @@ func resourcePostgresqlFlexibleServerUpdate(d *pluginsdk.ResourceData, meta inte Properties: &servers.ServerPropertiesForUpdate{}, } + requireUpdateOnLogin := false // it's required to call Create with `createMode` set to `Update` to update login name. + + createMode := d.Get("create_mode").(string) + if createMode == "" || servers.CreateMode(createMode) == servers.CreateModeDefault { + + _, adminLoginSet := d.GetOk("administrator_login") + _, adminPwdSet := d.GetOk("administrator_password") + + pwdEnabled := true // it defaults to true + if authRaw, authExist := d.GetOk("authentication"); authExist { + authConfig := expandFlexibleServerAuthConfig(authRaw.([]interface{})) + if authConfig.PasswordAuth != nil { + pwdEnabled = *authConfig.PasswordAuth == servers.PasswordAuthEnumEnabled + } + } + + if pwdEnabled { + if !adminLoginSet { + return fmt.Errorf("`administrator_login` is required when `authentication.password_auth_enabled` is set to `true`") + } + if !adminPwdSet { + return fmt.Errorf("`administrator_password` is required when `authentication.password_auth_enabled` is set to `true`") + } + } else if adminLoginSet || adminPwdSet { + return fmt.Errorf("`administrator_login` and `administrator_password` cannot be set when `authentication.password_auth_enabled` is set to `false`") + } + + if d.HasChange("administrator_login") { + requireUpdateOnLogin = true + } + } + var requireFailover bool // failover is only supported when `zone` and `high_availability.0.standby_availability_zone` are exchanged with each other if d.HasChanges("zone", "high_availability") { @@ -713,6 +755,23 @@ func resourcePostgresqlFlexibleServerUpdate(d *pluginsdk.ResourceData, meta inte parameters.Properties.Version = &version } + if requireUpdateOnLogin { + updateMode := servers.CreateModeUpdate + loginParameters := servers.Server{ + Location: location.Normalize(d.Get("location").(string)), + Properties: &servers.ServerProperties{ + CreateMode: &updateMode, + AuthConfig: expandFlexibleServerAuthConfig(d.Get("authentication").([]interface{})), + AdministratorLogin: utils.String(d.Get("administrator_login").(string)), + AdministratorLoginPassword: utils.String(d.Get("administrator_password").(string)), + Network: expandArmServerNetwork(d), + }, + } + if err = client.CreateThenPoll(ctx, *id, loginParameters); err != nil { + return fmt.Errorf("updating %s: %+v", id, err) + } + } + if err = client.UpdateThenPoll(ctx, *id, parameters); err != nil { return fmt.Errorf("updating %s: %+v", id, err) } diff --git a/internal/services/postgres/postgresql_flexible_server_resource_test.go b/internal/services/postgres/postgresql_flexible_server_resource_test.go index aab22e9198f1..c5a1f687e612 100644 --- a/internal/services/postgres/postgresql_flexible_server_resource_test.go +++ b/internal/services/postgres/postgresql_flexible_server_resource_test.go @@ -245,6 +245,7 @@ func TestAccPostgresqlFlexibleServer_authConfig(t *testing.T) { r := PostgresqlFlexibleServerResource{} data.ResourceTest(t, r, []acceptance.TestStep{ { + // stats from pwdEnabled set to `false` to test add `admininistrator_login` Config: r.authConfig(data, true, false), Check: acceptance.ComposeTestCheckFunc( check.That(data.ResourceName).ExistsInAzure(r), @@ -711,6 +712,14 @@ func (r PostgresqlFlexibleServerResource) authConfig(data acceptance.TestData, a tenantIdBlock = "tenant_id = data.azurerm_client_config.current.tenant_id" } + pwdBlock := "" + if pwdEnabled { + pwdBlock = ` +administrator_login = "adminTerraform" +administrator_password = "QAZwsx123" +` + } + return fmt.Sprintf(` %s @@ -718,24 +727,23 @@ data "azurerm_client_config" "current" { } resource "azurerm_postgresql_flexible_server" "test" { - name = "acctest-fs-%d" - resource_group_name = azurerm_resource_group.test.name - location = azurerm_resource_group.test.location - administrator_login = "adminTerraform" - administrator_password = "QAZwsx123" - storage_mb = 32768 - version = "12" - sku_name = "GP_Standard_D2s_v3" - zone = "2" + name = "acctest-fs-%d" + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location + %[3]s + storage_mb = 32768 + version = "12" + sku_name = "GP_Standard_D2s_v3" + zone = "2" authentication { - active_directory_auth_enabled = %[3]t - password_auth_enabled = %[4]t - %[5]s + active_directory_auth_enabled = %[4]t + password_auth_enabled = %[5]t + %[6]s } } -`, r.template(data), data.RandomInteger, aadEnabled, pwdEnabled, tenantIdBlock) +`, r.template(data), data.RandomInteger, pwdBlock, aadEnabled, pwdEnabled, tenantIdBlock) } func (r PostgresqlFlexibleServerResource) cmkTemplate(data acceptance.TestData) string { diff --git a/website/docs/r/postgresql_flexible_server.html.markdown b/website/docs/r/postgresql_flexible_server.html.markdown index dfa30f00af39..2faeac697b17 100644 --- a/website/docs/r/postgresql_flexible_server.html.markdown +++ b/website/docs/r/postgresql_flexible_server.html.markdown @@ -88,9 +88,11 @@ The following arguments are supported: * `location` - (Required) The Azure Region where the PostgreSQL Flexible Server should exist. Changing this forces a new PostgreSQL Flexible Server to be created. -* `administrator_login` - (Optional) The Administrator login for the PostgreSQL Flexible Server. Required when `create_mode` is `Default`. Changing this forces a new PostgreSQL Flexible Server to be created. +* `administrator_login` - (Optional) The Administrator login for the PostgreSQL Flexible Server. Required when `create_mode` is `Default` and `authentication.password_auth_enabled` is `true`. -* `administrator_password` - (Optional) The Password associated with the `administrator_login` for the PostgreSQL Flexible Server. Required when `create_mode` is `Default`. +-> **Note:** Once `administrator_login` is specified, changing this forces a new PostgreSQL Flexible Server to be created. + +* `administrator_password` - (Optional) The Password associated with the `administrator_login` for the PostgreSQL Flexible Server. Required when `create_mode` is `Default` and `authentication.password_auth_enabled` is `true`. * `authentication` - (Optional) An `authentication` block as defined below. @@ -148,6 +150,8 @@ An `authentication` block supports the following: * `password_auth_enabled` - (Optional) Whether or not password authentication is allowed to access the PostgreSQL Flexible Server. Defaults to `true`. +-> **NOTE:** When `password_auth_enabled` is set to `false`, `administrator_login` and `administrator_password` must not be specified. + * `tenant_id` - (Optional) The Tenant ID of the Azure Active Directory which is used by the Active Directory authentication. `active_directory_auth_enabled` must be set to `true`. -> **Note:** Setting `active_directory_auth_enabled` to `true` requires a Service Principal for the Postgres Flexible Server. For more details see [this document](https://learn.microsoft.com/en-us/azure/postgresql/flexible-server/how-to-configure-sign-in-azure-ad-authentication).