AWS CodePipeline V2のパイプライン変数をTerraformで扱う

# はじめに
[2023年10月24日に発表されたAWS CodePipelineのV2タイプ](https://aws.amazon.com/jp/about-aws/whats-new/2023/10/aws-codepipeline-parameterized-pipelines/)では、ついにパイプライン起動時に変数を渡して動的に動作を変更できるようになった。これまではSSMのParameter Storeを使うというワンクッションが必要であったが、そういった手間が不要になって運用におけるToilが減った。

しばらくTerraformのAWSプロバイダーはV2タイプのパイプラインに対応していなかったが、ようやく5.32.0で対応されたので、既存のパイプラインにどのような変更を加えれば良いかを書いておく。

本記事の対象者は、主に以下だ。
- TerraformでCodePipelineを実装したことがある
- CodePipelineの利用はこれからだが、Terraform自体はある程度使ったことがある

なお、TerraformのCodePipelineの実装サンプルそのものは[過去の記事](https://qiita.com/neruneruo/items/cda42244ad8e1e2d83b0#terraform%E3%81%AE%E5%AE%9A%E7%BE%A9)で書いているので、こちらも参考にしていただきたい。

:::note warn
CodePipelineはV2タイプになると既存と料金体系が変わる。
パイプラインの実行時間(not実行回数)に応じた料金がかかるようになるので、いきなりすべてのパイプラインを変更して高額請求にならないよう注意しよう。
詳細は[公式のCodePipelineの利用料金のページ](https://aws.amazon.com/jp/codepipeline/pricing/)を参照。
:::


# CodePipelineの修正内容
パイプライン変数の追加は、以下のようにすれば良い。
今回は、元にしているパイプラインは、S3からソースを取得してビルドステージで利用するシンプルな構成にしているが、ステージが増えたとしても、特にやることに大差はない。

```diff_HCL
resource "aws_codepipeline" "example" {
  name     = local.codepipeline_pipeline_name
  role_arn = aws_iam_role.codepipeline.arn

+ pipeline_type = "V2"
+
+ variable {
+   name          = "example_var1"
+   description   = "パイプライン変数のサンプル その1"
+   default_value = "value1"
+ }
+
+ variable {
+   name          = "example_var2"
+   description   = "パイプライン変数のサンプル その2"
+   default_value = "value2"
+ }

  artifact_store {
    type     = "S3"
    location = aws_s3_bucket.example.bucket
  }

  stage {
    name = "Source"

    action {
      run_order        = 1
      name             = "Source"
      category         = "Source"
      owner            = "AWS"
      provider         = "S3"
      version          = "1"
      output_artifacts = ["SourceArtifact"]

      configuration = {
        S3Bucket    = aws_s3_bucket.example.id
        S3ObjectKey = "input.zip"
      }
    }
  }

  stage {
    name = "Build"

    action {
      run_order       = 2
      name            = "Build"
      category        = "Build"
      owner           = "AWS"
      provider        = "CodeBuild"
      version         = "1"
      input_artifacts = ["SourceArtifact"]

      configuration = {
        ProjectName = aws_codebuild_project.example.name
+       EnvironmentVariables = jsonencode([
+         {
+           type  = "PLAINTEXT"
+           name  = "EXAMPLE_VAR1"
+           value = "#{variables.example_var1}"
+         },
+         {
+           type  = "PLAINTEXT"
+           name  = "EXAMPLE_VAR2"
+           value = "#{variables.example_var2}"
+         },
+       ])
      }
    }
  }
}
```

[AWS公式のユーザーガイド](https://docs.aws.amazon.com/ja_jp/codepipeline/latest/userguide/tutorials-pipeline-variables.html)に書かれているように、作ったパイプライン変数は```#{variables.パイプライン変数名}```で参照してCodeBuildの環境変数として渡すことが可能だ。CodeBuild側で定義する環境変数では参照できないので注意。

```default_value```は設定しないことも可能だが、その場合はパイプライン起動時に何かしらの変数を設定しないと、以下のようにエラーになって起動できないため注意が必要だ。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/111314/e5af3c28-0075-81b4-544c-1c9d1460b4f9.png)

ビルドステージの```configuration```の```EnvironmentVariables```は、JSON形式で渡さなければいけない。
そのままのJSONを書こうとすると、複数の変数を書いたりするのは大変だし、HCLで真面目にエスケープ等を書いていくと面倒だし可読性も下がるので、```jsonencode()```を活用しよう。

# いざ、起動してみる
さて、それでは以下のBuildspecをS3に格納して、起動してみよう。
今回のBuildspecでは、CodeBuildの```EnvironmentVariables```で指定した環境変数を表示して、うまく渡せていることを確認する。

```yaml:buildspec.yml
version: 0.2

phases:
  build:
    commands:
      - echo $EXAMPLE_VAR1
      - echo $EXAMPLE_VAR2
```

CodePipelineのコンソールから起動する場合は、起動時に以下のモーダルウィンドウが表示される。必要に応じて内容を書き換えよう。
今回は、example_var2をデフォルト値から変更してみる。以下のように、変数の値にスペースを入れることもできるので、コマンドライン引数をまとめて指定するといった使い方もできるはずだ。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/111314/afc4291c-7bd9-ebbd-b48a-f57482091b35.png)

CodeBuildの実行ログには以下のように出力される。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/111314/0bd77d61-60f0-5204-2b4a-5e4cb1accd62.png)

ちゃんと空白も含めて展開されている。

これで、CI/CDパイプラインの活用方法がより広げられるようになった。