Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dynamic build blocks are not supported #11301

Open
mpalmer opened this issue Oct 2, 2021 · 3 comments · Fixed by #11404
Open

Dynamic build blocks are not supported #11301

mpalmer opened this issue Oct 2, 2021 · 3 comments · Fixed by #11404
Labels
bug hcl2 question stage/thinking Flagged for internal discussions about possible enhancements wontfix Out of scope/alignment with the project, or issue is expected, intended behavior

Comments

@mpalmer
Copy link

mpalmer commented Oct 2, 2021

Overview of the Issue

The description of dynamic blocks at https://www.packer.io/docs/templates/hcl_templates/expressions#dynamic-blocks states:

a special dynamic block type, which is supported anywhere

However, when attempting to create a dynamic build block, like this:

$ cat /tmp/t.pkr.hcl
dynamic "build" {
}
$ packer version
Packer v1.7.6
$ packer build /tmp/t.pkr.hcl
Error: Unsupported block type

  on /tmp/t.pkr.hcl line 1, in dynamic "build":
   1: dynamic "build" {

Blocks of type "dynamic" are not expected here.
[four more copies of the same error message snipped for brevity]

If dynamic build blocks aren't actually supposed to work (:cry:), the documentation should reflect the reality that dynamic blocks are not, in fact, "supported anywhere".

Reproduction Steps

See above.

Packer version

1.7.6.

Simplified Packer Buildfile

dynamic "build" {
}

Operating system and Environment details

Debian 11 on x86_64.

Log Fragments and crash.log files

Error: Unsupported block type
  on /tmp/t.pkr.hcl line 1, in dynamic "build":
   1: dynamic "build" {


Blocks of type "dynamic" are not expected here.                  
@mpalmer mpalmer added the bug label Oct 2, 2021
@nywilken nywilken added the stage/thinking Flagged for internal discussions about possible enhancements label Oct 20, 2021
@nywilken
Copy link
Contributor

Hi there @mpalmer, I went ahead an opened a PR https://github.com/hashicorp/packer/pull/11404/files to call out where dynamic blocks can be used. Please let me know if that is enough detail.

Dynamic blocks are only supported for creating nested blocks within top-level block constructs such as build, source, datasource and provisioners. It can not be used to create top-level blocks such as build like you have in your example.

Do you have an example use case for wanting to generate build blocks?

For what it is worth, you can use dynamic to generate source blocks within a build block. See the example below.

variable "names" {
  type = list(string)
  default = ["testone", "testtwo"]
}

source "null" "example" {
  communicator = "none"
}

build {
  dynamic "source" {
    for_each = var.names
    labels   = ["null.example"]
    content {
      name = source.value
    }
  }

  provisioner "shell-local" {
    inline = ["echo hello from ${source.name}"]
  }
}

@mpalmer
Copy link
Author

mpalmer commented Nov 19, 2021

Yes, I think that your PR clarifies the situation sufficiently. My use case for dynamic source build blocks is (or rather, was, because I've ended up going in a different direction altogether now), roughly the following:

  • I've got a number of AMI "roles", the only difference between each is which Ansible playbook runs during build;
  • The build process for each of my AMIs boils down to "SSH into AMI, make sure all packages are fully upgraded, make sure Python's installed (for Ansible), run Ansible";
  • Some roles use Alpine as a base AMI, others use Ubuntu (for hysterical raisins).

I was not able to figure out how to handle all these requirements in one go, and maintain parallelism, without copy-pasting the build block for each role. The difficulty comes from the combination of needing a different provisioner block for the two different base AMIs (because they use a different package manager), because once you override the name in the dynamic source block, the information you need (which distro that AMI is for) is lost. To extend your example:

variable "source_mapping" {
  type = map(string)
  default = {
    "testone" = "example-a",
    "testtwo" = "example-b",
  }
}

variable "names" {
  type = list(string)
  default = ["testone", "testtwo"]
}

source "null" "example-a" {
  communicator = "none"
}

source "null" "example-b" {
  communicator = "none"
}

build {
  dynamic "source" {
    for_each = var.names
    labels   = ["null.${var.source_mapping[source.value]}"]
    content {
      name = source.value
    }
  }
  
  provisioner "shell-local" {
    only = ["null.example-a"]

    inline = ["echo hella from ${source.name}"]
  }
  
  provisioner "shell-local" {
    only = ["null.example-b"]

    inline = ["echo hellb from ${source.name}"]
  }
}

Neither of those provisioner blocks fire because the name of the source isn't null.example-[ab] any more, it's null.<source.value>. I vaguely recall trying to do tricky things with making the provisioner blocks dynamic as well, but I never got it to work, and the contortions I had to go through got gradually more intricate until I decided that there was no hope of anyone ever being able to figure out what was going on, so I cut bait.

Meanwhile, in a "dynamic build block" world, I thought something like this would do the trick:

# same vars and sources

dynamic "build" {
  for_each = var.source_mapping

  sources = ["null.${build.value}"]

  
  provisioner "shell-local" {
    only = ["null.example-a"]

    inline = ["echo hella from ${build.key}"]
  }
  
  provisioner "shell-local" {
    only = ["null.example-b"]

    inline = ["echo hellb from ${build.key}"]
  }
}

Now I realise that there'd be overlap between the build names (because the build name comes from source name, which would be the same for all builds that use the same source) but I vaguely recall a feature request somewhere for adding the ability to specify the build name in the build, rather than unconditionally using the source name.

@nywilken
Copy link
Contributor

@mpalmer thanks for the detailed use case. This issue was closed with the PR merge. But given your use case I will reopen so that we can use it as feedback for the continued HCL2 work. Thanks again for opening up this issue, and for your detailed responses.

@nywilken nywilken reopened this Nov 19, 2021
@nywilken nywilken added the wontfix Out of scope/alignment with the project, or issue is expected, intended behavior label Dec 15, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug hcl2 question stage/thinking Flagged for internal discussions about possible enhancements wontfix Out of scope/alignment with the project, or issue is expected, intended behavior
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants