Terraform - Multiple maps with lists [closed] - terraform

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 26 days ago.
Improve this question
I struggle to loop through my data structure. If anyone have any feedback regarding my data structure, this is highly desirable
Data structure
locals = {
values = {
key1 = ["a", "b"],
key2 = ["c", "d"]
}
}
What I've tried
value = { for key, value in local.values : key => values }
This basically prints out local.array as is. I know I should have the ability to loop through the value given in the expression above, but I'm not able to do so.
Desired output
# Following does NOT work
value = { for key, values in local.values : key =>
for v in values : key => v}
Key1: a
Key1: b
Key2: c
Key2: d

A map must have unique keys, you cannot use the same key twice. you could vor example make a map of the values to keys like.
locals {
values = {
key1 = ["a", "b"],
key2 = ["c", "d"]
}
}
output "vals" {
value = merge([for key, values in local.values: { for value in values: value => key}]...)
}
output
Outputs:
vals = {
"a" = "key1"
"b" = "key1"
"c" = "key2"
"d" = "key2"
}
Based on your comment you could essentially convert it to a list of maps where each map has a single map element that you could iterate over
locals {
values = {
key1 = ["a", "b"],
key2 = ["c", "d"]
}
}
output "vals" {
value = concat([for key, values in local.values: [for value in values: {(key) = value}]]...)
}
OUTPUT
Outputs:
vals = [
{
"key1" = "a"
},
{
"key1" = "b"
},
{
"key2" = "c"
},
{
"key2" = "d"
},
]

Related

How to remove values from a map in Terraform that match a list of keys?

I want to remove values from a map in Terraform that match a list of keys e.g. remove keys_b and keys_c from the map below.
Input
map = {
key_a = value_a,
key_b = value_b,
key_c = value_c
...
key_m = value_m
}
Desired Output
filtered_map = {
key_a = value_a,
...
key_m = value_m
}
I've tried using the contains function but that passes through only one value and not a list of values. I am not sure how to loop over this either.
output "test" {
value = { for k, v in var.map: k => v if ! contains(values(v), var.exclude) }
}
You were almost there. You had wrong arguments in contains. It should be:
output "test" {
value = { for k, v in var.map: k => v if contains(var.exclude, k) }
}

How to convert list to map in terraform?

string vals=var.vals // which will contain string in the format below
//"hr:recruitment,department:human,tool:sap,fruit:apple"
labels={
hostname=var.hostname
monitored=var.monitored
customer=var.cust1
machine-type=var.machinetype
}
I need to set labels(key,value) pairs for google_compute_instance by combining the above 2 properties to form a map.
So i converted vals to list by this code split(",",var.vals)
This gives me a list
tolist([
"hr:recruitment",
"department:human",
"tool:sap",
"fruit:apple",
])
Expected Output consisting of only map(string) combining labels and vals
labels:
{
hostname:var.hostname
monitored:var.monitored
customer:var.cust1
machine-type:var.machinetype
hr:"recruitment",
department:"human",
tool:"sap",
fruit:"apple"
}
How to convert this list to a map and combine it with labels?
I tried below & it seems to be working but it heavily relies on data quality of vals string (shouldn't contain duplicate keys). At it's core it relies on zipmap to build the map from keys & values lists.
// Having vals as a string variable
variable "vals" {
description = "The name of availability set"
type = string
default = "hr:recruitment,department:human,tool:sap,fruit:apple"
}
// hostname, monitored, cust1 & machinetype vars
variable "hostname" {
type = string
default = "dummy.net"
}
variable "monitored" {
type = bool
default = true
}
variable "cust1" {
type = string
default = "xyz"
}
variable "machinetype" {
type = string
default = "linux"
}
locals {
// parsing locally to split the vals string to fetch the keys
keys = [
for s in split(",", var.vals) : split(":", s)[0]
]
// parsing locally to split the vals string to fetch the values
values = [
for s in split(",", var.vals) : split(":", s)[1]
]
//I used labels also as vars
labels = {
hostname = var.hostname
monitored = var.monitored
customer = var.cust1
machine-type = var.machinetype
}
}
// Finally, zipmap to construct map from keys & values & merge with local.labels
output "final_map" {
value = merge(local.labels, zipmap(local.keys, local.values))
}
Finally, the output looks like below ::
Apply complete! Resources: 0 added, 0 changed, 0 destroyed.
Outputs:
final_map = {
"customer" = "xyz"
"department" = "human"
"fruit" = "apple"
"hostname" = "dummy.net"
"hr" = "recruitment"
"machine-type" = "linux"
"monitored" = true
"tool" = "sap"
}

Lookup function on nested locals variable

Using the lookup function, how could I lookup the value of c?
lookup({a="ay", b={c="ce"}}, "c", "what?")
"what?"
If your goal is to produce the value "what?" if either b or b.c are absent from the data structure then you can achieve that concisely using the try function:
> try({ a = "ay", b = { c = "ce" } }.b.c, "what?")
"ce"
> try({ a = "ay", b = {} }.b.c, "what?")
"what?"
> try({ a = "ay" }.b.c, "what?")
"what?"
Hope this helps:
locals {
# NOTE: lookup(map, key, default)
value_out = lookup({a="ay", b={c="ce"}}, "b", "what?")
value_out_c = local.value_out.c
}
output "value_returned_c" {
value = local.value_out_c
}
I tried this with terraform version v1.0.0. Not sure whether it solves your problem?
lookup(lookup({a="ay", b={c="ce"}}, "b", "what?"),"c", "what")

String Permutations of Different Lengths

I have been trying to wrap my head around something and can't seem to find an answer. I know how to get all the permutations of a string as it is fairly easy. What I want to try and do is get all the permutations of the string in different sizes. For example:
Given "ABCD" and a lower limit of 3 chars I would want to get back ABC, ABD, ACB, ACD, ADB, ADC, ... , ABCD, ACBD, ADBC, .. etc.
I'm not quite sure how to accomplish that. I have it in my head that it is something that could be very complicated or very simple. Any help pointing me in a direction is appreciated. Thanks.
If you've already got the full-length permutations, you can drop stuff off of the front or back, and insert the result into a set.
XCTAssertEqual(
Permutations(["A", "B", "C"]).reduce( into: Set() ) { set, permutation in
permutation.indices.forEach {
set.insert( permutation.dropLast($0) )
}
},
[ ["A", "B", "C"],
["A", "C", "B"],
["B", "C", "A"],
["B", "A", "C"],
["C", "A", "B"],
["C", "B", "A"],
["B", "C"],
["C", "B"],
["C", "A"],
["A", "C"],
["A", "B"],
["B", "A"],
["A"],
["B"],
["C"]
]
)
public struct Permutations<Sequence: Swift.Sequence>: Swift.Sequence, IteratorProtocol {
public typealias Array = [Sequence.Element]
private let array: Array
private var iteration = 0
public init(_ sequence: Sequence) {
array = Array(sequence)
}
public mutating func next() -> Array? {
guard iteration < array.count.factorial!
else { return nil }
defer { iteration += 1 }
return array.indices.reduce(into: array) { permutation, index in
let shift =
iteration / (array.count - 1 - index).factorial!
% (array.count - index)
permutation.replaceSubrange(
index...,
with: permutation.dropFirst(index).shifted(by: shift)
)
}
}
}
public extension Collection where SubSequence: RangeReplaceableCollection {
func shifted(by shift: Int) -> SubSequence {
let drops =
shift > 0
? (shift, count - shift)
: (count + shift, -shift)
return dropFirst(drops.0) + dropLast(drops.1)
}
}
public extension BinaryInteger where Stride: SignedInteger {
/// - Note: `nil` for negative numbers
var factorial: Self? {
switch self {
case ..<0:
return nil
case 0...1:
return 1
default:
return (2...self).reduce(1, *)
}
}
}

changing map values in groovy doesn't work

I am using Groovy version 2.1.0. I am trying to read values from a map and update another map.
a = ["key1":"" ,"key2":""]
b = ["key1": "10", "key3":"99" ]
for (i in b){
if( i.key in a)
a.(i.key) = i.value
}
def key2 = "key2"
a.key2 = "value2"
println a.get("key2")
println "value returned is :" + a.get("key1") + ":"
This results in o/p
value2
value returned is ::
But if the map 'a' doesn't contain empty string as values, then it works fine as expected.
a = ["key1":"7" ,"key2":""]
b = ["key1": "10", "key3":"99" ]
for (i in b){
if( i.key in a)
a.(i.key) = i.value
}
a."key2" = "value2"
println a.get("key2")
println "value returned is :" + a.get("key1") + ":"
This results in o/p
value2
value returned is :10:
I want to update the empty map with values, like in the first scenario. Where am I getting it wrong.
Thanks in advance.
You need to change:
if( i.key in a)
a.(i.key) = i.value
To:
if( i.key in a.keySet())
a.(i.key) = i.value
As Opal says, it's the if that's causing difficulties...
if( i.key in a)
Will fail if the key is not in the map, OR the value equates to Groovy False
You could do:
a = ["key1":"" ,"key2":""]
b = ["key1": "10", "key3":"99" ]
a = (a+b).findAll { k, v -> k in a.keySet() }
def key2 = "key2"
a[ key2 ] = "value2"
println a.key2
println "value returned is : $a.key1 :"
(be careful, your key2 bit wasn't doing what I believe you expected (it worked as your key2 var name was the same as its value)

Resources