terraformaws-codepipeline

Terraform keeps reporting changes - Codepipeline


My Terraform code keeps reporting changes after apply although the plan has been correctly applied.

Terraform and provider version:

Terraform v1.1.7
on darwin_amd64
+ provider registry.terraform.io/hashicorp/aws v4.6.0
resource "aws_codepipeline" "this" {
  name     = "${lookup(var.tags, "Environment", "")}-terraform-pipeline"
  role_arn = aws_iam_role.this.arn

  artifact_store {
    location = data.aws_s3_bucket.codepipeline_bucket.bucket
    type     = "S3"
  }

  dynamic "stage" {
    for_each = local.stages
    content {
      name = stage.value.name
      dynamic "action" {
        for_each = stage.value.action
        content {
          name             = action.value.name
          category         = action.value.category
          owner            = action.value.owner
          provider         = action.value.provider
          version          = action.value.version
          run_order        = action.value.run_order
          input_artifacts  = action.value.input_artifacts
          output_artifacts = action.value.output_artifacts
          configuration    = action.value.configuration
        }
      }
    }
  }
}

locals {
  stages = [{
    name = "Source"
    action = [{
      run_order        = "1"
      category         = "Source"
      name             = "Source"
      owner            = "AWS"
      provider         = "CodeCommit"
      version          = "1"
      input_artifacts  = []
      output_artifacts = ["SourceArtifacts"]
      configuration = {
        BranchName           = "master"
        OutputArtifactFormat = "CODEBUILD_CLONE_REF"
        RepositoryName       = local.repo_name
        ProjectName          = null
      }
    }]
  }, {
    name = "dev"
    action = [{
      run_order        = "2"
      category         = "Build"
      name             = "InitAndPlan"
      owner            = "AWS"
      provider         = "CodeBuild"
      version          = "1"
      input_artifacts  = ["SourceArtifacts"]
      output_artifacts = ["PlanArtifacts"]
      configuration = {
        BranchName           = null
        OutputArtifactFormat = null
        RepositoryName       = null
        ProjectName          = module.codebuild_tf_init_plan.name
      }
    }, {
      run_order        = "3"
      category         = "Approval"
      name             = "Approve"
      owner            = "AWS"
      provider         = "Manual"
      version          = "1"
      input_artifacts  = []
      output_artifacts = []
      configuration = {
        BranchName           = null
        OutputArtifactFormat = null
        RepositoryName       = null
        ProjectName          = null
      }
    }]
  }]
}

When I change the run_order (to be 2 and 2 for the Approval and InitAndPlan) stages, then the issue disapears. It is however, not what I want.

The Approve stages needs to be executed after the InitAndPlan stages.

What do I miss?

As requested, here is the TF plan

Terraform will perform the following actions:

  # module.codepipeline.aws_codepipeline.this will be updated in-place
  ~ resource "aws_codepipeline" "this" {
        id       = "sandbox-terraform-pipeline"
        name     = "sandbox-terraform-pipeline"
        tags     = {}
        # (3 unchanged attributes hidden)


      ~ stage {
            name = "dev"

          ~ action {
              ~ category         = "Build" -> "Approval"
              ~ configuration    = {
                  - "ProjectName" = "sandbox-terraform-init-plan" -> null
                }
              ~ input_artifacts  = [
                  - "SourceArtifacts",
                ]
              ~ name             = "InitAndPlan" -> "Approve"
              ~ output_artifacts = [
                  - "PlanArtifacts",
                ]
              ~ provider         = "CodeBuild" -> "Manual"
              ~ run_order        = 2 -> 3
                # (2 unchanged attributes hidden)
            }
          ~ action {
              ~ category         = "Approval" -> "Build"
              ~ configuration    = {
                  + "ProjectName" = "sandbox-terraform-init-plan"
                }
              ~ input_artifacts  = [
                  + "SourceArtifacts",
                ]
              ~ name             = "Approve" -> "InitAndPlan"
              ~ output_artifacts = [
                  + "PlanArtifacts",
                ]
              ~ provider         = "Manual" -> "CodeBuild"
              ~ run_order        = 3 -> 2
                # (2 unchanged attributes hidden)
            }
        }
        # (2 unchanged blocks hidden)
    }

Plan: 0 to add, 1 to change, 0 to destroy.

Solution

  • It's possible only when action is a set rather list.

    They might look alike but set like in other languages, doesn't guarantee order like lists. More details here & a similar discussion here.

    Going forward, in case of such doubts, you could do type validation of variables like discussed here