Skip to content

Instantly share code, notes, and snippets.

@Lowess
Last active September 25, 2017 21:35
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Lowess/79e3cc2a89be68a7058e53c7ca566bcb to your computer and use it in GitHub Desktop.
Save Lowess/79e3cc2a89be68a7058e53c7ca566bcb to your computer and use it in GitHub Desktop.
Terraform with count
resource "aws_security_group" "sg" {
vpc_id = "${var.vpc}"
name = "${var.name}"
description = "${var.description}"
tags = "${merge(var.tags, map("Name", format("%s", var.name)))}"
}
resource "aws_security_group_rule" "sg_rule_sg_ids" {
count = "${length(var.inbound_sources) * (var.add_rules ? 1 : 0)}"
type = "${var.type}"
from_port = "${lookup(var.inbound_sources[count.index], "from_port")}"
to_port = "${lookup(var.inbound_sources[count.index], "to_port")}"
protocol = "${lookup(var.inbound_sources[count.index], "protocol", var.protocol)}"
source_security_group_id = "${lookup(var.inbound_sources[count.index], "source")}"
security_group_id = "${aws_security_group.sg.id}"
}
module "security_group" {
source = "../../../../../modules/tf_aws_ec2_security_group/"
vpc = "vpc-12345"
name = "test-sg"
description = "This is a test sg"
add_rules = true
inbound_sources = [
# Service 1
{
from_port = 80
to_port = 80
source = "sg-1"
},
# Service 2
{
from_port = 80
to_port = 80
source = "sg-2"
}
]
tags {
"Terraform" = "true"
"Environment" = "${var.environment}"
}
}
07:50:50-florian~/workspace/ops/terraform/accounts/sandbox/prod/ap-northeast-1/example$ tf plan
+ module.security_group.aws_security_group.sg
description: "This is a test-sg"
egress.#: "<computed>"
ingress.#: "<computed>"
name: "test-sg"
owner_id: "<computed>"
tags.%: "3"
tags.Environment: "prod"
tags.Name: "test-sg"
tags.Terraform: "true"
vpc_id: "vpc-1234"
+ module.security_group.aws_security_group_rule.sg_rule_sg_ids[0]
from_port: "80"
protocol: "tcp"
security_group_id: "${aws_security_group.sg.id}"
self: "false"
source_security_group_id: "sg-1"
to_port: "80"
type: "ingress"
+ module.security_group.aws_security_group_rule.sg_rule_sg_ids[1]
from_port: "80"
protocol: "tcp"
security_group_id: "${aws_security_group.sg.id}"
self: "false"
source_security_group_id: "sg-2"
to_port: "80"
type: "ingress"
Plan: 3 to add, 0 to change, 0 to destroy.
07:51:03-florian~/workspace/ops/terraform/accounts/sandbox/prod/ap-northeast-1/example$ tf apply
data.terraform_remote_state.vpc_state: Refreshing state...
module.security_group.aws_security_group.sg: Creating...
description: "" => "This is a test-sg"
egress.#: "" => "<computed>"
ingress.#: "" => "<computed>"
name: "" => "test-sg"
owner_id: "" => "<computed>"
tags.%: "" => "3"
tags.Environment: "" => "prod"
tags.Name: "" => "test-sg"
tags.Terraform: "" => "true"
vpc_id: "" => "vpc-01742a65"
module.security_group.aws_security_group.sg: Creation complete (ID: sg-6dee9a0b)
module.security_group.aws_security_group_rule.sg_rule_sg_ids.1: Creating...
from_port: "" => "80"
protocol: "" => "tcp"
security_group_id: "" => "sg-6dee9a0b"
self: "" => "false"
source_security_group_id: "" => "sg-1"
to_port: "" => "80"
type: "" => "ingress"
module.security_group.aws_security_group_rule.sg_rule_sg_ids.0: Creating...
from_port: "" => "80"
protocol: "" => "tcp"
security_group_id: "" => "sg-6dee9a0b"
self: "" => "false"
source_security_group_id: "" => "sg-2"
to_port: "" => "80"
type: "" => "ingress"
module.security_group.aws_security_group_rule.sg_rule_sg_ids.1: Creation complete (ID: sgrule-2871264419)
module.security_group.aws_security_group_rule.sg_rule_sg_ids.0: Creation complete (ID: sgrule-3291610961)
module "security_group" {
source = "../../../../../modules/tf_aws_ec2_security_group/"
vpc = "vpc-12345"
name = "test-sg"
description = "This is a test sg"
add_rules = true
inbound_sources = [
###
### NOTE: Service 3 is especially placed at the index 0 to show you how count reacts.
### In my real use case I am copying the X latest AMIs of a service and building LC automatically
### Whenever a new AMI needs to be copied, terraform will destroy all of them and recreate them because
### the array index has shifted.
###
# Service 3
{
from_port = 80
to_port = 80
source = "sg-3"
},
# Service 1
{
from_port = 80
to_port = 80
source = "sg-1"
},
# Service 2
{
from_port = 80
to_port = 80
source = "sg-2"
}
]
tags {
"Terraform" = "true"
"Environment" = "${var.environment}"
}
}
08:03:42-florian~/workspace/ops/terraform/accounts/sandbox/prod/ap-northeast-1/example$ tf plan
-/+ module.security_group.aws_security_group_rule.sg_rule_sg_ids[0] (new resource required)
from_port: "80" => "80"
protocol: "tcp" => "tcp"
security_group_id: "sg-6dee9a0b" => "sg-6dee9a0b"
self: "false" => "false"
source_security_group_id: "sg-867513e0" => "sg-3" (forces new resource)
to_port: "80" => "80"
type: "ingress" => "ingress"
-/+ module.security_group.aws_security_group_rule.sg_rule_sg_ids[1] (new resource required)
from_port: "80" => "80"
protocol: "tcp" => "tcp"
security_group_id: "sg-6dee9a0b" => "sg-6dee9a0b"
self: "false" => "false"
source_security_group_id: "sg-aaa836cc" => "sg-1" (forces new resource)
to_port: "80" => "80"
type: "ingress" => "ingress"
+ module.security_group.aws_security_group_rule.sg_rule_sg_ids[2]
from_port: "80"
protocol: "tcp"
security_group_id: "sg-6dee9a0b"
self: "false"
source_security_group_id: "sg-2"
to_port: "80"
type: "ingress"
Plan: 3 to add, 0 to change, 2 to destroy.
@Lowess
Copy link
Author

Lowess commented Aug 23, 2017

This scenario shows you how Terraform reacts when the index of an element in an array changes. Terraform will destroy and recreate those resources because the index of the element from the state does not match the new index of the element in the code.

Again this example is trivial and the SG for Service 3 could be added at the end of the list, but when list are dynamically generated it can get tricky to maintain indexes.

An example would be using the ami_copy resource in combination with ami_ids. I am using these two modules to synchronize AMIs across different regions.

The thing is: If one AMI gets deleted from the source account, the Terraform module using a count statement to copy amis will have to delete all AMIs and recreate them all because the index shifted by 1.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment