Splitting a comma separated string - azure

I have an output that is a multi-valued, comma separated string.
input.tf
resource "azurerm_app_service" "testap" {
name = "MySuperCoolAppServer001"
location = "eastus"
resource_group_name = "notshown"
app_service_plan_id = "notshown"
}
output.tf
output "output_tf_testap_outbound_ip_addresses" {
value = "${azurerm_app_service.testap.outbound_ip_addresses}"
}
And I get this in the console:
output_tf_testap_outbound_ip_addresses =
1.2.3.4,1.2.3.5,1.2.3.6,1.2.3.7,1.2.3.8,1.2.3.9
How do I get the first item of the list? In this case, I'm trying to isolate the value:
1.2.3.4
Is there a way to get a "collection" of all the items when the total number of items is not known before run time? (The list above has 6 items).
The following code doesn't seem to work:
output "first_ip" {
value = ["${azurerm_app_service.testap.outbound_ip_addresses[0]}"]
}
===================== APPEND =================
first_ip_no_index works. first_ip does not
output "first_ip_no_index" {
value = ["${split(",", azurerm_app_service.tf_middle_tier_azurerm_app_service.outbound_ip_addresses)}"]
}
output "first_ip" {
value = "${split(",", azurerm_app_service.tf_middle_tier_azurerm_app_service.outbound_ip_addresses)[0]}"
}
first_ip generated this error:
Error reading config for output first_ip: parse error at 1:91:
expected "}" but found "["

You can use the split() function to split a string into a list.
output "output_tf_testap_outbound_ip_addresses" {
value = ["${split(",", azurerm_app_service.testap.outbound_ip_addresses)}"]
}
After that you can then index it by using the element(list, index) syntax:
output "first_ip" {
value = "${element(split(",", azurerm_app_service.testap.outbound_ip_addresses), 0}"
}
You should also normally be able to use the list\[index\] syntax like this:
output "first_ip" {
value = "${split(",", azurerm_app_service.testap.outbound_ip_addresses)[0]}"
}
However there seems to be a bug in Terraform 0.11 that prevents slicing the result of the split function, throwing the following error:
Error: Error loading /tmp/tf-split-test/main.tf: Error reading config
for output foo: parse error at 1:25: expected "}" but found "["
You could use a local to split the list and then slice that to get around this if you'd prefer to use this syntax over the element function.
locals {
outbound_ip_addresses_list = "${split(",", azurerm_app_service.testap.outbound_ip_addresses)}"
}
output "first_ip" {
value = "${local.outbound_ip_addresses_list[0]}"
}

Related

Terraform use Variable from random function

I´m a beginner in Terraform.
I like to know, how can I use a variable which was generated in a random function in the same .tr script and use it like below for a different input. I´m also not sure, if the random stuff is working correctly? Can someone help me? But how to pass the varibale?
for example
locals {
dslist = [
"Datastore1",
"Datastore2",
"Datastore3"
]
}
resource "random_shuffle" "random_dslist" {
input = local.dslist
result_count = 1
}
output "random_dslist" {
value = random_shuffle.random_dslist.result
}
data "vsphere_datastore" "datastore" {
name = "${var.random_dslist}" # -> how can I pass the generated random datastore in here?
datacenter_id = "${data.vsphere_datacenter.dc.id}"
}
You can use the value of the resource just like you already used it for the output:
Only difference here is that, according to the documentation random_shuffle.result gives you a list, since you can get more than one random result. Therefore, just take the first result [0], because you know that you expect only one item in the list.
resource "random_shuffle" "random_dslist" {
input = local.dslist
result_count = 1
}
data "vsphere_datastore" "datastore" {
name = random_shuffle.random_dslist.result[0]
datacenter_id = data.vsphere_datacenter.dc.id
}

How to access a local using a variable in Terraform

I have the following code.
mymodule
variable "senses" {
type = string
}
locals {
sounds = {
"cat" = "meow"
"dog" = ["bark", "woof"]
}
}
output "noise" {
value = local[var.senses]["cat"]
}
call mymodule
module "mymodule" {
source = "../../../modules/mymodule"
senses = "sound"
}
returns error:
Error: Invalid reference
on ../../../modules/mymodule/outputs.tf line 62, in output "noise":
62: value = local[var.senses]["cat"]
The "local" object cannot be accessed directly. Instead, access one of its
attributes.
my code can't seem to handle
value = local[var.senses]["cat"]
Any suggestions on how i can get this to work?
I don't believe it's possible to use a variable to switch which local you're reading. I.e. local[var.senses] is the root of the issue.
If you refactor slightly and put your values inside a single, known, value--such as local.senses it should then let you do a key lookup within that value.
So, if you modify your locals to place your values in a senses key:
locals {
senses = {
"sounds" = {
"cat" = "meow"
"dog" = ["bark", "woof"]
}
}
}
and update your lookup to use that field:
value = local.senses[var.senses]["cat"]
Then I believe it will work, since your are doing a key lookup against a specific local rather than trying to dynamically select the local.

how can i iterate from a list to output value?

I m getting from terraform 12, call a list of values
data "oci_core_instances" "test_instances" {
#Required
compartment_id = "${var.compartment_ocid}"
availability_domain = "${data.oci_identity_availability_domains.ads.availability_domains[0].name}"
}
// numInstances = 3 for my case
locals {
numInstances = length(data.oci_core_instances.test_instances.instances)
}
and i want to iterate like (pseudo code) :
# Output the result single element
output "format_instances_name_state" {
value = "${
for (i=0 ; i< 3; i++)
format("%s=>%s",data.oci_core_instances.test_instances.instances[i].display_name,data.oci_core_instances.test_instances.instances[i].state)
} "
}
how can i do this in terraform ?
i have tried this :
# Output the result single element
output "format_instances_name_state" {
value = "${
for i in local.numInstances :
format("%s=>%s",data.oci_core_instances.test_instances.instances[i].display_name,data.oci_core_instances.test_instances.instances[i].state)
} "
}
but i m getting this error:
Error: Extra characters after interpolation expression
on main.tf line 64, in output "format_instances_state_element_single":
63:
64: for i in local.numInstances :
Expected a closing brace to end the interpolation expression, but found extra
characters.
any ideas ?
It seems like what you really want here is a map from display name to state, in which case the following expression would produce that:
output "instance_states" {
value = {
for inst in data.oci_core_instances.test_instances.instances : inst.display_name => inst.state
}
}
If you really do need that list of strings with => inside for some reason, you can adapt the above to get it, like this:
output "format_instances_state_element_single" {
value = [
for inst in data.oci_core_instances.test_instances.instances : "${inst.display_name}=>${inst.state}"
]
}
In this second case the for expression is marked by [ ] brackets instead of { } braces, which means it will produce a list result rather than a map result.

flattening output contents of a composite map

I have two module that output respectively
output "discovery_service_hostname" {
value = "${aws_appmesh_virtual_service.service.name}"
}
and
output "discovery_service_arn" {
value = zipmap( aws_service_discovery_service.sd[*].name, aws_service_discovery_service.sd[*].arn)
}
Both are used in the main script that outputs
output "services" {
value = {
"web" = "${module.web.discovery_service_hostname}"
"wwb-backend" = "${module.web_backend.discovery_service_hostname}"
"wwb-backend-n" = "${module.web_backend_n.discovery_service_hostname}"
}
}
in this case I used the 1st module for web andweb-backend, while I used the 2nd module for web-backend-n
I need to access the service arn via lookup function in a 3rd script, but I would avoid duplicating the whole code to handle the two cases
final output like this
discovery_service = {
"web" = "arn:xxx1"
"web-backend" = "arn:xxx2"
"web-backend-n" = {
"web-backend-n-1" = "arn:xxx3"
"web-backend-n-2" = "arn:xxx4
"web-backend-n-3" = "arn:xxx5"
}
Is there a way to have an output like
discovery_service = {
"web" = "arn:xxx1"
"web-backend" = "arn:xxx2"
"web-backend-n-1" = "arn:xxx3"
"web-backend-n-2" = "arn:xxx4
"web-backend-n-3" = "arn:xxx5"
}
thanks!
I will answer my own question. Solution is to always output a map (even from the module with single outputs) like this:
output "discovery_service_arn" {
value = zipmap( [ aws_service_discovery_service.sd.name ], [ aws_service_discovery_service.sd.arn ])
}
and
output "discovery_service_arn" {
value = zipmap( aws_service_discovery_service.sd[*].name, aws_service_discovery_service.sd[*].arn)
}
then in the final script use merge to get a single map like
output "discovery_service" {
value = merge(
module.web.discovery_service_arn,
module.web_backend.discovery_service_arn,
module.web_backend_n.discovery_service_arn
)
}

Construct list of maps from a csv in terraform

I have the following variable
variable "whitelisted_ips" {
default = "xx.xxx.xx.x/21,xxx.xx.xxx.x/20"
}
I use this some places where a list of CIDRS is needed using the following
cidr_blocks = ["${split(",", var.whitelisted_ips)}"]
That all works fine.
I want to reuse these values and end up with the following structure (expressed as JSON to give you an idea)
waf_ips = [
{ value = "xx.xxx.xx.x/21", type="IPV4"},
{ value = "xxx.xx.xxx.x/20", type="IPV4"},
]
So I am looking to create a list of maps from the string (the IPV4 is hardcoded and repeats on every line).
If I feed my current JSON to an aws_waf_rule and treat it as a list it succeeds, but I'd rather not repeat the data in the tfvars file as its the same and I'd like to reuse that string separated list.
Ok so having learned more and read more it turns out you can do this with a null resource for static data so.
locals {
cidr_blocks = ["xxx.xxx.xxx/23", "xxx.xxx.xxx/23", "xxx.xxx.xxx/23"]
}
resource "null_resource" "cidr_map_to_protocol" {
count = "${length(local.cidr_blocks)}"
triggers = {
value = "${element(local.cidr_blocks, count.index)}"
type = "IPV4"
}
}
output "mapped_cidr_to_protocol" {
value = "${null_resource.cidr_map_to_protocol.*.triggers}"
}
this will not work for a computed resource unfortunately.

Resources