hashicorp / terraform

Terraform enables you to safely and predictably create, change, and improve infrastructure. It is a source-available tool that codifies APIs into declarative configuration files that can be shared amongst team members, treated as code, edited, reviewed, and versioned.
https://www.terraform.io/
Other
42.59k stars 9.54k forks source link

Have coalesce skip non-existing resources #9543

Closed bart613 closed 8 years ago

bart613 commented 8 years ago

Hi there,

I'm trying to use coalesce as a mean to provide a "default" value if something doesn't exist. See the following code:

variable "dummy" { default = "asdf" }

resource "aws_alb_target_group" "target_group" {
  name     = "${var.alb_target_group_name}"
  port     = "${var.container_port}"
  protocol = "${var.container_protocol}"
  vpc_id   = "${var.vpc}"

  count = "0"
}
resource "aws_alb_listener_rule" "rule" {
  listener_arn = "${var.alb_listener_arn}"
  priority     = "${var.alb_listener_priority + count.index}"

  action {
    type             = "forward"
    target_group_arn = "${coalesce(aws_alb_target_group.target_group.arn, var.dummy)}"
  }

  condition {
    field  = "path-pattern"
    values = [ "${element(split(",", var.alb_listener_paths), count.index)}" ]
  }

  count = "${coalesce(length(split(",", var.alb_listener_paths)), var.zero)}"
}

In this case, if the count in the aws_alb_target_group.target_group resource is 0, the aws_alb_listener_rule.rule fails saying aws_alb_target_group.target_group group doesn't have attribute arn, which is true - as it doesn't exist.

My hope was for the coalesce function, to return first non-empty value and if it hits non-existing resource, it'd simply skip over it.

Having coalesce skipping non-existing resources would make creating some conditions much easier / possible with terraform.

bart613 commented 8 years ago

Sorry - being silly about the use of count here...

luisdavim commented 7 years ago

I actually have a case for this, I’m trying to write a module to deploy Sensu on AWS, the plan was to use elasticache for Redis but now I’m facing an edge case. Some of our VPCs have tenancy set to dedicated and we can’t use elasticache there(http://docs.aws.amazon.com/AmazonElastiCache/latest/UserGuide/AmazonVPC.EC.html), I thought I could work around this by conditionally using elasticache or deploying a redis cluster in a ASG. I’ve written the code and used:

count = "${replace(replace(var.vpc_instance_tenancy,"/.*dedicated.*/","0"),"/(.*default.*|^$)/","1")}"

to decide if I should create the elasticahe cluster or the ASG, the problem is that I need to pass a hostname or IP address to the Sensu servers and api nodes so that they can connect to Redis, was planning to use:

redis_host = "${coalesce(aws_elasticache_cluster.redis_cluster.cache_nodes.0.address,aws_elb.redis_lb.dns_name)}"

but this always fails because one of the resources never gets created and I can’t reference it in the coalesce function.

luisdavim commented 7 years ago

@bart613 can you reopen this issue?

apparentlymart commented 7 years ago

@luisdavim if you have a resource that sometimes has count = 0 then you must reference it using the "splat variable" syntax: aws_elasticache_cluster.redis_cluster.*.cache_nodes.0.address. This will produce an empty list if count = 0 and a one-element list if count = 1.

Here's one way to write your redis_host expression to exploit that behavior for conditional operation:

  redis_host = "${element(concat(aws_elasticache_cluster.redis_cluster.*.cache_nodes.0.address, list(aws_elb.redis_lb.dns_name)), 0)}"

This produces a list with the zero-or-one redis cluster addresses followed by the one ELB dns name, and then takes the first element of that list.

luisdavim commented 7 years ago

Thanks. But what about the elb resource? I'm creating one or the other.

apparentlymart commented 7 years ago

The same trick can be done for both of them:

  redis_host = "${element(concat(aws_elasticache_cluster.redis_cluster.*.cache_nodes.0.address, aws_elb.redis_lb.*.dns_name), 0)}"
luisdavim commented 7 years ago

Interesting, I'll give it a try. Thanks

luisdavim commented 7 years ago

it worked, thanks a milion :)

ghost commented 4 years ago

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.