hashicorp / terraform

Terraform enables you to safely and predictably create, change, and improve infrastructure. It is a source-available tool that codifies APIs into declarative configuration files that can be shared amongst team members, treated as code, edited, reviewed, and versioned.
https://www.terraform.io/
Other
42.44k stars 9.51k forks source link

map and filter over lists #16597

Closed xenoterracide closed 5 years ago

xenoterracide commented 6 years ago

Problem

you have a data structure that you want to transform into another data structure, specifically a list of maps.

https://stackoverflow.com/q/43893295/206466 ( arrow is convert to)

variable "my" { type = "list", default = [{ key = "a" }, {key = "b"}]  } -> ["a", "b"]

there's already a flattenlist operation, but no option to flatten a list of maps

the most intuitive would be this

${var.my.*.key}

however I could see arguments for

${var.my.*["key"]}
${lookup( transform(var.my), "key" )

or some other number of options

these only work for transforming from a list of maps though, it may also be useful to transform to any arbitrary structure. At the very least transforming from any rich structure, to a flattened list seems like a good idea.

apparentlymart commented 6 years ago

Hi @xenoterracide!

We're currently working on integrating into Terraform the new version of HCL, currently codenamed "HCL2" (until it's complete) which includes a few different features in this area:

The two different splat syntaxes are collectively known as the splat operators in the new language specification, in attribute-only and full variants.

In the near future there will be a version of Terraform that has this new version as an opt-in experiment to gather feedback, and then we'll roll it out as the primary parser in a future major release.

xenoterracide commented 6 years ago

is there a way now to format a list of maps? trying to generate an fstab from [{ dev = '/dev/...' mount = '/srv/..' }, ... }

I managed to figure this [{...},{...}] -> [...,...] out

data "template_file" "Mounts" {
    count = "${length(var.volumes)}"
    template = "${lookup( var.volumes[count.index], "mount")}"
}

locals {
    mounts = "${data.template_file.Mounts.*.rendered}"
    lines = "${formatlist(" - [ cloud-init-per, instance, chmod, chmod, 1777, %s ]", local.mounts )}"
}

data "template_file" "RunCmd" {
    template = "${file("cloudinit/runcmd.yml")}"
    vars {
        generated = "${join( "\n", local.lines )}"
    }
}

but now I want to generate mount lines

mounts:
 - [ ${dev}, ${mount}, 'auto', 'defaults,noexec,nosuid', '0', '0' ]

problem being that our version of cloudinit doesn't support merging correctly.

apparentlymart commented 6 years ago

We now have a few articles out there about the features I described earlier, as part of a series on what's coming in the next major release:

We are still planning to distribute a pre-release version of this as soon as its ready. While we originally hoped to include this as a feature flag in a "real" release, the complexity of supporting both implementations in a single release turned out to be prohibitive and so instead we will be releasing a larger number of pre-release versions than we'd normally do in a release cycle, starting with an "alpha" release primarily for our own testing as soon as we reach feature complete and the new features are minimally usable.

apparentlymart commented 5 years ago

Hi @xenoterracide!

As discussed over in #8439, these features are now merged in master and will be included in the forthcoming v0.12.0 final release. Therefore I'm going to close this out. Thanks for this feature request, and thanks for your patience while we laid the groundwork to implement it.

ghost commented 4 years ago

I'm going to lock this issue because it has been closed for 30 days ⏳. This helps our maintainers find and focus on the active issues.

If you have found a problem that seems similar to this, please open a new issue and complete the issue template so we can capture all the details necessary to investigate further.