Thanks for the clarification, @nc237!
Based on your latest comment I expect that you need a StringList
parameter rather than String
parameter, so I’m going to write it that way. That detail is not super important to this example so hopefully you can adjust that part to be a different way if you need to.
Otherwise, I think we can break this down into a few different steps. The first one you seem to already have solved, which is to retrieve the IDs of AMIs matching your given name pattern:
data "aws_ami_ids" "this" {
provider = aws.source
for_each = var.ami_map
sort_ascending = true
owners = [var.owner_id]
filter {
name = "name"
values = [each.value] # regexp
}
filter {
name = "virtualization-type"
values = ["hvm"]
}
}
This is the same as what you already provided. I’m not an expert on this particular data source so I’m not sure if there’s some limit on the number of items it can possibly return so that it won’t get gradually slower over time as you add more AMIs. The main assumption here though is that if it does have a limit then that limit is greater than three, so we’ll always get at least enough information to deal with the next step.
The aws_ami_ids
data source has sort_ascending = true
and so I assume that means that the first three items in its result will be the most recent three, and so the next step is to truncate these lists to at most three items:
locals {
amis = tomap({
for k, q in data.aws_ami_ids.this : k => chunklist(q.ids, 3)[0]
})
}
This expression has a few tricky parts to it, so I’ll break it down into smaller pieces:
-
The { for ... in ... : ... }
part is a for
expression which constructs one data structure from the elements of another. In this case, the source collection is the map of instances of data.aws_ami_ids.this
, and so k
is the instance key (always matching a key from var.ami_map
) and q
– short for “query” – is the object representing the corresponding instance of the data resource.
Terraform evaluates the expressions on the right hand side of the colon for each element of data.aws_ami_ids.this
, so the result has the same number of elements as the input.
-
The chunklist
function here is a bit cheeky: it’s asking Terraform to split the given list of IDs into chunks of at most three elements, and then taking only the first chunk and discarding the rest.
I did it this way because chunklist
automatically handles the case where there are fewer than three elements in the list, whereas it would be more finicky to handle that with other approaches. However, in case that seems “too clever” here’s another expression that is more verbose but perhaps clearer about what it’s doing:
slice(q.ids, 0, min(length(q.ids), 3))
-
Finally, the surrounding tomap
is optional but I like to include this to be explicit that I’m intending this result to be used as a map rather than as an object. A { for ... }
expression generates an object by default because it’s the more general kind, but object types in Terraform typically represent a fixed set of attributes whereas a map represents an arbitrary set of keys decided dynamically.
local.amis
should therefore be a map from each of the keys in your initial var.ami_map
to a list of at most three AMI ids.
The final step is to write these in to SSM using aws_ssm_parameter
. The documentation for that resource type is unclear on how exactly you’re supposed to submit a StringList
, but I’m guessing from the corresponding CLI documentation that the provider is expecting value
to be a string containing comma-separated values, and so I’ve written the following under that assumption:
resource "aws_ssm_parameter" "this" {
provider = aws.destination
for_each = local.amis
type = "StringList"
name = "/dummy/ami/${each.key}/ami_id"
value = join(",", each.value)
}
The local.amis
value is a map with one element per SSM parameter you want to create, so it’s suitable for direct use in for_each
without any further transformation. The only remaining complications then are to interpolate each.key
into the name
and to transform the list of separate ID strings from each.value
into a single string with commas separating the items.
I don’t have active AWS credentials at the moment so I’ve just written this out directly into the comment box without testing it, and so I’m sure I’ve made at least one typo somewhere. If you try this and see any errors that you aren’t sure how to resolve, please let me know and I’ll try to correct myself!