DEV Community

seifoo
seifoo

Posted on • Updated on

Terraform aws codebuild : embed buildspec.yml

If you're working with aws and using terraform for ci/cd automation, you have the option to work with CodePipeline and CodeBuild. In CodeBuild you should define your buildspec.yml file as a command list to make your build process.
You have two options: first, read the buildspec.yml file from the source and the second is to use an embedded file.

Using the second option when using terraform has many advantages:

  • you are using a single file for many pipelines
  • changing and maintenance is easy

I had to do this for some of my projects. I had several repos with the same technology and pipeline read buildspec.yml from code. Later we had to do some changes and I was forced to modify all of them.I decided to embed buildspec.yml file in my terraform and manage it using parameters.

The first step was to load buildspec.yml from local and as my previous experiences i tried to use template_file :

data "template_file" "buildspec" {
  template = "${file("${path.module}/buildspec.yml")}"
}
Enter fullscreen mode Exit fullscreen mode

But it failed!

 Error: failed to render : <template_file>:16,32-33: Extra characters after interpolation expression; Expected a closing brace to end the interpolation expression, but found extra characters.
│
│   with module.pipeline.data.template_file.buildspec,
│   on ../../../../modules/cicd_ecs_github_embed/main.tf line 172, in data "template_file" "buildspec":
│  172: data "template_file" "buildspec" {
│
Enter fullscreen mode Exit fullscreen mode

I used it before for loading CodeBuild Policy and CodePipleine policy templates. Anyway, by searching more I found template_file use to see files as a template and except some placeholder like ${var} to fill it. and my file has some $var placeholder that would be filled from CodeBuild!

Solution 1: use local_file

you can ignore using template_file for this step if you dont want to pass any params to it at this stage.

So I moved to use another terraform object local_file :

data "local_file" "buildspec_local" {
    filename = "${path.module}/buildspec.yml.tmpl"
}
Enter fullscreen mode Exit fullscreen mode

and then in my CodeBuild :

source {
    buildspec           = data.local_file.buildspec_local.content
    git_clone_depth     = 0
    insecure_ssl        = false
    report_build_status = false
    type                = "CODEPIPELINE"
  }
Enter fullscreen mode Exit fullscreen mode

solution 2: escape ${} in buildspec

If you really want to pass some dynamic parameters in your buildspec.yml file , you should escape ${var:option} parameters. because terraform expect all variable in simple ${var} format ,when you're using some special tag like IMAGE_TAG=${COMMIT_HASH:=latest} it gives error, so escape this parameter by double $ character s below :
- IMAGE_TAG=$${COMMIT_HASH:=latest}
Now you can pass your desired variables in template file and escape CodeBuild specific variables:

data "template_file" "buildspec" {
  template = "${file("${path.module}/buildspec.yml")}"
  vars = {
  #feed dynamic variables I need 
  ps_asset_s3_bucket="${var.ps_asset_s3_bucket_key}"
  ...
  }
Enter fullscreen mode Exit fullscreen mode

and then load it in source section of your code build
I hope this experience be useful for you.

Discussion (0)