nbering / terraform-provider-ansible

"Logical" provider for integrating with an Ansible Dynamic Inventory script.
https://nbering.github.io/terraform-provider-ansible/
Mozilla Public License 2.0
329 stars 64 forks source link

Handling the "count" parameter in Terraform #11

Closed ap1969 closed 6 years ago

ap1969 commented 6 years ago

Hi, This might be a question more for an example, than an actual issue. Let's say I'm setting up 5 load-balanced servers:

resource "aws_instance" "web" {
  ami           = "ami-408c7f28"
  instance_type = "t1.micro"
  count = "5"
}

How would I pass the 5 servers to Ansible using this? Is it even possible?

resource "ansible_host" "example" {
    inventory_hostname = "example.com"
    groups = ["web"]
    vars {
        ansible_user = "admin"
    }
}

Thanks in advance, Andy

nbering commented 6 years ago

I took the liberty of fixing up the code formatting in your post. I'll get back to you on this later today if no one beats me to it.

ap1969 commented 6 years ago

Thanks @nbering - appreciate the help.

nbering commented 6 years ago

I added a couple of examples with count to the test data for nbering/terraform-inventory.

Basic

This example just uses the count index in the domain name.

Configuration

resource "ansible_host" "count_sample" {
  count              = 5
  inventory_hostname = "count-sample-${count.index}.example.com"
}

Plan

  + ansible_host.count_sample[0]
      id:                 <computed>
      inventory_hostname: "count-sample-0.example.com"

  + ansible_host.count_sample[1]
      id:                 <computed>
      inventory_hostname: "count-sample-1.example.com"

  + ansible_host.count_sample[2]
      id:                 <computed>
      inventory_hostname: "count-sample-2.example.com"

  + ansible_host.count_sample[3]
      id:                 <computed>
      inventory_hostname: "count-sample-3.example.com"

  + ansible_host.count_sample[4]
      id:                 <computed>
      inventory_hostname: "count-sample-4.example.com"

Advanced

This example uses a list of hostnames from a variable instead of the index for the hostname. This demonstrates linking count to a list and it's contents. Names were randomly generated with HaikunatorJS. You could do something similar with Terraform's own Random Provider.

Configuration

variable "hostnames" {
  type = "list"

  default = [
    "broad-union",
    "young-violet",
    "lively-tree",
    "mute-fog",
    "rough-bread",
  ]
}

variable "domain" {
  default = "example.com"
}

resource "ansible_host" "count_advanced" {
  count              = "${length(var.hostnames)}"
  inventory_hostname = "${element(var.hostnames, count.index)}.${var.domain}"
}

Plan

  + ansible_host.count_advanced[0]
      id:                 <computed>
      inventory_hostname: "broad-union.example.com"

  + ansible_host.count_advanced[1]
      id:                 <computed>
      inventory_hostname: "young-violet.example.com"

  + ansible_host.count_advanced[2]
      id:                 <computed>
      inventory_hostname: "lively-tree.example.com"

  + ansible_host.count_advanced[3]
      id:                 <computed>
      inventory_hostname: "mute-fog.example.com"

  + ansible_host.count_advanced[4]
      id:                 <computed>
      inventory_hostname: "rough-bread.example.com"
ap1969 commented 6 years ago

Fantastic! Many thanks indeed. Appreciate your help.

nbering commented 6 years ago

No problem at all.

yogesh174 commented 3 years ago

But with this, If I destroy only one host then all the other hosts added using count are being removed from the inventory.

nbering commented 3 years ago

But with this, If I destroy only one host then all the other hosts added using count are being removed from the inventory.

Keep in mind that this is a virtual resource. Destroying a resource in this provider doesn't mean your server was destroyed. It just means the state was deleted and probably replaced by a new value.

I don't know if there is a better pattern today, but when I wrote this it was commonplace in examples I was seeing in IRC, HashiCorp on other module's docs, etc.

yogesh174 commented 3 years ago

But with this, If I destroy only one host then all the other hosts added using count are being removed from the inventory.

Keep in mind that this is a virtual resource. Destroying a resource in this provider doesn't mean your server was destroyed. It just means the state was deleted and probably replaced by a new value.

I don't know if there is a better pattern today, but when I wrote this it was commonplace in examples I was seeing in IRC, HashiCorp on other module's docs, etc.

Let me rephrase it this way. Suppose I create 5 instances and add them to the inventory using this module with count. Then if I decrease the count to 4 then this instance along with all the other instances in the inventory are getting removed. But the expected result is that only that one instance that I deleted should be removed from the inventory.

nbering commented 3 years ago

@yogesh174 This sounds like expected behaviour to me, in some cases. But not all. But it is still a function of the Terraform engine and not this provider. There's no special implementation here that handles count. In Terraform Core, it just treats this resource like an array of resources, and each element is to this provider a separate resource.

What you're likely running into, is that there's no way to "splice" something into or out of the array. If a property that triggers removal of a resource is changed, then it will be removed. And each "count" instance is a separate resource coupled to it's "count" index.

If changing count from 5 to 4 causes the hostname of item 1 to change, item 1 will be removed and recreated.