Home > Back-end >  Terraform - 'Objects have changed outside of Terraform' for a new Azure resource group
Terraform - 'Objects have changed outside of Terraform' for a new Azure resource group

Time:08-25

I have been experimenting with terraform with the following basic configuration file for creating a resource group...

resource "azurerm_resource_group" "myrg" {
  name = "MyResourceGroup"
  location = "westeurope"
}

output resource_group_details {
  value = azurerm_resource_group.myrg
}
  • First terraform plan - 1 resource will be created
  • First terraform apply - 1 resource created
  • Second terraform plan (with no changes made to the configuration file) - Objects have changed outside of Terraform (See below)
  • Second terraform apply - Objects have changed outside of Terraform, 0 added/changed/detroyed
  • Third terraform plan (with no changes made to the configuration file) - No changes. Your infrastructure matches the configuration.
Note: Objects have changed outside of Terraform

Terraform detected the following changes made outside of Terraform since the last "terraform apply" which may have
affected this plan:

  # azurerm_resource_group.myrg has changed
  ~ resource "azurerm_resource_group" "myrg" {
        id       = "/subscriptions/176f2ee3-d0a2-476d-9106-43cad1f63f16/resourceGroups/MyResourceGroup"
        name     = "MyResourceGroup"
        tags     = {}
        # (1 unchanged attribute hidden)
    }

Based on what I've tried to find about this online, it looks like this warning is because Azure adds an empty tag array to a resource group during creation. Then when terraform compares the now existing resource with the configuration file and state, it's now warning you there is a difference. I'm not quite sure how terraform reconciles this on the third terraform plan though....

What should be the workflow here? Particularly when thinking about CI?

It appears to just be noise to be informed of the existence of an empty, optional attribute that I haven't defined.

I've looked at -refresh=false but it looks like this could suppress a genuine change that has occurred on your infrastructure that you may want to be notified about. When using -refresh-only on the second terraform plan and apply it just outputs the same noise as above.

CodePudding user response:

Indeed, what you have observed here is a small bug in the Azure provider where it is being inconsistent between the object it returns during apply and the object it returns during refresh.

It is typically okay for a provider to insert a default value for an argument that wasn't set, which is what seems to be happening here, but a provider ought to be consistent in doing so in all of its results: in the initial plan, in the new state created after apply, and in the refreshed state created on the next plan. Terraform produces this message in particular if the refreshed state created on the next plan is different than the new state that was created by the previous apply.


One way to hide the bug would be to explicitly set the tags argument to the default value that the provider's refresh step is inserting:

resource "azurerm_resource_group" "myrg" {
  name     = "MyResourceGroup"
  location = "westeurope"

  tags = {}
}

As long as the provider logic doesn't treat an empty map as special during plan and apply (which I'm not sure about), this should hopefully cause the initial result to agree with the refreshed result and thus avoid showing an incorrect "changed outside of Terraform" note.


Another separate answer is to change your output value to return more specific attributes of the resource group, so that Terraform can see that the end result doesn't depend on the tags attribute.

Terraform shows this message in an attempt to explain why the resource_group_details output value is also planned to change, and so Terraform shouldn't show the message if it can be sure that your output value won't be affected by the change to the tags. For example:

output "resource_group_details" {
  value = {
    name     = azurerm_resource_group.myrg.name
    location = azurerm_resource_group.myrg.location
    # (...and any other attributes you want to export,
    # as long as you don't refer to "tags".)
  }
}

Note that this rule generally applies to anything in your configuration that may directly or indirectly refer to the tags attribute, so if there's more to your configuration that you didn't show here then you should also make sure that nothing else refers to tags.

Terraform's analysis of this is not fully precise, so if it isn't sure that there aren't any references to tags then it will still show the note just in case. Therefore you would need to stick to relatively simple expressions that refer directly to individual attributes of azurerm_resource_group.myrg, and avoid using expressions which do dynamic work with the entire resource object which would prevent Terraform's analysis from proving that the tags attribute is unused.

  • Related