handling csv cell line breaks - terraform

locals {
dns_data = <<-CSV
RecordType,RecordName,RecordZone,RecordZoneId,RecordValue
A,something.example.com,something,zoneid,"x.x.x.x \n x.x.x.x"
CSV
dns_records = csvdecode(local.dns_data)
}
resource "aws_route53_record" "route53_entry" {
for_each = {for record in local.dns_records : record.RecordName => record}
name = each.value.RecordName
type = each.value.RecordType
zone_id = each.value.RecordZoneId
ttl = 60
records = [each.value.RecordValue]
}
I'm trying to create the r53 entries inside a zone using a CSV. How to handle the line breaks inside a cell? My A record cord can have multiple values, tried multiple ways with no luck. Thanks for any help.

Related

Terraform - Add a specific description for each group

I need to put a specific description of a csv file to each group I created.
On my csv, I have 2 columns: 1 for the group name and another for the description.
locals {
Right_Groups = [for x in csvdecode(file("${path.module}/_RightGroups.csv")) : x.droits_groups]
}
I create each group with :
resource "azuread_group" "Terra-Aad-Group-Right" {
for_each = toset(local.Right_Groups)
display_name = lower(each.value)
security_enabled = true
description = each.value
}
With this, the description is equal to the group name.
If I set "each.value.description" to "description", it doesn't work.
The csv is like this :
droits_groups,description
con-inf-dev01,dev01
con-axw-rec01,rec01
Anyone have an idea ?
Thank you.
I would suggest creating a map instead of list which you are converting to a set. This is because of the fact that sets will have the same keys and values [1]:
each.value — The map value corresponding to this instance. (If a set was provided, this is the same as each.key).
To convert the data to a map you could try:
Right_Groups = {for x in csvdecode(file("${path.module}/_RightGroups.csv")) : x.droits_groups => x.description}
This will create the following map:
> local.Right_Groups
{
"con-axw-rec01" = "rec01"
"con-inf-dev01" = "dev01"
}
Then, in the resource you would do:
resource "azuread_group" "Terra-Aad-Group-Right" {
for_each = local.Right_Groups
display_name = lower(each.key)
security_enabled = true
description = each.value
}
[1] https://www.terraform.io/language/meta-arguments/for_each#the-each-object

Iterate through a conditional for_each map of strings

Trying to put something together to get passed a limitation of the tfe plugin.
I have 200+ workspaces that I manage with a variable in Terraform Cloud that I need to update. All workspaces that I need to update start with "dev-workspace" in this case.
I have a data block with the following:
data "tfe_workspace_ids" "all" {
names = ["*"]
organization = "myorganization"
}
I can't do a wildcard search for these workspaces due to a limitation of the module. This data block returns a map of strings that include all of my workspaces:
aa = {
"dev-workspace-1" = "ws-anonymized"
"dev-workspace-2" = "ws-ws-anonymized"
"dev-workspace-3" = "ws-ws-anonymized"
"test-workspace-1" = "ws-ws-anonymized"
"prod-workspace-1" = "ws-ws-anonymized"
}
My problem is that I need to take this map of strings and filter it down to just return the ones that have "dev-workspace" in the key. I've tried something like the following:
resource "tfe_variable" "dev-workspace" {
for_each = contains(data.tfe_workspace_ids.all.ids, "dev-workspace")
key = "access_key"
value = "XXXX"
category = "terraform"
workspace_id = each.value
sensitive = true
description = "AWS IAM secret access key."
}
But it doesn't look like you can use contains in this manner with for_each:
Error: Error in function call
on main.tf line 16, in resource "tfe_variable" "dev-workspace":
16: for_each = contains(data.tfe_workspace_ids.all.ids, "dev-workspace")
|----------------
| data.tfe_workspace_ids.all.ids is map of string with 284 elements
Call to function "contains" failed: argument must be list, tuple, or set.
I'm not really sure what to do here, but have tried this several ways and can't figure it out. Thanks for any help.
If you want to filter, your resource could be (you have to change var.aa to the value of data.tfe_workspace_ids which produces the input map):
variable "aa" {
default = {
"dev-workspace-1" = "ws-anonymized"
"dev-workspace-2" = "ws-ws-anonymized"
"dev-workspace-3" = "ws-ws-anonymized"
"test-workspace-1" = "ws-ws-anonymized"
"prod-workspace-1" = "ws-ws-anonymized"
}
}
resource "tfe_variable" "dev-workspace" {
for_each = {for k, v in var.aa:
k => v if length(regexall("dev-workspace", k)) > 0}
key = "access_key"
value = "XXXX"
category = "terraform"
workspace_id = each.value
sensitive = true
description = "AWS IAM secret access key."
}

Creating a record list from a terraform resource

In Terraform, I'm trying to create a DNS SRV record from created DNS A records. I would like to populate the records with the names from the aws_route53_record.etcd names, but running into errors when referencing the resource names.
Is there an easy way to achieve this?
# This resource works without errors
resource "aws_route53_record" "etcd" {
count = length(var.control_plane_private_ips)
zone_id = data.aws_route53_zone.test.zone_id
name = "etcd-${count.index}.${data.aws_route53_zone.test.name}"
type = "A"
ttl = 60
records = var.control_plane_private_ips
}
resource "aws_route53_record" "etcd_ssl_tcp" {
zone_id = data.aws_route53_zone.test.zone_id
name = "_etcd-server-ssl._tcp.${data.aws_route53_zone.test.name}"
type = "SRV"
ttl = 60
# code is producing an error here. Would like to add the names to the records
for_each = [for n in aws_route53_record.etcd : { name = n.name }]
records = [
"0 10 2380 ${each.value.name}.${data.aws_route53_zone.test.name}"
]
}
When running a terraform plan, I get the following error.
Error: Invalid for_each argument
on main.tf line 55, in resource "aws_route53_record" "etcd_ssl_tcp":
55: for_each = [for n in aws_route53_record.etcd : { name = n.name }]
The given "for_each" argument value is unsuitable: the "for_each" argument
must be a map, or set of strings, and you have provided a value of type tuple.
you use for_each and for in the same line. Both are describing loops and this makes it really hard to fallow. Try to split the line in 2 different lines and assign the for to a local variable. Splitting the for and for_each will help us check this.
I think the issue is [for n in aws_route53_record.etcd : { name = n.name }]
the starting bracket [for ... defines a list and the
{ name .. defines a map . So a list of maps. Perhaps to remove the { ?
Figured it out based on the feedback. Thanks for the help!
resource "aws_route53_record" "etcd_ssl_tcp" {
zone_id = data.aws_route53_zone.kubic.zone_id
name = "_etcd-server-ssl._tcp.${data.aws_route53_zone.test.name}"
type = "SRV"
ttl = 60
records = [
for n in aws_route53_record.etcd :
"0 10 2380 ${n.name}"
]
}

Creating multiple Glue Jobs in Terraform

I am not able to create multiple Glue Jobs through Terraform. I am trying to do a count for jobname using count but when I try to do the same for job s3 script path its saying only string or single allowed." command.0.script_location must be a single value, not a list
"
I tried playing around count order but looks like for every count name its creating 2 paths
resource "aws_glue_job" "glue_ETL_jobs" {
count = "${length(var.jobnames)}"
count = "${length(var.script_location)}"
name ="${var.jobnames[count.index]}_glueETLjob"
role_arn = "${var.ETLjob_glue_role}"
command {
script_location = ["${var.script_location[count.index]}"]
}
default_arguments = {
"--job-language" = "${var.job_language}"
"--job-bookmark-option" = "${var.job_bookmark_option}"
"--TempDir" = "${var.tempdirectory}"
"--enable-continuous-cloudwatch-log" = "${var.cloud_watch_logging}"
"--enable-continuous-log-filter" = "${var.continuous_log_filter}"
"--max-capacity" = "${var.max-capacity}"
}
}
as give abv
name="${var.jobnames[count.index]}_glueETLjob"
script_location = ["${var.script_location[count.index]}"]

I need my module to return either a list of items if input is a non-empty list or an empty list

My module takes a possibly-empty-list as input, and if that list is non-empty, creates some resources and returns a specific attribute that I need outside of the module, like so:
variable contexts {
type = "list"
}
resource "pagerduty_service" "p1" {
count = "${length(var.contexts)}"
name = "p1-${element(var.contexts, count.index)}"
description = "p1-${element(var.contexts, count.index)}"
auto_resolve_timeout = 14400
acknowledgement_timeout = 1800
escalation_policy = "${pagerduty_escalation_policy.p1.id}"
alert_creation = "create_alerts_and_incidents"
incident_urgency_rule {
type = "constant"
urgency = "high"
}
}
data "pagerduty_vendor" "cloudwatch" {
name = "Cloudwatch"
}
resource "pagerduty_service_integration" "p1_cloudwatch" {
count = "${length(var.contexts)}"
name = "Amazon Cloudwatch"
vendor = "${data.pagerduty_vendor.cloudwatch.id}"
service = "${element(pagerduty_service.p1.*.id, count.index)}"
}
output "integration_keys" {
value = "${pagerduty_service_integration.*.integration_keys}"
}
The trouble I am having is that when this module is run first with a non-empty list, thus creating the resources, it works fine. If I run it again, it fails with this exception:
* module.pagerduty.output.integration_keys: Resource 'pagerduty_service_integration.possibly_empty_resource_list' does not have attribute 'integration_key' for variable 'pagerduty_service_integration.possibly_empty_resource_list.*.integration_key'
I can't figure out a nice way to have this output return an empty list if the possibly_empty_resource_list is empty.
Any ideas?
EDIT:
I tried performing a ternary check on the output, but for some reason, using a list is not supported so this won't work however I hope it illustrates what I am trying to do:
"${length(var.contexts) > 0 ? pagerduty_service_integration.*.integration_keys : list()}"
Solution:
output "instance_id" {
value = "${element(concat(aws_instance.example.*.id, list("")), 0)}"
}
There's a section at the very bottom of the terraform upgrade to 0.11 guide here: https://www.terraform.io/upgrade-guides/0-11.html that shows what I use for counted resources
ex:
output "instance_id" { value = "${element(concat(aws_instance.example.*.id, list("")), 0)}" }
(moved over from a comment)

Resources