Lanti
Lanti

Reputation: 2329

Optional argument in module call if map variable is not empty object

I have the following module which creating a private bucket. I only want to use logging, when I define a non-empty logging argument in my module call:

variable "tags" {
  description = "A mapping of tags to assign to the bucket."
  type        = "map"
  default     = {}
}

variable "logging" {
  description = "A mapping of logging to assign to the bucket."
  type        = "map"
  default     = {}
}

resource "aws_s3_bucket" "private_bucket" {
  bucket  = "${var.bucket}"
  acl     = "private"
  policy  = "${data.aws_iam_policy_document.policy.json}"
  tags    = "${var.tags}"
  # logging = "${var.logging}"
  logging = "${length(keys(var.logging)) > 0 ? var.logging : null}"

  # ...

  # This block is replaced by the argument
  /* logging {
    target_bucket = "${var.logging_bucket}"
    target_prefix = "s3/${local.bucket_id}/"
  } */

  # ...
}

However this is not working. I calling the module like this:

module "private_bucket" {
  source = "modules/private-bucket"
  bucket = "${local.private_bucket_name}"

  tags {
    Name        = "Serverless stack private bucket"
    Environment = "${local.stage}"
  }
}

Why top-level if-else not implemented in Terraform? Is there any alternative to initialize a variable in a module/resource with conditional, not just it's value?

Edit:

Here is a pseudo-code, what I want to achieve:

resource "aws_s3_bucket" "private_bucket" {
  bucket  = "${var.bucket}"
  acl     = "private"
  policy  = "${data.aws_iam_policy_document.policy.json}"
  tags    = "${var.tags}"

  # if var.logging is not an empty object,
  # then initialize logging with the object
  if (var.logging != {}) {
    logging = "${var.logging}"
  }

  # ...
}

Upvotes: 2

Views: 13739

Answers (3)

Matt Browne
Matt Browne

Reputation: 12419

If you need to check this inside a loop and you are using Terraform 0.12+, you can do it as follows. In other words, checking length(keys(...)) works now (as of Terraform 0.12).

locals {
  possible_subnets = [
    var.k8s_cluster_1_subnet,
    var.database_subnet,
    var.vpc_solr_subnet
  ]
}

...
module "my-module" {
  ...
  subnet_names = [for subnet in local.possible_subnets :
    subnet.name if length(keys(subnet)) > 0
  ]
}

Upvotes: 2

Ilhicas
Ilhicas

Reputation: 1507

You may use from version 0.12 (I'm not sure if before was possible before), the way to achieve what your pseudo code wants to do, may be achieved with the fllowing terraform hcl script

locals {
  if_logging = var.logging ? [{}] : []
}
... (assume rest of the bucket resource definition here)
dynamic "logging" {
    for_each = local.if_logging

    content {
       target_bucket = var.bucket
       target_prefix = var.prefix
    }
  }

This is due to the way dynamic works.

Check dynamic docs for terraform at https://www.terraform.io/docs/configuration/expressions.html#dynamic-blocks

Upvotes: 2

Richard Cheney
Richard Cheney

Reputation: 36

You can't use maps in the then or else sections. I think that Terraform 0.12 might be more flexible.

I did the same on Azure, and ended up using the merge function in the locals{} section, with var.tags defaulting to {}:

tags    = "${merge(data.azurerm_resource_group.env.tags, var.tags)}"

I then use ${local.tags} against the resource blocks.

Upvotes: 2

Related Questions