How do I use one provisioner for multiple Packer builds in an HCL-formatted template?

I’m using Packer to provision a VM for my project’s CI pipeline, which is hosted on a supported cloud provider. My provisioning scripts are a little complicated, so I need to iterate on them carefully to get them right. To save money I’m using a local image builder with the same provisioners as used in the cloud builder. This local image won’t be used in production, or even in development; it just serves to help me validate my provisioning scripts (and the resulting environment).

Since I’m testing my provisioner scripts, I want to share one provisioner block with all relevant build blocks. However, I can’t figure out for the life of me how to do that; for now, I’ve been copying and pasting my provisioner block. The only field is the only field that varies, as I don’t usually want to build the local and cloud images at the same time. How can I use one provisioner block within multiple build blocks in an HCL-formatted template, plus the occasional override?

Here’s (a simplified version of) the code that I want to shrink:

# Variables go here...

source "vagrant" "windows-local" {
  source_path = "gusztavvargadr/visual-studio"
  box_name = "build-runner-windows-local"
  box_version = "v2019.0.2010"
  communicator = "ssh"
  # Other fields omitted for brevity
}

source "amazon-ebs" "windows" {
  access_key = "${var.aws_access_key}"
  ami_name = "build-runner-windows"
  communicator = "winrm"
  instance_type = "t2.micro"
  region = "${var.aws_region}"
  secret_key = "${var.aws_secret_key}"
  source_ami_filter {
    filters = {
      name = "Windows_Server-2019-English-Full-Base-2020.11.11"
      root-device-type = "ebs"
      virtualization-type = "hvm"
    }
    most_recent = true
    owners = ["amazon"]
  }
  # Other fields omitted for brevity
}

build {
  name = "windows-aws"
  sources = ["source.amazon-ebs.windows"]

  provisioner "powershell" {
    environment_vars = [
      "AWS_ACCESS_KEY_ID=${var.aws_access_key}",
      "AWS_SECRET_ACCESS_KEY=${var.aws_secret_key}",
      "AWS_DEFAULT_REGION=${var.aws_region}",
      "A_DOZEN_MORE_VARS=..."
    ]
    only = ["amazon-ebs.windows"] # Note: Not the same value as in the windows-local build
    scripts = [
      "windows/first-script.ps1",
      "windows/second-script.ps1",
      "windows/cleanup.ps1"
    ]
  }
  provisioner "windows-restart" {}

}

build {
  name = "windows-local"
  sources = ["source.vagrant.windows-local"]

  provisioner "powershell" {
    environment_vars = [
      "AWS_ACCESS_KEY_ID=${var.aws_access_key}",
      "AWS_SECRET_ACCESS_KEY=${var.aws_secret_key}",
      "AWS_DEFAULT_REGION=${var.aws_region}",
      "A_DOZEN_MORE_VARS=..."
    ]
    only = ["vagrant.windows-local"]  # Note: Not the same value as in the windows-aws build
    scripts = [
      "windows/first-script.ps1",
      "windows/second-script.ps1",
      "windows/cleanup.ps1"
    ]
  }
  provisioner "windows-restart" {}
}

Hey there! You just need to add the source builders to sources in the build. In your case, that would be:

build {
  sources = [
       "source.vagrant.windows-local",
       "source.amazon-ebs.windows"
  ]

  provisioner "powershell" {
    environment_vars = [
      "AWS_ACCESS_KEY_ID=${var.aws_access_key}",
      "AWS_SECRET_ACCESS_KEY=${var.aws_secret_key}",
      "AWS_DEFAULT_REGION=${var.aws_region}",
      "A_DOZEN_MORE_VARS=..."
    ]
    only = ["vagrant.windows-local"]  # Note: Not the same value as in the windows-aws build
    scripts = [
      "windows/first-script.ps1",
      "windows/second-script.ps1",
      "windows/cleanup.ps1"
    ]
  }
  provisioner "windows-restart" {}
}

Then, you can remove name from build and add them in the specific source block, like:

source "vagrant" "windows-local" {
  name = "windows-local"
  source_path = "gusztavvargadr/visual-studio"
  box_name = "build-runner-windows-local"
  # ...
}

source "amazon-ebs" "windows" {
  name = "windows-aws"
  access_key = "${var.aws_access_key}"
  ami_name = "build-runner-windows"
  # ...
}

If you need more information, here some doc you might find helpful:


2 Likes

Perfect, thank you very much! If you want to add that answer to my Stack Overflow post, I’ll accept it there so you get the rep.