Search code examples
amazon-ec2terraformterraform-provider-aws

Terraform EC2 NIC private_ips build list from custom module outputs


I have a custom child module that is building various AWS resources for unique EC2 instances, which are loaded from JSON definition files. In the root module, I need to concatenate an output property from each of the child modules to apply secondary private IPv4 addresses to a network interface resource. The network interface will have 2 static IPv4 addresses, plus an IPv4 address from EACH of the child modules that are built.

Here is my folder structure:

root/
|_
  main.tf
  instances/
  |_
    instance1.json
    instance2.json
    ...
  modules/instance/
  |_
    main.tf
    outputs.tf

The root main.tf file will load all of the JSON files into custom child modules using the for_each argument like so:

locals {
  json_files = fileset("./instances/", "*.json")
  json_data = [for f in local.json_files: jsondecode(file("./instances/${f}"))]
}
module "instance" {
  for_each = { for k,v in local.json_data: k => v }
  source = "../modules/instance"
  server_name = each.value.server_name
  firewall_vip = each.value.firewall_vip
  ...
}

There is a string output attribute I'm trying to grab from the child modules to then apply as a list to an aws_network_interface resource private_ips property.

The string output attribute is a virtual IP used for special routing through a firewall to the backend instances. Example of the output attribute in the child module outputs.tf file:

output "firewall_vip" {
  description = "The virtual IP to pass through firewall"
  value = "10.0.0.10"
}

Side note: The "firewall_vip" output property is ALSO defined within the JSON files for an input variable to the child module... So is there an easier way to pull the property straight from the JSON files instead of relying on the child module outputs?

Within the root module main.tf file, I am trying to concatenate a list of all secondary IPs to apply to the NIC with the Splat expression (not sure if this is the right approach):

resource "aws_network_interface" "firewall" {
  subnet_id = <subnet ID>
  private_ips = concat(["10.0.0.4","10.0.0.5"], module.instance[*].firewall_vip)
}

I receive an error saying:

Error: Incorrect attribute value type
  module.instance is a map of object, known only after apply
Inappropriate value for attribute "private_ips": element 2: string required.

I have also tried to use the For expression to achieve this like so:

resource "aws_network_interface" "firewall" {
  private_ips = concat(["10.0.0.4", "10.0.0.5"], [for k,v in module.instance[*]: v if k == "firewall_vip"])
  ...
}

I do not receive any errors with this method, but it also will not recognize any of the "firewall_vip" outputs from the child modules for appending to the list.

Am I going about this the wrong way? Any suggestions would be very helpful, as I'm still a Terraform newb.


Solution

  • I realize I was over-complicating this, and I could just use the locals{} block to pull the JSON attributes without having to rely on the child module outputs...

    In the root main.tf file:

    locals {
      json_data = [for f in fileset("./instances/", "*.json"): jsondecode(file("./instances/${f}"))]
      server_vips = local.json_data[*].server_vip
    }
    
    resource "aws_network_inteface" "firewall" {
      private_ips = concat(["10.0.0.4", "10.0.0.5"], local.server_vips)
      ...
    }