let's assume i have a map like this:
variable "test_parameters" {
type = map
default = {
"A" = "subnet-73e35d3e",
"B" = "subnet-7e00d503",
"C" = "subnet-d9d446b2",
}
}
What is the terraform-code
to store the values of the map in a single aws_ssm_parameter ?
get a single value from the parameter like: B = subnet-7e00d503 or B:subnet-7e00d503 ?
Many thanks for help ;)
You can store it as json, and then get json back.
resource "aws_ssm_parameter" "foo" {
name = "myparam"
type = "String"
value = jsonencode(var.test_parameters)
}
To read it:
data "aws_ssm_parameter" "foo" {
name = "myparam"
}
# to use
locals {
myparam_values = jsondecode(data.aws_ssm_parameter.foo.value)
}
Related
This is my main file
services_list = flatten([
reverse(values(var.host_svc)) ])
}
variable "host_svc" {
type = map(map(any))
}
output "aa" {
value = local.services_list
}
This is terraform tfvars file
host_svc = {
accounts = {
name = "accounts"
pod = "3"
cpu = "512M"
memory = "1024M"
}
analytics = {
name = "analytics"
pod = "3"
cpu = "512M"
memory = "1024M"
}
}
When i am output local.services_list i ma getting whole object. i just want to fetch just name of each map object like accounts,analytics.
i have tried with list data type it works but i want to do with map ojject because i have to use different object values
You can do that much easier than you are trying:
local {
services_list = [for k, v in var.host_svc : k]
}
Or even more easy using the built-in keys function [1]:
local {
services_list = keys(var.host_svc)
}
[1] https://developer.hashicorp.com/terraform/language/functions/keys
If I understood you correctly, you want to read the names from your map. If you want to read your map keys, just use keys(map) function:
variable "host_svc" {
type = map(map(any))
default = {
accounts_k = {
name = "accounts"
pod = "3"
cpu = "512M"
memory = "1024M"
}
analytics_k = {
name = "analytics"
pod = "3"
cpu = "512M"
memory = "1024M"
}
}
}
output "aa" {
value = keys(var.host_svc)
}
Which will output:
+ aa = [
+ "accounts_k",
+ "analytics_k",
]
I used _k suffix just to differentiate between the map keys and your name key inside the internal map
In case you want to read name attribute of that map you can do:
output "aa" {
value = [for svc in local.services_list : svc.name]
}
In case you don't want to have duplicates in that outputted list, use toset():
output "aa" {
value = toset([for svc in local.services_list : svc.name])
}
I have two sets of locals defined as below:
locals {
env1 = {
a = {
}
b = {
}
}
}
locals {
env2 = {
x = {
}
y = {
}
}
}
Now, I have to run a loop for local.env1 so that loop runs for a & b. But I also need "x" from local.env2 for a resource attribute in the same resource block the loops runs.
There are 2 resource blocks and it would look something like this:
resource_block1
{
for_each = local.env1
scope = each.key
id = something["x"]
}
resource_block2
{
for_each = local.env1
scope = each.key
id = something["y"]
}
For "id" attribute in both the resource blocks I don't want to hardcode "x" or "y" respectively. I want to programmatically fill "x" and "y" for "id" attribute in the respective resource blocks.
I tried to create a map for env1 and env2 I was able to fetch "a" and "b" from local.env1 but I am unable to fetch/filter only "x" or only "y" from it.
Any ideas/solutions please? Thank you for checking.
How can I achieve the following:
I want to add map objects to a list based on whether they are passed as empty or not in the root module. So if this is passed in the variables
A = { foo = bar }
B = {}
C = { foo = bar }
then I would expect the final_list variable to be the one below
# main.tf
final_list = [{A}, {C}]
If there are alternate ways of achieving this (ie by using boolean flags), I'm ok with using those as well.
Probably you want filter usage like this:
locals {
a = {
foo = "bar"
}
b = {}
c = {
foo = "bar"
}
merge = [
for map in [local.a,local.b,local.c] :
map if map != {}
]
}
output "merge" {
value = local.merge
}
I'm trying to get multiple values out of an 'any' type variable. I'm new to terraform and open to recommendations. Specifically for this example, I'd like to know how I can output the 'bucket_name' value in my outputs.
variable "replica_config" {
type = any
default = {
role = "role_name"
rules = [
{
id = "full-s3-replication"
status = true
priority = 10
delete_marker_replication = false
destination = {
bucket = "bucket_name"
storage_class = "STANDARD"
replica_kms_key_id = "key_id"
account_id = "account_id"
replication_time = {
status = "Enabled"
minutes = 15
}
}
}
]
}
}
Current Output:
output "output4" {
value = flatten(var.replica_config["rules"])
}
Since you you have a list for rules, you can use a splat expression as such:
output "output4" {
value = var.replica_config.rules[*].destination.bucket
}
Keep in mind, the output of this expression will also be a list. If you want a single item instead of a list, you can use an index.
For example:
output "output4" {
value = var.replica_config.rules[0].destination.bucket
}
I have a nested map variable of account name and ID by OU, like:
variable "aws_accounts" {
type = map(map(any))
default = {
first_ou = {
first_account = "111111111"
second_account = "222222222"
}
second_ou = {
third_account = "333333333"
fourth_account = "444444444"
}
}
}
This is great for passing a map of account_name to account_id as a sub-variable to do things by ou and the modules in question are constructed to accept a map input.
I would like to also render a local so that I can also reference single accounts but get a map value for them without having to maintain a separate list of variables, like
local.first_account = {
first_account = "111111111"
}
local.second_account = {
second_account = "222222222"
}
local.third_account = {
third_account = "33333333"
}
etc.
I have tried various techniques but without success:
I cannot work out how to refer to each map in the array iteratively- most documentation seems to be based on lists and when I try to do a for_each I get
The "each" object can be used only in "module" or "resource" blocks, and only when the "for_each" argument is set.
Based on your example, it seems like you want to take your two-level map and turn it into a single-level map where the keys are the account names and the "OU names" are just discarded.
Here's one way to achieve that:
locals {
account_ids = merge(values(var.aws_accounts)...)
}
This first uses values to take the values from the top-level map, producing a list of maps.
It then uses merge to take all of the elements from each of the maps and combine them into a single new map. I used the ... symbol to tell Terraform that it should treat each element of the list as a separate argument to merge, rather than just passing the whole list as a single argument.
After merging these together you could potentially split them apart again, creating a separate map each, using a for expression.
locals {
account_maps = tomap({
for k, id in local.account_ids :
k => { (k) = id }
})
}
Maybe not exactly what you're looking for, but could be helpful:
locals {
accounts = merge(var.aws_accounts["first_ou"], var.aws_accounts["second_ou"])
}
If you need to do this in a more dynamic way:
locals {
accounts = zipmap(
flatten([for item in var.aws_accounts : keys(item)]),
flatten([for item in var.aws_accounts : values(item)])
)
}
Now you can access each account with local.accounts["first_account"] etc.
OK So with help from Martin Atkins and Bryan Heden I have found an answer to this. It isn't exactly pretty but it does work:
variable "aws_accounts" {
type = map(map(any))
default = {
first_ou = {
first_account = "111111111"
second_account = "222222222"
}
second_ou = {
third_account = "333333333"
fourth_account = "444444444"
}
}
}
locals {
# gives single map from nested map
account_ids = merge(values(var.aws_accounts)...)
# gives separate structured map for each key
single_accounts_maps = {
for account, id in local.account_ids :
account => {
account = account
id = id
}
}
# gives map where values = keys plus values
single_accounts_maps_joined = zipmap(
flatten([for item in var.aws_accounts : keys(item)]),
[for item in local.single_accounts_maps :
join(" = ", values(item))]
)
# gives nested map by key = {key = "value"}
single_accounts_maps_keys_values = {
for item in local.single_accounts_maps_joined :
(split(" = ", item)[0]) => {
(split(" = ", item)[0]) = (split(" = ", item)[1])
}
}
}
Output that I wanted:
terraform console
> local.single_accounts_maps_keys_values
{
"first_account" = {
"first_account" = "111111111"
}
"fourth_account" = {
"fourth_account" = "444444444"
}
"second_account" = {
"second_account" = "222222222"
}
"third_account" = {
"third_account" = "333333333"
}
}
After the discussion with Martin Atkins and his subsequent edits below, I am recommending his answer instead as simpler, more legible and more graceful, although the tomap() nesting appears to be unneeded, i.e. do
locals {
account_ids = merge(values(var.aws_accounts)...)
account_maps = {
for k, id in local.account_ids :
k => { (k) = id }
}
}