Home > Software engineering >  Passing Variables into a customer terraform module
Passing Variables into a customer terraform module

Time:06-10

I am trying to build a module in terraform that can be passed a variable map from a workspace file and lookup the variables to build an AWS CodePipeline. For those not aware, CodePipeline has a series of stages, and inside those stages are actions. My module needs to handle building a pipeline wiht any supported number of stages and actions within those stages.

Below is a part of the module I've wirtten concerned with the creation of the pipeline itself:

dynamic "stage" {
    for_each = [for s in var.stages : {
      name   = s.name
      action = s.action
    } if(lookup(s, "enabled", true))]

    content {
      name = stage.value.name
      dynamic "action" {
        for_each = stage.value.action
        content {
          name             = lookup(action.value, "name", null)
          owner            = lookup(action.value, "owner", null)
          version          = lookup(action.value, "version", null)
          category         = lookup(action.value, "category", null)
          provider         = lookup(action.value, "provider", null)
          input_artifacts  = lookup(action.value, "input_artifacts", null)
          output_artifacts = lookup(action.value, "output_artifacts", null)
          configuration    = {
            BranchName           = lookup(action.value, "BranchName", null)
            PollForSourceChanges = lookup(action.value, "PollForSourceChanges", null)
            RepositoryName       = lookup(action.value, "RepositoryName", null)
            ProjectName          = lookup(action.value, "ProjectName", null)
          }
          role_arn         = lookup(action.value, "role_arn", null)
          run_order        = lookup(action.value, "run_order", null)
          region           = lookup(action.value, "region", null)
        }
      }
    }
  }

  tags = merge(
    { "Name" = "${var.prefix}-${var.name}" },
    var.tags,
  )
}

And here is an excerpt from the workspace yaml, where I pass the variables for two stages, each with an associated action:

test_pipeline_prefix: "test"
test_pipeline_name: "test-pipeline"
test_pipeline_description: "this is a POC pipeline"
test_pipeline_s3: "<<REDACTED ARN>>"
test_pipeline_codestar_arn: "<<REDACTED ARN>>"
test_pipeline_tags: [""]

test_pipeline_stages: [{
  name: "Source",
  action: [{
    name                   = "Source",
    category               = "Source",
    owner                  = "AWS"
    version                = "1",
    provider               = "CodeStarSourceConnection",
    output_artifacts       = "source_output",
    BranchName             = "main",
    PollForSourceChanges   = "false",
    RepositoryName         = "<<REDACTED REPO>>",
    region                 = "eu-west-2",
    run_order              = 1
  }]
},
{
  name: "Plan",
  action: [{
    name                   = "Plan",
    category               = "Build",
    owner                  = "AWS"
    version                = "1",
    provider               = "CodeBuild",
    input_artifacts        = "source_output",
    output_artifacts       = "build_output",
    ProjectName            = "pipeline-plan",
    run_order              = 2
  }]
}]

Finally I call it with:

module "codepipeline" {
  source         = "./modules/codepipeline"
  s3             = local.vars.test_pipeline_s3
  description    = local.vars.test_pipeline_description
  prefix         = local.vars.test_pipeline_prefix
  name           = local.vars.test_pipeline_name
  stages         = local.vars.test_pipeline_stages
  codestar_arn   = local.vars.test_pipeline_codestar_arn

  tags = {
    Environment = local.vars.env
    Terraform = "true"
  }
}

What I am hoping for it to do, is loop through the stages and actions in the "test_pipeline_stages" variable supplied, and loop through to create a stage for the Source, with an action configured to connect to the preexsiting CodeStar connection, and another stage called "Plan" that runs the CodeBuild job as it's action.

The result I'm actually getting is:

│ Error: Missing required argument
│   with module.codepipeline.aws_codepipeline.this,
│   on modules/codepipeline/main.tf line 1, in resource "aws_codepipeline" "this":
│    1: resource "aws_codepipeline" "this" {
│ 
│ The argument "stage.0.action.0.owner" is required, but no definition was
│ found.

│ Error: Missing required argument
│   with module.codepipeline.aws_codepipeline.this,
│   on modules/codepipeline/main.tf line 1, in resource "aws_codepipeline" "this":
│    1: resource "aws_codepipeline" "this" {
│ 
│ The argument "stage.0.action.0.provider" is required, but no definition was
│ found.

│ Error: Missing required argument
│   with module.codepipeline.aws_codepipeline.this,
│   on modules/codepipeline/main.tf line 1, in resource "aws_codepipeline" "this":
│    1: resource "aws_codepipeline" "this" {
│ 
│ The argument "stage.0.action.0.category" is required, but no definition was
│ found.

│ Error: Missing required argument
│ 
│   with module.codepipeline.aws_codepipeline.this,
│   on modules/codepipeline/main.tf line 1, in resource "aws_codepipeline" "this":
│    1: resource "aws_codepipeline" "this" {
│ 
│ The argument "stage.0.action.0.version" is required, but no definition was
│ found.

│ Error: Missing required argument
│   with module.codepipeline.aws_codepipeline.this,
│   on modules/codepipeline/main.tf line 1, in resource "aws_codepipeline" "this":
│    1: resource "aws_codepipeline" "this" {
│ 
│ The argument "stage.1.action.0.version" is required, but no definition was
│ found.

│ Error: Missing required argument
│   with module.codepipeline.aws_codepipeline.this,
│   on modules/codepipeline/main.tf line 1, in resource "aws_codepipeline" "this":
│    1: resource "aws_codepipeline" "this" {
│ 
│ The argument "stage.1.action.0.category" is required, but no definition was
│ found.

│ Error: Missing required argument
│   with module.codepipeline.aws_codepipeline.this,
│   on modules/codepipeline/main.tf line 1, in resource "aws_codepipeline" "this":
│    1: resource "aws_codepipeline" "this" {
│ 
│ The argument "stage.1.action.0.owner" is required, but no definition was
│ found.

│ Error: Missing required argument
│   with module.codepipeline.aws_codepipeline.this,
│   on modules/codepipeline/main.tf line 1, in resource "aws_codepipeline" "this":
│    1: resource "aws_codepipeline" "this" {
│ 
│ The argument "stage.1.action.0.provider" is required, but no definition was
│ found.

│ Error: Missing required argument
│   with module.codepipeline.aws_codepipeline.this,
│   on modules/codepipeline/main.tf line 2, in resource "aws_codepipeline" "this":
│    2:   name     = "${var.prefix}-${var.name}"
│ 
│ The argument "stage.0.action.0.name" is required, but no definition was
│ found.

│ Error: Missing required argument
│   with module.codepipeline.aws_codepipeline.this,
│   on modules/codepipeline/main.tf line 2, in resource "aws_codepipeline" "this":
│    2:   name     = "${var.prefix}-${var.name}"
│ 
│ The argument "stage.1.action.0.name" is required, but no definition was
│ found.

This suggest to me that its not indexing the variables prporly but I can't really figure the best way to proceed. Anyone got any ideas?

CodePudding user response:

comma is missing after owner= "AWS", put comma in workspace file.

CodePudding user response:

Thanks to responders so far - the actual fix I'll detail below, but all responses up to this point have helped me get there. I also agree that supplying null values as a fallback is not sensible; I'll look to review that.

The actual issue was simply that my workspace yaml as posted above is... not valid yaml. Once I replaced it with the below, the module began to read out the values correctly.

test_pipeline_stages: [{
  name: "Source",
  action: [{
    ActionName: "Source",
    ActionCategory: "Source",
    ActionOwner: "AWS",
    ActionVersion: "1",
    ActionProvider: "CodeStarSourceConnection",
    output_artifacts: ["source_output"],
    BranchName: "main",
    PollForSourceChanges: "false",
    RepositoryName: "REDACTED",
    ConnectionArn: "REDACTED",
    region: "eu-west-2",
    run_order: 1
  }]
},
{
  name: "Plan",
  action: [{
    ActionName: "Plan",
    ActionCategory: "Build",
    ActionOwner: "AWS",
    ActionVersion: "1",
    ActionProvider: "CodeBuild",
    input_artifacts: ["source_output"],
    output_artifacts: ["build_output"],
    ProjectName: "pipeline-plan",
    test_pipeline_ans_tags: "",
    run_order: 2
  }]
}]
  • Related