hashicorp / terraform-provider-azurerm

Terraform provider for Azure Resource Manager
https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs
Mozilla Public License 2.0
4.54k stars 4.61k forks source link

changing the `azurerm_postgresql_flexible_server` version from 11 to any other version forces a recreate #25184

Open Xangliev opened 7 months ago

Xangliev commented 7 months ago

Is there an existing issue for this?

Community Note

Terraform Version

1.5.7

AzureRM Provider Version

3.94.0 and lower versions seem to be impacted

Affected Resource(s)/Data Source(s)

azurerm_postgresql_flexible_server

Terraform Configuration Files

resource "azurerm_postgresql_flexible_server" "server2" {
  name                = var.name
  location            = var.location
  resource_group_name = var.resource_group_name

  administrator_login    = var.administrator_login
  administrator_password = var.administrator_password

  sku_name   = var.sku_name
  storage_mb = var.storage_mb
  zone       = var.zone
  version    = "11" // eg. changing to "12" or "15" forces a replacement
}

Debug Output/Panic Output

Terraform will perform the following actions:
  # azurerm_postgresql_flexible_server.server must be replaced
-/+ resource "azurerm_postgresql_flexible_server" "server" {
      ~ backup_retention_days         = 7 -> (known after apply)
      ~ fqdn                          = <redacted> -> (known after apply)
      ~ id                            = <redacted> -> (known after apply)
        name                          = "psql-test-ra3h3"
      + private_dns_zone_id           = (known after apply)
      ~ public_network_access_enabled = true -> (known after apply)
      ~ version                       = "11" -> "15" # forces replacement
        # (8 unchanged attributes hidden)
      - authentication {
          - active_directory_auth_enabled = false -> null
          - password_auth_enabled         = true -> null
        }
    }

Expected Behaviour

Terraform should perform the upgrade on the existing resource without forcing a replacement of the server resource.

Actual Behaviour

Terraform forces a replacement of the server resource and all dependant resources.

Steps to Reproduce

  1. create the postgresql flexible server resource definition
  2. run terraform apply to create the postgresql flexible server resource
  3. change the server version from 11 to 15 within the resource definition
  4. rerun terraform apply

Important Factoids

No response

References

No response

Xangliev commented 7 months ago

UPDATE: apparently setting the create_mode variable to "Update" is required in order for Terraform not to replace the server resource.

I would honestly expect that changing the value of the server_version variable would not replace existing resources by default, as performing a server upgrade via the Azure Portal doesn't trigger a replacement of any kind either.

neil-yechenwei commented 6 months ago

Thanks for raising this issue. Service team confirmed the version of postgresql flexible server should be in-place updated while upgrading "version" and create_mode is "Update".

Below is example:

resource "azurerm_postgresql_flexible_server" "test" {
  name                = "acctest-fs-test183"
  resource_group_name = azurerm_resource_group.test.name
  location            = azurerm_resource_group.test.location

  administrator_login    = "_admin_Terraform_123123"
  administrator_password = "QAZabx123"

  sku_name = "GP_Standard_D2s_v3"
  zone     = "2"
  version  = "12"

  create_mode = "Update"
}
tanadeau commented 5 months ago

@neil-yechenwei: Is there a reason the provider doesn't set the create_mode to "Update" automatically if version changes? Unless I'm mistaken, I don't think create_mode can always be set to "Update" especially on first creation. This seems to be very error-prone and a good way to lose data.

wslaghekke commented 4 months ago

Am i understanding correctly that there is currently no way to have a terraform config that will depending on the existence of the server automatically create / upgrade it? (because i need to have create_mode = "Default" for creating the server and create_mode = "Update" for upgrading postgres)

tombuildsstuff commented 4 months ago

@neil-yechenwei as @tanadeau has mentioned above - the provider should be setting create_mode = "Update" automatically as required, that the API behaves in a weird manner is Terraform's problem, not something that should be pushed onto users.

FWIW this is why we shouldn't necessarily expose CreateMode (and similar) fields in resources, but instead infer it from other fields (e.g. hypothetically if there's a field restore_from_server_id = ".." and that field is populated, we could determine that create_mode = "Restore" rather than create_mode = "Default|Update"). It's a bit late for the places we've already exposed this field, but as mentioned above, this is an API/implementation detail that Terraform should be handling - users just want to update the API version, so we should be sending whatever the API needs to achieve that?

As such, @neil-yechenwei would you be able to send a PR to automatically set the value for CreateMode when updating the server in this instance?

Thanks!

lieberlois commented 4 months ago

Any updates here?

sleenen commented 2 months ago

Please fix this, this is ridiculous. The terraform resource documentation even says this:

_* createmode cannot be changed once it's set since it's a parameter at creation.

Followed by:

_* While creating the resource, createmode cannot be set to Update.

And the property itself says:

Changing this forces a new PostgreSQL Flexible Server to be created.

So we have to set it to Create, then we can't even change the value to Update even if we wanted to do an in place upgrade of the version... This is horrible. Users want to be able to upgrade their instance in place, just like they can do through the portal.

(I'm trying this now though and we can change the value of create_mode without it resulting in a re-create of the instance?! In that case the documentation is wrong. But having to do this is still bad. )

lieberlois commented 2 months ago

@sleenen I figured it out like a month ago, sorry for not posting the answer immediately.

The (very stupid) idea of this implementation seems to be that you only set the create_mode to Update along with other changes. In our scenario, we tried to first set the create_mode, then tf apply, then update the PostgreSQL version. Only setting the create_mode to update with no other changes however recreates the database. After hours of trying stuff out I just tried to do both at once, and it worked πŸ˜† not sure if this explanation was clear, I don't know how to describe it - very confusing ^^

sleenen commented 2 months ago

Thanks @lieberlois , I've tried the same. First time I got a weird internal server error with no more explanation. Second try I got a timeout on the polling and the instance wasn't updated to new version.

lieberlois commented 2 months ago

@sleenen Thats odd, we managed to upgrade all of our instances from 11 to 16 this way πŸ€” oh when did you try this? There was an issue on Microsoft side, this was fixed like 1-2 months ago

sleenen commented 2 months ago

Tried it last night and this morning again.

lieberlois commented 1 month ago

@sleenen We have our next release next week on saturday, I'll notify you if everything worked πŸ‘

sleenen commented 1 month ago

@tombuildsstuff @neil-yechenwei any update on this?

simaotwx commented 1 month ago

Please fix this, this is ridiculous. The terraform resource documentation even says this:

_* createmode cannot be changed once it's set since it's a parameter at creation.

Followed by:

_* While creating the resource, createmode cannot be set to Update.

And the property itself says:

Changing this forces a new PostgreSQL Flexible Server to be created.

So we have to set it to Create, then we can't even change the value to Update even if we wanted to do an in place upgrade of the version... This is horrible. Users want to be able to upgrade their instance in place, just like they can do through the portal.

(I'm trying this now though and we can change the value of create_mode without it resulting in a re-create of the instance?! In that case the documentation is wrong. But having to do this is still bad. )

I was about to create an issue but I found this one. The documentation is highly misleading, confusing and contradicts itself. Relying on the knowledge of existence to change the Terraform configuration makes it dependent on external factors and no longer reproducible. Looking forward to the change that will set "Update" automatically when the version is updated. I would also have expected that create_mode could be set to Update from the beginning.

gangefors commented 1 month ago

This is also an issue when upgrading a server with create_mode=PointInTimeRestore which is common in a staging environment.

Even if I set create_mode=Update Terraform says it will recreate the database server.

$ terraform --version
Terraform v1.9.5
on linux_amd64
+ provider registry.terraform.io/hashicorp/azurerm v3.116.0

$ terraform apply ...
[...]
-/+ resource "azurerm_postgresql_flexible_server" "psql" {
      ~ create_mode                       = "PointInTimeRestore" -> "Update"
      ~ fqdn                              = "xxxxxx.postgres.database.azure.com" -> (known after apply)
      ~ id                                = "xxxxxx" -> (known after apply)
        name                              = "xxxxxx"
      ~ point_in_time_restore_time_in_utc = "2024-08-27T07:38:13Z" -> (known after apply)
      - source_server_id                  = "xxxxxx" -> null
      ~ storage_tier                      = "P20" -> (known after apply)
      ~ version                           = "13" -> "15" # forces replacement
        # (14 unchanged attributes hidden)

Seems that we have to rely on click-ops and update the server manually in Azure and just bump the version in tfvars.

Please fix this.

Addition: I've now tried creating a brand new server with v13 and then trying to upgrade it by only changing the version and setting create_mode="Update" and I still end up with terraform wanting to destroy my existing server.

# module.psql.azurerm_postgresql_flexible_server.psql must be replaced
-/+ resource "azurerm_postgresql_flexible_server" "psql" {
      ~ create_mode                   = "Default" -> "Update"
      ~ fqdn                          = "xxx.postgres.database.azure.com" -> (known after apply)
      ~ id                            = "xxx" -> (known after apply)
        name                          = "psql-jfp-axis-se-dev"
      ~ storage_tier                  = "P20" -> (known after apply)
      ~ version                       = "13" -> "15" # forces replacement
        # (14 unchanged attributes hidden)
DennisJensen95 commented 1 month ago

This is highly unintuitive and I simply do not understand. I am using AzureRM 4.0.1, I started spinning two postgres flexible servers. All is fine, then i wanted to upgrade PG version from 15 -> 16.

I set the create_mode = "Update" and it does this fine without replacing the entire DB and I was now able to update the Prod server on a General tier but not the dev instance on a burst tier. Now I deleted my dev tier, tore it down to set it up again on PG version 16, but now I can't set the create_mode = "Update" on the dev tier without having to destroy it, at the same time i can't change create_mode away from "Update" because that will tear down my prod environment and i can't spin my dev tier up in "Update" mode πŸ˜΅β€πŸ’«

Please fix this and do it the right way, this is crucial infastructure.

lieberlois commented 1 month ago

image

terraform-provider-azurerm/internal/services/postgres/postgresql_flexible_server_resource.go seems to be the problematic code part πŸ€” if no create mode is specified, or not explicitly set to "Update" it will force a recreation. What do the Hashicorp guys say to that?

divyn10 commented 1 week ago

@sleenen I was also facing the same issue then found out this link please check if Timescaledb, pgaudit, dblink, orafce, pg_partman, postgres_fdw all these extensions are not present before upgrading via terraform