Terraform: incrementing `count` on resources breaks the existing deployment

Created on 21 Jul 2017  ยท  3Comments  ยท  Source: hashicorp/terraform

Terraform Version

0.9.11

Terraform Configuration Files

resource "openstack_networking_network_v2" "net-backend" {
  name = "${var.backend_network}"
  admin_state_up = "true"
}

resource "openstack_networking_subnet_v2" "net-backend-subnet" {
  name = "${var.backend_network}"
  network_id = "${openstack_networking_network_v2.net-backend.id}"
  cidr = "${var.backend_network_cidr}"
  dns_nameservers = [ "100.127.70.70" ]
  ip_version = 4
  depends_on = ["openstack_networking_network_v2.net-backend"]
}

resource "openstack_networking_port_v2" "test_port_backend" {
  name = "test${count.index+1}"
  count = "2"
  admin_state_up = "true"
  network_id = "${openstack_networking_network_v2.net-backend.id}"
}

resource "openstack_compute_instance_v2" "test" {
  name = "test${count.index+1}"
  count = "2"
  image_id = "66ae409c-f2ea-4a8c-a25c-3859d79f9f33"
  flavor_name = "m1.small"
  key_pair = "misko"
  availability_zone = "mz"

  network {
    port = "${element(openstack_networking_port_v2.test_port_backend.*.id, count.index)}"
  }

}

variable "backend_network" {
  description = "local network name"
}

variable "backend_network_cidr" {
  description = "local network cidr"
}

Expected Behavior

Add instance + port

Actual Behavior

destroyed existing instances / creating new ones

Steps to Reproduce

Note for my environment: I have to terraform import pre-existing net-backend and net-backend-subnet resources because if TF creates them for me, it won't work in our openstack lab environment.

  1. terraform apply
    -> 2 machines and 2 network ports are created
  2. increase count for both test and test_port_backend resources from 2 to 3
  3. instead of adding 1 port (test_port_backend) resource and 1 vm resource (test), destroys existing instances instead of adding one:
-/+ openstack_compute_instance_v2.test.0
    access_ip_v4:             "" => "<computed>"
    access_ip_v6:             "" => "<computed>"
    all_metadata.%:           "0" => "<computed>"
    availability_zone:        "mz" => "mz"
    flavor_id:                "2" => "<computed>"
    flavor_name:              "m1.small" => "m1.small"
    force_delete:             "false" => "false"
    image_id:                 "66ae409c-f2ea-4a8c-a25c-3859d79f9f33" => "66ae409c-f2ea-4a8c-a25c-3859d79f9f33"
    image_name:               "Ubuntu 16.04 RAW" => "<computed>"
    key_pair:                 "misko" => "misko"
    name:                     "test1" => "test1"
    network.#:                "1" => "1"
    network.0.access_network: "false" => "false"
    network.0.fixed_ip_v4:    "" => "<computed>"
    network.0.fixed_ip_v6:    "" => "<computed>"
    network.0.floating_ip:    "" => "<computed>"
    network.0.mac:            "" => "<computed>"
    network.0.name:           "" => "<computed>"
    network.0.port:           "a7404184-47b7-4470-ab14-28520f34c790" => "${element(openstack_networking_port_v2.test_port_backend.*.id, count.index)}" (forces new resource)
    network.0.uuid:           "" => "<computed>"
    region:                   "RegionOne" => "RegionOne"
    security_groups.#:        "1" => "<computed>"
    stop_before_destroy:      "false" => "false"

-/+ openstack_compute_instance_v2.test.1
    access_ip_v4:             "" => "<computed>"
    access_ip_v6:             "" => "<computed>"
    all_metadata.%:           "0" => "<computed>"
    availability_zone:        "mz" => "mz"
    flavor_id:                "2" => "<computed>"
    flavor_name:              "m1.small" => "m1.small"
    force_delete:             "false" => "false"
    image_id:                 "66ae409c-f2ea-4a8c-a25c-3859d79f9f33" => "66ae409c-f2ea-4a8c-a25c-3859d79f9f33"
    image_name:               "Ubuntu 16.04 RAW" => "<computed>"
    key_pair:                 "misko" => "misko"
    name:                     "test2" => "test2"
    network.#:                "1" => "1"
    network.0.access_network: "false" => "false"
    network.0.fixed_ip_v4:    "" => "<computed>"
    network.0.fixed_ip_v6:    "" => "<computed>"
    network.0.floating_ip:    "" => "<computed>"
    network.0.mac:            "" => "<computed>"
    network.0.name:           "" => "<computed>"
    network.0.port:           "7cbf77e8-211f-4fb6-b454-ff24740cc54c" => "${element(openstack_networking_port_v2.test_port_backend.*.id, count.index)}" (forces new resource)
    network.0.uuid:           "" => "<computed>"
    region:                   "RegionOne" => "RegionOne"
    security_groups.#:        "1" => "<computed>"
    stop_before_destroy:      "false" => "false"

+ openstack_compute_instance_v2.test.2
    access_ip_v4:             "<computed>"
    access_ip_v6:             "<computed>"
    all_metadata.%:           "<computed>"
    availability_zone:        "mz"
    flavor_id:                "<computed>"
    flavor_name:              "m1.small"
    force_delete:             "false"
    image_id:                 "66ae409c-f2ea-4a8c-a25c-3859d79f9f33"
    image_name:               "<computed>"
    key_pair:                 "misko"
    name:                     "test3"
    network.#:                "1"
    network.0.access_network: "false"
    network.0.fixed_ip_v4:    "<computed>"
    network.0.fixed_ip_v6:    "<computed>"
    network.0.floating_ip:    "<computed>"
    network.0.mac:            "<computed>"
    network.0.name:           "<computed>"
    network.0.port:           "${element(openstack_networking_port_v2.test_port_backend.*.id, count.index)}"
    network.0.uuid:           "<computed>"
    region:                   "RegionOne"
    security_groups.#:        "<computed>"
    stop_before_destroy:      "false"

+ openstack_networking_port_v2.test_port_backend.2
    admin_state_up:          "true"
    all_fixed_ips.#:         "<computed>"
    allowed_address_pairs.#: "<computed>"
    device_id:               "<computed>"
    device_owner:            "<computed>"
    mac_address:             "<computed>"
    name:                    "test3"
    network_id:              "d3ebd619-3f2d-45cb-8e28-86da7cdf4cc5"
    region:                  "RegionOne"
    security_group_ids.#:    "<computed>"
    tenant_id:               "<computed>"


Plan: 6 to add, 0 to change, 2 to destroy.

References

Incorrect resource count reported here

Most helpful comment

Hi @michalmedvecky! Sorry this isn't working as expected.

The problem here is that using the element function currently prevents Terraform from inferring that only a single element of the openstack_networking_port_v2.test_port_backend.*.id list is "computed" (can't be known until a resource is created), so the conservative outcome is to assume that the entire array is computed.

Terraform can get a better signal here if you use the index operator:

  network {
    port = "${openstack_networking_port_v2.test_port_backend.*.id[count.index]}"
  }

Since this is first-class syntax rather than just a function, Terraform can correctly understand that this result only depends on a single value from this list, and thus get the desired effect.

Sorry for this gotcha in the language. We have some early plans on changes to the interpolation language interpreter that could make it able to make similar observations about function calls, but currently it treats all functions as opaque to analysis, causing this problem. For now, we recommend that the element function be used only when its extra "modulo length" behavior is useful, and that the index operator should be preferred where possible.

All 3 comments

Hi @michalmedvecky! Sorry this isn't working as expected.

The problem here is that using the element function currently prevents Terraform from inferring that only a single element of the openstack_networking_port_v2.test_port_backend.*.id list is "computed" (can't be known until a resource is created), so the conservative outcome is to assume that the entire array is computed.

Terraform can get a better signal here if you use the index operator:

  network {
    port = "${openstack_networking_port_v2.test_port_backend.*.id[count.index]}"
  }

Since this is first-class syntax rather than just a function, Terraform can correctly understand that this result only depends on a single value from this list, and thus get the desired effect.

Sorry for this gotcha in the language. We have some early plans on changes to the interpolation language interpreter that could make it able to make similar observations about function calls, but currently it treats all functions as opaque to analysis, causing this problem. For now, we recommend that the element function be used only when its extra "modulo length" behavior is useful, and that the index operator should be preferred where possible.

Thanks, that helped.

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.

Was this page helpful?
0 / 5 - 0 ratings