amazon-web-servicesterraformaws-transfer-family

Terraform AWS: Using foreach with aws_transfer_workflow - SFTP transfer workflow with multiple steps?


I have been attempting to create an SFTP transfer workflow with multiple steps that I can change dynamically .

Error

With the below resource I get multiple workflows each with 5 steps. See below.

`

resource "aws_transfer_workflow" "Workflow" {
  for_each = var.workflow_steps

  dynamic "steps" {
    for_each = each.value # To create a dynamic block
    content {
      dynamic "copy_step_details" {
        for_each = each.value.type == "COPY" ? [1] : []
        content {
          name                 = each.value.name
          source_file_location = each.value.source_file_location
          destination_file_location {
            s3_file_location {
              bucket = each.value.destination_bucket
              key    = each.value.destination_key
            }
          }
        }
      }

      dynamic "custom_step_details" {
        for_each = each.value.type == "CUSTOM" ? [1] : []
        content {
          name                 = each.value.name
          source_file_location = each.value.source_file_location
          target               = each.value.target
          timeout_seconds      = each.value.timeout_seconds
        }
      }

      dynamic "delete_step_details" {
        for_each = each.value.type == "DELETE" ? [1] : []
        content {
          name                 = each.value.name
          source_file_location = each.value.source_file_location
        }
      }

      dynamic "decrypt_step_details" {
        for_each = each.value.type == "DECRYPT" ? [1] : []
        content {
          name                 = each.value.name
          type = "PGP"
          source_file_location = each.value.source_file_location
          destination_file_location {
            s3_file_location {
              bucket = each.value.destination_bucket
              key    = each.value.destination_key
            }
          }

        }
      }

        dynamic "tag_step_details" {
        for_each = each.value.type == "TAG" ? [1] : []
        content {
          name                 = each.value.name
          source_file_location = each.value.source_file_location
          tags {
                key   = each.value.tag_key
                value = each.value.tag_value
              }
        }
      }
      type = each.value.type
    }
  }
}

See variable used as input:

variable "workflow_steps" {
  description = "Map of workflow steps"
  type        = map(object)
  default = {
    step1 = {
      type = "COPY"
      name = "Copy"
      source_file_location = "$${original.file}"
      destination_bucket = ""
      destination_key = ""
    }
    step2 = {
      type = "CUSTOM"
      name = "Custom"
      source_file_location = "$${original.file}"
      target = "arn:aws:lambda"
      timeout_seconds = 60
    }
    step3 = {
      type = "TAG"
      name = "Tag"
      source_file_location = "$${original.file}"
      tag_key = "Name"
      tag_value = "Hello World"
    }
    step4 = {
      type = "DECRYPT"
      name = "Decrypt"
      source_file_location = "$${original.file}"
      destination_bucket = ""
      destination_key = "test"
    }
    step5 = {
      type = "DELETE"
      name = "Delete"
      source_file_location = "$${original.file}"
    }
  }
}

Result:

I attempted changing the variable data type but instead of getting 5 workflows with 5 steps I get 5 workflows with one step. When I attempt to remove the for_each block thats outside of the dynamic block the resource doesn't deploy successfully. I get further errors.


Solution

  • You should apply for_each only within the dynamic block to create multiple steps. The resource-level for_each should only be used if you're creating multiple workflows with different sets of steps.

    Somthing like this, here count is just to test execution you can remove it if it's one workflow :

    resource "aws_transfer_workflow" "workflow" {
      count = 1 # Only one workflow
      
      steps {
        dynamic "step" {
          for_each = var.workflow_steps
          content {
            type = step.value.type
            
            dynamic "copy_step_details" {
              for_each = step.value.type == "COPY" ? [1] : []
              content {
                name                 = step.value.name
                source_file_location = step.value.source_file_location
                destination_file_location {
                  s3_file_location {
                    bucket = step.value.destination_bucket
                    key    = step.value.destination_key
                  }
                }
              }
            }
    
            dynamic "custom_step_details" {
              for_each = step.value.type == "CUSTOM" ? [1] : []
              content {
                name                 = step.value.name
                source_file_location = step.value.source_file_location
                target               = step.value.target
                timeout_seconds      = step.value.timeout_seconds
              }
            }
    
            dynamic "delete_step_details" {
              for_each = step.value.type == "DELETE" ? [1] : []
              content {
                name                 = step.value.name
                source_file_location = step.value.source_file_location
              }
            }
    
            dynamic "decrypt_step_details" {
              for_each = step.value.type == "DECRYPT" ? [1] : []
              content {
                name                 = step.value.name
                source_file_location = step.value.source_file_location
                destination_file_location {
                  s3_file_location {
                    bucket = step.value.destination_bucket
                    key    = step.value.destination_key
                  }
                }
              }
            }
    
            dynamic "tag_step_details" {
              for_each = step.value.type == "TAG" ? [1] : []
              content {
                name                 = step.value.name
                source_file_location = step.value.source_file_location
                tags {
                  key   = step.value.tag_key
                  value = step.value.tag_value
                }
              }
            }
          }
        }
      }
    }