Repository navigation
[Bug Report] vmss module causes unintended force replacement when used with moved block #157
Description
Describe the bug
When a Virtual Machine Scale Set (VMSS) is created with create_public_ip = false, and instead pip_prefix_name and pip_prefix_resource_group_name are provided via the var.interfaces variable, the public IP prefix is retrieved using the data.azurerm_public_ip_prefix.allocate data source.
If the Terraform configuration is later refactored using a moved block, this can unintentionally trigger a forced replacement of the azurerm_linux_virtual_machine_scale_set.this resource. This happens because the public IP prefix ID, retrieved via the data source, is not known until the next terraform apply. As a result, Terraform treats the value as potentially changed and marks the VMSS for replacement.
To avoid this unintended replacement, we can run the following command first:
terraform apply -target=data.azurerm_public_ip_prefix.allocate
This ensures the public IP prefix ID is resolved before the full apply, preventing unnecessary resource recreation.
Module Version
3.3.8
Terraform version
1.12.2
Expected behavior
Using moved block to refactor Terraform template should not cause intended replacement of VMSS if PIP Prefix resource has not been recreated.
I propose that following changes are made to vmss module:
- Remove
data.azurerm_public_ip_prefix.allocateresource fromvmssmodule. - Remove
pip_prefix_nameandpip_prefix_resource_group_namefromvar.interfacesvariable - Add
pip_prefix_idtovar.interfacesvariable so that the resource id can be passed directly to theazurerm_linux_virtual_machine_scale_set.thisresource without the need to retrieve it via the data source.
Using a moved block to refactor a Terraform configuration should not trigger a replacement of the VMSS resource, provided that the associated Public IP Prefix (PIP Prefix) has not been recreated. However, the current implementation causes unintended replacements due to reliance on a data source that cannot resolve its value until the next terraform apply.
Proposed Changes to the vmss Module
To prevent unnecessary replacements and improve clarity and control, the following changes are recommended:
Remove the data.azurerm_public_ip_prefix.allocate data source from the vmss module.
This eliminates the dependency on a value that is not known during the planning phase.
Remove pip_prefix_name and pip_prefix_resource_group_name from the var.interfaces variable.
These are no longer needed if the full resource ID is passed directly.
Introduce a new variable pip_prefix_id in var.interfaces.
This allows the caller to explicitly pass the full resource ID of the Public IP Prefix, enabling the azurerm_linux_virtual_machine_scale_set.this resource to reference it directly without relying on a data source.
Benefits
Avoids unintended VMSS replacements during refactoring.
Simplifies the module interface by removing indirect lookups.
Improves predictability and stability of Terraform plans and applies.
Current behavior
When creating a Virtual Machine Scale Set (VMSS) with create_public_ip = false, the module expects the Public IP Prefix to be provided indirectly via:
pip_prefix_namepip_prefix_resource_group_name
These values are passed through the var.interfaces variable. The module then uses a data source:
This data source retrieves the Public IP Prefix ID, which is then used in the azurerm_linux_virtual_machine_scale_set.this resource.
Problem During Refactoring
When the Terraform configuration is refactored using a moved block, Terraform attempts to preserve resource identity. However, because the data.azurerm_public_ip_prefix.allocate value is not known until apply time, Terraform cannot confirm whether the value has changed. As a result, it marks the VMSS resource for replacement, even if the actual PIP Prefix has not changed.
This behavior is unintended and can lead to unnecessary downtime and resource churn.
Anything else to add?
No response
Activity
jinkang23 commentedon Jul 15, 2025
@acelebanski -I respecfully request that you reconsider this decision. I have observed similar behavior during a straightforward
dns_serversmodification within thevnetmodule, even in the absence of anymovedorimportblocks. Thank you.Here is an example of
terraform planwith adns_serverschange:acelebanski commentedon Jul 16, 2025
Hello @jinkang23, I don't understand the
dns_serversexample, it attempts to update the vnets in place which is good.However, we decided to support specifying the Public IP Prefix by ID in parallel to supporting name & resource group name. We treat this as a one-off just to help in your specific use case. At the moment we're not planning to refactor the entire codebase to get rid of using data sources as it's still our preference.
jinkang23 commentedon Jul 16, 2025
Hi @acelebanski - Thank you for reconsidering and accepting my request.
To clarify, my concern isn't about updating DNS servers on the vnet resource itself, but how this update triggers Terraform to mark
resource "azurerm_linux_virtual_machine_scale_set" "this"for force replacement. Notably, passing the Public IP Prefix by ID (instead of via resource group/name using data sources) avoids this issue, which is my main concern.acelebanski commentedon Jul 17, 2025
@jinkang23 I cannot replicate your problem with DNS update on a VNET replacing VMSS. Probably something specific to your other code changes. Nevertheless, I'm going to implement a solution for you as described in my previous comment.