Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Plan: diff output not efficient #256

Closed
sylr opened this issue Jun 20, 2019 · 5 comments
Closed

Plan: diff output not efficient #256

sylr opened this issue Jun 20, 2019 · 5 comments

Comments

@sylr
Copy link

sylr commented Jun 20, 2019

Terraform Version

terraform version
Terraform v0.12.2
+ provider.azurerm v1.30.1

Terraform Configuration Files

Origin:

resource "azurerm_network_security_group" "test-nsg" {
  name                = "test-nsg"
  resource_group_name = "${azurerm_resource_group.test-RG.name}"
  location            = "${azurerm_resource_group.test-RG.location}"

  security_rule {
    name                        = "rule1"
    priority                    = 500
    direction                   = "Inbound"
    access                      = "Allow"
    protocol                    = "TCP"
    source_address_prefix       = "10.0.0.0/28"
    source_port_range           = "*"
    destination_address_prefix  = "*"
    destination_port_range      = "22"
  }

  security_rule {
    name                        = "rule2"
    priority                    = 600
    direction                   = "Inbound"
    access                      = "Allow"
    protocol                    = "TCP"
    source_address_prefix       = "10.0.0.0/28"
    source_port_range           = "*"
    destination_address_prefix  = "*"
    destination_port_range      = "22"
  }

  security_rule {
    name                        = "rule3"
    priority                    = 700
    direction                   = "Inbound"
    access                      = "Allow"
    protocol                    = "TCP"
    source_address_prefix       = "10.0.0.0/28"
    source_port_range           = "*"
    destination_address_prefix  = "*"
    destination_port_range      = "22"
  }
}

Target:

resource "azurerm_network_security_group" "test-nsg" {
  name                = "test-nsg"
  resource_group_name = "${azurerm_resource_group.test-RG.name}"
  location            = "${azurerm_resource_group.test-RG.location}"

  security_rule {
    name                        = "rule1"
    priority                    = 500
    direction                   = "Inbound"
    access                      = "Allow"
    protocol                    = "TCP"
    source_address_prefix       = "10.0.0.0/28"
    source_port_range           = "*"
    destination_address_prefix  = "*"
    destination_port_range      = "22"
  }

  security_rule {
    name                        = "rule2-1"
    priority                    = 600
    direction                   = "Inbound"
    access                      = "Allow"
    protocol                    = "TCP"
    source_address_prefix       = "10.0.0.0/28"
    source_port_range           = "*"
    destination_address_prefix  = "*"
    destination_port_range      = "22"
  }

  security_rule {
    name                        = "rule3"
    priority                    = 700
    direction                   = "Inbound"
    access                      = "Allow"
    protocol                    = "TCP"
    source_address_prefix       = "10.0.0.0/28"
    source_port_range           = "*"
    destination_address_prefix  = "*"
    destination_port_range      = "22"
  }
}

Only rule2 name has been modified

Expected Behavior

------------------------------------------------------------------------

An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
  ~ update in-place

Terraform will perform the following actions:

  # azurerm_network_security_group.test-nsg will be updated in-place
  ~ resource "azurerm_network_security_group" "test-nsg" {
        id                  = "/subscriptions/.../resourceGroups/test-RG/providers/Microsoft.Network/networkSecurityGroups/test-nsg"
        location            = "westeurope"
        name                = "test-nsg"
        resource_group_name = "test-RG"
      ~ security_rule       = [
            {
                access                                     = "Allow"
                description                                = ""
                destination_address_prefix                 = "*"
                destination_address_prefixes               = []
                destination_application_security_group_ids = []
                destination_port_range                     = "22"
                destination_port_ranges                    = []
                direction                                  = "Inbound"
                name                                       = "rule1"
                priority                                   = 500
                protocol                                   = "TCP"
                source_address_prefix                      = "10.0.0.0/28"
                source_address_prefixes                    = []
                source_application_security_group_ids      = []
                source_port_range                          = "*"
                source_port_ranges                         = []
            },
            {
                access                                     = "Allow"
                description                                = ""
                destination_address_prefix                 = "*"
                destination_address_prefixes               = []
                destination_application_security_group_ids = []
                destination_port_range                     = "22"
                destination_port_ranges                    = []
                direction                                  = "Inbound"
              ~ name                                       = "rule2-1"
                priority                                   = 600
                protocol                                   = "TCP"
                source_address_prefix                      = "10.0.0.0/28"
                source_address_prefixes                    = []
                source_application_security_group_ids      = []
                source_port_range                          = "*"
                source_port_ranges                         = []
            }
            {
                access                                     = "Allow"
                description                                = ""
                destination_address_prefix                 = "*"
                destination_address_prefixes               = []
                destination_application_security_group_ids = []
                destination_port_range                     = "22"
                destination_port_ranges                    = []
                direction                                  = "Inbound"
                name                                       = "rule3"
                priority                                   = 700
                protocol                                   = "TCP"
                source_address_prefix                      = "10.0.0.0/28"
                source_address_prefixes                    = []
                source_application_security_group_ids      = []
                source_port_range                          = "*"
                source_port_ranges                         = []
            }
        ]
        tags                = {}
    }

Plan: 0 to add, 1 to change, 0 to destroy.

Actual Behavior

------------------------------------------------------------------------

An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
  ~ update in-place

Terraform will perform the following actions:

  # azurerm_network_security_group.test-nsg will be updated in-place
  ~ resource "azurerm_network_security_group" "test-nsg" {
        id                  = "/subscriptions/.../resourceGroups/test-RG/providers/Microsoft.Network/networkSecurityGroups/test-nsg"
        location            = "westeurope"
        name                = "test-nsg"
        resource_group_name = "test-RG"
      ~ security_rule       = [
          - {
              - access                                     = "Allow"
              - description                                = ""
              - destination_address_prefix                 = "*"
              - destination_address_prefixes               = []
              - destination_application_security_group_ids = []
              - destination_port_range                     = "22"
              - destination_port_ranges                    = []
              - direction                                  = "Inbound"
              - name                                       = "rule1"
              - priority                                   = 500
              - protocol                                   = "TCP"
              - source_address_prefix                      = "10.0.0.0/28"
              - source_address_prefixes                    = []
              - source_application_security_group_ids      = []
              - source_port_range                          = "*"
              - source_port_ranges                         = []
            },
          - {
              - access                                     = "Allow"
              - description                                = ""
              - destination_address_prefix                 = "*"
              - destination_address_prefixes               = []
              - destination_application_security_group_ids = []
              - destination_port_range                     = "22"
              - destination_port_ranges                    = []
              - direction                                  = "Inbound"
              - name                                       = "rule2"
              - priority                                   = 600
              - protocol                                   = "TCP"
              - source_address_prefix                      = "10.0.0.0/28"
              - source_address_prefixes                    = []
              - source_application_security_group_ids      = []
              - source_port_range                          = "*"
              - source_port_ranges                         = []
            },
          + {
              + access                                     = "Allow"
              + description                                = ""
              + destination_address_prefix                 = "*"
              + destination_address_prefixes               = []
              + destination_application_security_group_ids = []
              + destination_port_range                     = "22"
              + destination_port_ranges                    = []
              + direction                                  = "Inbound"
              + name                                       = "rule2-1"
              + priority                                   = 600
              + protocol                                   = "TCP"
              + source_address_prefix                      = "10.0.0.0/28"
              + source_address_prefixes                    = []
              + source_application_security_group_ids      = []
              + source_port_range                          = "*"
              + source_port_ranges                         = []
            },
          - {
              - access                                     = "Allow"
              - description                                = ""
              - destination_address_prefix                 = "*"
              - destination_address_prefixes               = []
              - destination_application_security_group_ids = []
              - destination_port_range                     = "22"
              - destination_port_ranges                    = []
              - direction                                  = "Inbound"
              - name                                       = "rule3"
              - priority                                   = 700
              - protocol                                   = "TCP"
              - source_address_prefix                      = "10.0.0.0/28"
              - source_address_prefixes                    = []
              - source_application_security_group_ids      = []
              - source_port_range                          = "*"
              - source_port_ranges                         = []
            },
          + {
              + access                                     = "Allow"
              + description                                = null
              + destination_address_prefix                 = "*"
              + destination_address_prefixes               = []
              + destination_application_security_group_ids = []
              + destination_port_range                     = "22"
              + destination_port_ranges                    = []
              + direction                                  = "Inbound"
              + name                                       = "rule1"
              + priority                                   = 500
              + protocol                                   = "TCP"
              + source_address_prefix                      = "10.0.0.0/28"
              + source_address_prefixes                    = []
              + source_application_security_group_ids      = []
              + source_port_range                          = "*"
              + source_port_ranges                         = []
            },
          + {
              + access                                     = "Allow"
              + description                                = null
              + destination_address_prefix                 = "*"
              + destination_address_prefixes               = []
              + destination_application_security_group_ids = []
              + destination_port_range                     = "22"
              + destination_port_ranges                    = []
              + direction                                  = "Inbound"
              + name                                       = "rule3"
              + priority                                   = 700
              + protocol                                   = "TCP"
              + source_address_prefix                      = "10.0.0.0/28"
              + source_address_prefixes                    = []
              + source_application_security_group_ids      = []
              + source_port_range                          = "*"
              + source_port_ranges                         = []
            },
        ]
        tags                = {}
    }

Plan: 0 to add, 1 to change, 0 to destroy.
@apparentlymart
Copy link
Contributor

Hi @sylr! Sorry for this odd diff presentation.

Terraform is behaving this way because the provider has told Terraform that this argument is represented by a set, and thus the elements in the set are identified only by their contents and not by any other identifier such as a list index or map key. As a consequence, changing any part of one of these elements in the configuration is interpreted by the provider (and thus, in turn, by Terraform itself) as removing the old object and adding a new object; there is no external identifier to use to correlate these to understand that it's an edit.

I expect there's a good reason why the provider team marked this as being a set. Usually this is because the remote system (in this case, Azure) itself treats it as a set, and thus the provider would otherwise have no way to correlate objects in the configuration and state with objects in the remote system.

Since these objects seem to have a unique name associated with them, this seems like a situation that would benefit from the planned new SDK feature to allow for nested blocks that are correlated by a string label, like this:

security_rule "rule1" {
  # ...
}
security_rule "rule2" {
  # ...
}
security_rule "rule3" {
  # ...
}

The new provider protocol in Terraform 0.12 includes support for this, but the Terraform SDK doesn't currently make it available for providers because it is still limited by the Terraform 0.11 protocol while Terraform 0.11 is still supported. Work is starting now on a new version of the SDK that is built around the Terraform 0.12 featureset, and once that is complete the Azure provider team could potentially adopt the feature for this particular block so that a configuration like the above would work and Terraform would track create/update/delete by correlating by those labels.

I'm going to ask our bot to record this in the AzureRM provider repository, because ultimately making use of this feature will require an AzureRM provider code change to use it. For the moment though, this remains blocked on the provider SDK work I mentioned above and on the AzureRM provider adopting that new SDK for this particular resource type. For that reason, I expect that in the near term the issue will serve as a placeholder for the potential future work rather than something that can be acted on immediately.

Thanks again for reporting this!

@ghost
Copy link

ghost commented Jul 12, 2019

This issue has been automatically migrated to hashicorp/terraform-provider-azurerm#3841 because it looks like an issue with that provider. If you believe this is not an issue with the provider, please reply to hashicorp/terraform-provider-azurerm#3841.

@ghost ghost closed this as completed Jul 12, 2019
@ghost
Copy link

ghost commented Aug 13, 2019

I'm going to lock this issue because it has been closed for 30 days ⏳. This helps our maintainers find and focus on the active issues.

If you have found a problem that seems similar to this, please open a new issue and complete the issue template so we can capture all the details necessary to investigate further.

@ghost ghost locked and limited conversation to collaborators Aug 13, 2019
@hashicorp hashicorp unlocked this conversation Nov 20, 2019
@tombuildsstuff tombuildsstuff transferred this issue from hashicorp/terraform Nov 20, 2019
@radeksimko
Copy link
Member

I believe this is a duplicate of #220 (support for named blocks).

@ghost
Copy link

ghost commented Dec 30, 2019

I'm going to lock this issue because it has been closed for 30 days ⏳. This helps our maintainers find and focus on the active issues.

If you have found a problem that seems similar to this, please open a new issue and complete the issue template so we can capture all the details necessary to investigate further.

@ghost ghost locked and limited conversation to collaborators Dec 30, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants