Search code examples
terraformterraform-provider-awsamazon-ekshcl

Terraform: Can I conditionally create an object within a map?


I have a module defined for an EKS cluster using hashicorp's AWS EKS module, and I am trying to conditionally create a managed node group depending on the cluster.

I have no idea if this is even feasible, I know conditionals within Terraform are classically limiting and frustrating. Here is what I have so far (invalid), but it gets the point across for what I'm trying to do which is conditionally create the gpu managed node group.

module "eks" {
  source  = "terraform-aws-modules/eks/aws"
  version = "19.0.4"

  ...
  ...
  ...

  eks_managed_node_groups = {
    // always launch the generic group
    generic = {
      # The default iam_role_name is too long and causes a Terraform
      # error, so I changed all of these to keep them consistent.
      name                = "${var.cluster_name}-generic"
      iam_role_name       = "${var.cluster_name}-generic"
      security_group_name = "${var.cluster_name}-generic"
    }
    gpu = var.enable_gpu ? {
      ami_type       = "AL2_x86_64"
      capacity_type  = "ON_DEMAND"
      instance_types = ["p2.xlarge"] 

      name                = "${var.cluster_name}-gpu"
      iam_role_name       = "${var.cluster_name}-gpu"
      security_group_name = "${var.cluster_name}-gpu"

      desired_size = 1 
      max_size     = 3 
      min_size     =  0 

      update_config = {
        max_unavailable_percentage = 50
      }

      create_schedule = true
      schedules = {
        schedule-scale-down = {
          recurrence       = "0 1 * * 1-5"
          min_size         = -1
          max_size         = -1
          desired_capacity = 0
        },
        schedule-scale-up = {
          recurrence       = "0 13 * * 1-5"
          min_size         = -1
          max_size         = -1
          desired_capacity = 1
        }
      }
    } : {}

Is this even possible? Running this throws the following error: The true and false result expressions must have consistent types. The 'true' value includes object attribute "ami_type", which is absent in the 'false' value.


Solution

  • I figured this out with the help of the Hashicorp discussion board

    The best way I found to do this is merging the objects in locals, then passing that local value to eks_managed_node_groups like so:

    locals {
      default_managed_node_group = {
        generic = {
          name                = "${var.cluster_name}-generic"
          iam_role_name       = "${var.cluster_name}-generic"
          security_group_name = "${var.cluster_name}-generic"
        }
      }
    
      gpu_managed_node_group = {
        gpu = {
          ami_type       = "AL2_x86_64"
          capacity_type  = "ON_DEMAND"
          instance_types = ["p2.xlarge"] 
    
          name                = "${var.cluster_name}-gpu"
          iam_role_name       = "${var.cluster_name}-gpu"
          security_group_name = "${var.cluster_name}-gpu"
    
          desired_size = 1 
          max_size     = 3 
          min_size     =  0 
    
          update_config = {
            max_unavailable_percentage = 50
          }
    
          create_schedule = true
          schedules = {
            schedule-scale-down = {
              recurrence       = "0 1 * * 1-5"
              min_size         = -1
              max_size         = -1
              desired_capacity = 0
            },
            schedule-scale-up = {
              recurrence       = "0 13 * * 1-5"
              min_size         = -1
              max_size         = -1
              desired_capacity = 1
            }
          }
        }
      }
    
      # Merge into a single object if enable_gpu = true
      eks_managed_node_groups = merge( local.default_managed_node_group, var.enable_gpu ? local.gpu_managed_node_group : {} )
      
    }
    
    module "eks" {
      source  = "terraform-aws-modules/eks/aws"
      version = "19.0.4"
      ...
      
      eks_managed_node_groups = local.eks_managed_node_groups