AWS Codepipeline with Terraform - How to dynamically create stages

Viewed 2887

I designed an AWS codepipeline module using terraform module, I have multiple actual codepipelines using the codepipeline module. I use module as design pattern because all the codepipelines look similar, except that some of the codepipelines need approval stages, some do not need. How do I design the codepipeline module approval stages so that the actual codepipelines can be created based on different needs?

I tried to use count = 0 or 1 to control the stage but it does not work because the stage is not resource-level. Is there any tricky way or workaround?

I feel this link asked the similar question but I cannot figure out what is the answer: Terraform & AWS CodePipeline - Dynamically define actions on a stage

Here is my codepipeline terraform module:

resource "aws_codepipeline" "dev" {
  name     = "my_codepipeline"
  role_arn = ...
  ...
  stage {
    name = "Source"
    ...
  }
  stage {
    name = "test"
    ...
  }
  stage {
    # count = 0 # or 1. it does not work
    name = "Approval"
    action {
      name     = "Approval"
      owner    = "AWS"
      category = "Approval"
      provider = "Manual"
      version  = "1"

      configuration {
        NotificationArn    = "..."
        CustomData         = "..."
        ExternalEntityLink = "..."
      }
    }
  }
  stage {
    name = "prod"
    ...
  }
}
3 Answers

To dynamically add a stage (and not just an action) you could do the following:

dynamic "stage" {
   for_each = var.production_approval ? [1] : []
   content {
     name = "Approve"
     action {
       configuration = {
         NotificationArn = var.approve_sns_arn
         CustomData      = var.approve_comment
       }
       name     = "Production-Approval"
       category = "Approval"
       owner    = "AWS"
       provider = "Manual"
       version  = "1"
     }
   }
 }

When going through your use case, I have the feeling that it is very suitable with new terraform feature in v0.12.x

Below is a sample on how to use for_each to set dynamic target regions, you should be fine to do the same for stages.

  dynamic "target_region" {
    for_each = var.target_image_regions
    content {
      name                   = target_region.value
      regional_replica_count = 1
    }
  }

let me know if this works for you or not.

Reference: https://www.hashicorp.com/blog/announcing-terraform-0-12

I figured that you can get this working in Terraform 0.12+ as BMW said, but only if you have number of block greater than 0.

At least 1 "action" blocks are required.

Unfortunately, my (and your) use case required 0/1 actions depending on the environment so we have to manage it manually for a while.

Cheers.

dynamic "action" {
  for_each = local.production_approval # e.g. [] || [true]  
  content {
    category         = "Approval"
    configuration    = {}
    input_artifacts  = []
    name             = "Production-Approval"
    output_artifacts = []
    owner            = "AWS"
    provider         = "Manual"
    run_order        = 1
    version          = "1"
  }
}
Related