unable to use sum in terraform - terraform

I'm facing issues while using sum in terraform
my local variable is as follows :
> local.total_output
[
"150",
"150",
"150",
]
> sum(local.total_output)
> Error: Invalid function argument
on <console-input> line 1:
(source code not available)
|----------------
| local.total_output is tuple with 3 elements
Invalid value for "list" parameter: argument must be list, set, or tuple of
number values.
>
Am I doing something wrong here?

As the error says, values in the list should be type of number. You can convert them with the for loop:
sum([for str in local.total_output: tonumber(str)])
Since total_output is a local, probably would be easier just declare it as a list of numbers (no quotes):
locals {
total_output = [150, 150, 150]
}

Your total_output is a list of strings. It should be list of numbers:
[
150,
150,
150,
]

Related

Initialise a list element referring to an earlier element from the same list

Given the list
l = [ "ALPHA ONE", 123, _( "Alpha One" ), _( "ALPHA ONE" ) ]
where elements 2 and 3 (the translated text) are both tied directly to element 0.
Is it possible to define the list in which elements 2 and 3 dynamically refer to element 0? Is there a notation/mechanism for a list element to be initialised by referring to an earlier element?
For example, something along the lines of
l = [ "ALPHA ONE", 123, _( [ 0 ].title() ), _( [ 0 ].upper() ) ]
This would make life easier/safer as I don't want to have to define essentially the text over and over.
From Python 3.8 this is possible using assignment expressions (the walrus operator). Assign the first element to a name using the walrus operator and then reuse this variable in the other elements
l = [(x := "ALPHA ONE"), 123, _(x.title()), _(x.upper())]
Is there a reason you need to put it in a list literal? Also, this seems more like a tuple.
t = "ALPHA ONE"
l = (t, 123, _(t.title()), _(t.upper()))

length of keys in a map in Terraform - odd output

Given:
variable "foo" {
type = map
default = {
lorem = "ipsum"
dolor = "sit"
}
}
then, in Terraform console, why does
[for k, v in var.foo : length(k) ]
give:
[
4,
5,
]
That's a really odd result. When I run the exact same thing locally, I get the expected result:
> [for k, v in var.foo : length(k) ]
[
5,
5,
]
Do you have a value set for "foo" in a *.auto.tfvars file somewhere? How about an environment variable called TF_VAR_foo? My best guess is that there is a different variable defined somewhere called "foo" that is overwriting the default value specified in the variable declaration.

input dynamic nested list into terraform setproduct() function

Problem:
I have a dynamic nested list that I want to input into the terraform setproduct() function. I can't pass the nested list directly to the setproduct() function nor use a for loop to iterate through the nested list within the setproduct() function (see attempts section). The setproduct() function works only when I explicitly define 2 or more single-level lists arguments (see expected output section).
Input: (the sublists are dynamically created which means the sublist index range varies)
locals {
foo = [
[
{"honda" = "passport"},
{"honda" = "civic"}
],
[
{"toyota" = "prius"}
]
]
}
Expected Output:
bar = [
[
{"honda" = "passport"},
{"toyota" = "prius"}
],
[
{"honda" = "civic"},
{"toyota" = "prius"}
]
]
The expected output can be created using the output block below. Although as stated in the problem section, the local.foo nested list has a dynamic 2nd level index range. So explicitly defining the [0] and [1] indice isn't a viable solution.
output "bar" {
value = setproduct(local.foo[0], local.foo[1])
}
Attempts:
#1
output "bar" {
value = setproduct(local.foo)
}
Output error:
on test.tf line 35, in output "attempts":
35: value = setproduct(local.foo)
|----------------
| local.foo is tuple with 2 elements
Call to function "setproduct" failed: at least two arguments are required.
#2
output "bar" {
value = setproduct(local.foo[*])
}
Output error:
on test.tf line 35, in output "attempts":
35: value = setproduct(local.foo[*])
|----------------
| local.foo is tuple with 2 elements
Call to function "setproduct" failed: at least two arguments are required.
I think you are after Expanding Function Arguments:
output "bar" {
value = setproduct(local.foo...)
}

How to iterate a list up to certain element/index in terraform?

This is simple in other language by using for or do while statement. Being a novice, I still can't figure out to do it in Terraform.
The real case that I need to do is to build a connection string to mongoDB replica-set service. The replication_factor is 3, 5 or 7 which means I need to create a list of 2, 4, or 6 hostnames/addresses.
I come up with the following code sofar:
locals {
uri_list = [
"#${alicloud_mongodb_instance.tyk_mongodb-test.id}1.mongodb.${var.region}.rds.aliyuncs.com:${var.db_port}",
"#${alicloud_mongodb_instance.tyk_mongodb-test.id}2.mongodb.${var.region}.rds.aliyuncs.com:${var.db_port}",
"#${alicloud_mongodb_instance.tyk_mongodb-test.id}3.mongodb.${var.region}.rds.aliyuncs.com:${var.db_port}",
"#${alicloud_mongodb_instance.tyk_mongodb-test.id}4.mongodb.${var.region}.rds.aliyuncs.com:${var.db_port}",
"#${alicloud_mongodb_instance.tyk_mongodb-test.id}5.mongodb.${var.region}.rds.aliyuncs.com:${var.db_port}",
"#${alicloud_mongodb_instance.tyk_mongodb-test.id}6.mongodb.${var.region}.rds.aliyuncs.com:${var.db_port}"
]
uri_list_out = [
for uriname in local.uri_list :
lower(uriname)
if substr(uriname,length("${alicloud_mongodb_instance.tyk_mongodb-test.id}") + 1, 1) < var.mongos_config["${var.environment}"]["replication_factor"]
]
}
What I expect from
output "uri_list_out" {
value = local.uri_list_out
}
is the first two elements of uri_list but instead I got only [1,2] for replication_factor = 3. Seems like if instruction in for also modify the output ???
I appreciate any hints to solve this problem.
Hendro
I believe what you really need is the slice(list, startindex, endindex) function:
uri_list_out = [
for uri in slice(local.uri_list, 0, var.mongos_config[var.environment]["replication_factor"] - 1) :
replace(uri, "/^#/", "") # Remove the leading '#'
]
The docs for the slice function
> slice(["a", "b", "c", "d"], 1, 3)
[
"b",
"c",
]

Python convert string to variable name

Im aware that this may come up as a duplicate but so far I haven't found (or should that be understood) an answer to what Im looking for.
I have a list of strings and want to convert each one into a variable name which I then assign something to. I understand that I may need a dict for this but I am unfamiliar with them as I am relatively new to python and all the examples I have seen so far deal with values whilst I'm trying something different.
Im after something like:
list = ['spam', 'eggs', 'ham']
for i in range(len(list)):
list[i] = rat.readColumn(ratDataset, list[i])
where the first list[i] is a variable name and not a string. The second list[i] is a string (and for context is the name of a column Im reading from a raster attribute table (rat))
Essentially I want each string within the list to be set as a variable name.
The idea behind this is that I can create a loop without having to write out the line for each variable I want, with matching rat column name (the string). Maybe there is a beer way of doing this than I am suggesting?
Try the following:
lst = ['spam', 'eggs', 'ham']
d = {} # empty dictionary
for name in lst:
d[name] = rat.readColumn(ratDataset, name)
Do not use list for your identifiers as it is a type identifier and you would mask its existence. The for loop can iterate directly for the elements inside -- no need to construct index and use it aganist the list. The d['spam'] will be one of your variables.
Although, it is also possible to create the real variable names like spam, eggs, ham, you would not probably do that as the effect would be useless.
Here comes a simple dictionary use :
variables = ['spam', 'eggs', 'ham']
data = {}
datum = 0
for variable in variables:
data[variable] = datum
datum+=1
print(data)
print("value : ",data[variables[2]])
It gives as result :
{'eggs': 1, 'ham': 2, 'spam': 0}
value : 2
NB : don't use list as a variable name, list is a type identifier that you can use to transform an object into a list if possible (list("abc")==['a', 'b', 'c']) and you are overriding it with your value list right now.
one way is setting the variable name as a string and changing a part or all of it via format() method and then using the string as a varibale via vars()[STRING]
import numpy as np
X1= np.arange(1,10)
y1=[i**2 for i in X1]
X2= np.arange(-5,5)
y2=[i**2 for i in X2]
for i in range(1,3):
X = 'X{}'.format(i)
y = 'y{}'.format(i)
print('X_{}'.format(i) , vars()[X])
print('y_{}'.format(i) , vars()[y])
Output:
X_1 [1 2 3 4 5 6 7 8 9]
y_1 [1, 4, 9, 16, 25, 36, 49, 64, 81]
X_2 [-5 -4 -3 -2 -1 0 1 2 3 4]
y_2 [25, 16, 9, 4, 1, 0, 1, 4, 9, 16]

Resources