Metric filter patter with variables - amazon-web-services

I am trying to define a metric filter for my vpc flow logs and wanted the pattern to formed by a data source result. I have defined a data source to return all enis of given subnets and I want to loop over the result set and construct one metric filter for those enis. but the for_each is creating a metric filter for each eni.
I can't figure out a way to adjust the code such that I can write something like
(interfaceid=$value1 || interfaceid=$value2 || ...) in the filter pattern. any help will be much appreciated.
data "aws_network_interfaces" "ENI_List" {
filter {
name = "subnet-id"
values = ["subnet-A", "subnet-B", "subnet-C"]
}
}
Below is my metric filter. I want to be able to use each eni in the data.aws_network_interfaces.ENI_List.ids result set in my pattern like below
resource "aws_cloudwatch_log_metric_filter" "EUN_Network_Filter" {
for_each = toset("${data.aws_network_interfaces.ENI_List.ids}")
name = "EUN_DC_Network_Traffic_Monitoring"
pattern = "[version, accountid, (interfaceid=${each.value}), srcaddr, dstaddr, srcport, dstport, protocol, packets, bytes, start, end, action, logstatus=NODATA]"
log_group_name = "VPC_Flow_Log_Group" # "${data.aws_cloudwatch_log_group.vpc_flow_log_group}"
metric_transformation {
name = "EUN_Network"
namespace = "EUN_Network_Traffic"
value = "1"
}
}

Well, you could create the following local value with combination of formatlist and join:
locals {
interfaceids_str = join(" || ", formatlist("interfaceid=%s", var.enis))
}
then
resource "aws_cloudwatch_log_metric_filter" "EUN_Network_Filter" {
name = "EUN_DC_Network_Traffic_Monitoring"
pattern = "[version, accountid, (${local.interfaceids_str}), srcaddr, dstaddr, srcport, dstport, protocol, packets, bytes, start, end, action, logstatus=NODATA]"
log_group_name = "VPC_Flow_Log_Group" # "${data.aws_cloudwatch_log_group.vpc_flow_log_group}"
metric_transformation {
name = "EUN_Network"
namespace = "EUN_Network_Traffic"
value = "1"
}
}

Related

Reference variable in a for loop in terraform

I have a list of accounts declared under variable "acct". I need to create as many ARNs as the accounts below using this list. How to do it? The below code gives me attribute error:
A reference to a resource type must be followed by at least one attribute access, specifying the resource name.
variable "acct"{
type = list(string)
default = ["111111111111","22222222222",.....]
}
data "aws_arn" "SrcArn" {
account = [for acc in var.acct : acc ]
arn = ["arn:aws:logs:us-east-1:${account}:*"]
}
I need to create a list of arns which then can be used further down in the code. Can these then be referenced below like this:
condition {
test = "ArnLike"
values = data.aws_arn.SrcArn
variable = "aws:SourceArn"
}
If you want to use aws_arn, you can use to this.
variable "acct"{
type = list(string)
default = ["111111111111","22222222222",.....]
}
data "aws_arn" "SrcArn" {
count = var.acct
arn = ["arn:aws:logs:us-east-1:${var.acct[count.index]}:*"]
}
And if you wanna make arn_list,
locals {
# only use to variable.
# not use to data "aws_arn"
arn_list_only_use_to_variable = [for account in var.acct: "arn:aws:logs:us-east-1:${account}:*"]
# use to data "aws_arn"
src_arn = data.aws_arn.SrcArn
arn_list_2_use_to_data_aws_arn = [for account in src_arn: account]
}
...
condition {
test = "ArnLike"
values = local.arn_list_only_use_to_variable
variable = "aws:SourceArn"
}
...

In Terraform, how do you output a list from an array of objects?

I'm creating a series of s3 buckets with this definition:
resource "aws_s3_bucket" "map" {
for_each = local.bucket_settings
bucket = each.key
...
}
I'd like to output a list of the website endpoints:
output "website_endpoints" {
# value = aws_s3_bucket.map["example.com"].website_endpoint
value = ["${keys(aws_s3_bucket.map)}"]
}
What's the syntax to pull out a list of the endpoints (rather than the full object properties)?
If you just want to get a list of website_endpoint, then you can do:
output "website_endpoints" {
value = values(aws_s3_bucket.map)[*].website_endpoint
}
This uses splat expression.
You can loop over your buckets with for loop and output specific attribute, in this case website_endpoint.
output "endpoint" {
value = [for s in aws_s3_bucket.map : s.website_endpoint[*]]
}

Outputs from for_each loop for each resource

I am having a hard time figuring out how to make an output for each target group resource that this code creates.
I'd like to be able to reference each one individually in other modules. It sounds like for_each stores it as a map, so my question is how would I get the arn for targetgroup1 and targetgroup2?
Terraform normally refers to outputs by resource name, so I am struggling with that in this scenario and also how to refer to these individual arns.
Would I also need to work the outputs into the for_each or could I drop it into the output.tf file?
locals {
target_groups_beta = {
targetgroup1 = {
name = "example",
path = "/",
environment = "Beta"
}
targetgroup2 = {
name = "example2",
path = "/",
environment = "Beta"
}
}
}
resource "aws_lb_target_group" "target-group" {
for_each = local.target_groups_beta
name = "example-${each.value.name}-"
port = 80
protocol = "HTTP"
vpc_id = var.vpc-id
deregistration_delay = 5
tags = {
Environment = "${each.value.environment}"
}
health_check{
healthy_threshold = 2
unhealthy_threshold = 2
timeout = 10
interval = 15
path = each.value.path
}
}
I receive the following error when trying to do it in the output.tf file without a key value, but when I input one such as value = "${aws_lb_target_group.target-group[0].arn}" it says it's invalid. Error without key value below:
Error: Missing resource instance key
on modules\targetgroups\output.tf line 2, in output "tg_example_beta":
2: value = "${aws_lb_target_group.target-group.arn}"
Because aws_lb_target_group.target-group has "for_each" set, its attributes
must be accessed on specific instances.
For example, to correlate with indices of a referring resource, use:
aws_lb_target_group.target-group[each.key]
The aws_lb_target_group.target-group generated will be a map, with key values of targetgroup2 and targetgroup1.
Therefore, to get the individual target group details you can do:
output "target-group1-arn" {
value = aws_lb_target_group.target-group["targetgroup1"].arn
}
To return both as a map:
output "target-groups-arn-alternatice" {
value = {for k, v in aws_lb_target_group.target-group: k => v.arn}
}
target-groups-arn-alternatice = {
"targetgroup1" = "arn:aws:elasticloadbalancing:us-east-1:xxxx:targetgroup/example-example/285b26e15221b113"
"targetgroup2" = "arn:aws:elasticloadbalancing:us-east-1:xxxx:targetgroup/example-example2/075bd58359e4c4b2"
}
To return both as a list (order will be same as for keys function):
output "target-groups-arn" {
value = values(aws_lb_target_group.target-group)[*].arn
}
target-groups-arn = [
"arn:aws:elasticloadbalancing:us-east-1:xxxx:targetgroup/example-example/285b26e15221b113",
"arn:aws:elasticloadbalancing:us-east-1:xxxx:targetgroup/example-example2/075bd58359e4c4b2",
]

How to use for_each with iterator in dynamic block in Terraform?

I am trying to do this basically:
module "california" {
source = "./themodule"
# ...
}
module "oregon" {
source = "./themodule"
# ...
}
resource "aws_globalaccelerator_endpoint_group" "world" {
# ...
dynamic "endpoint_configuration" {
for_each = [
module.california.lb,
module.oregon.lb
]
iterator = lb
content {
endpoint_id = lb.arn
weight = 100
}
}
}
# themodule/main.tf
resource "aws_lb" "lb" {
# ...
}
output "lb" {
value = aws_lb.lb
}
I am outputting lb from a submodule in Terraform, and trying to use that in the parent module in a for_each array, with a custom iterator name. It is giving me this error:
This object does not have an attribute named "arn".
But it DOES have that attribute, it's an aws_lb. What am I doing wrong in the usage of this for_each and module setup, and how do I fix it? Thank you very much!
https://www.hashicorp.com/blog/terraform-0-12-rich-value-types/
If I change it to this it seems to work:
resource "aws_globalaccelerator_endpoint_group" "world" {
listener_arn = aws_globalaccelerator_listener.world.id
endpoint_configuration {
endpoint_id = module.california.lb.arn
weight = 100
}
}
From the docs:
The iterator object (setting in the example above) has two attributes:
key is the map key or list element index for the current element. If the for_each expression produces a set value then key is identical to value and should not be used.
value is the value of the current element.
Based on that, in the content, you should used lb.value["arn"], as per example. Thus, the following could be tried:
content {
endpoint_id = lb.value["arn"]
weight = 100
}

How to output all the resources of one type in Terraform?

I have a bunch of aws_ecr_repositories defined in my Terraform code:
resource "aws_ecr_repository" "nginx_images" {
name = "nginx-test"
}
resource "aws_ecr_repository" "oracle_images" {
name = "oracle-test"
}
I want to be able to have an output that can list all the aws_ecr_repository resources into one output. This is what I tried:
output "ecr_repository_urls" {
value = "[${aws_ecr_repository.*.repository_url}]"
}
This does not work because Terraform does not seem to allow wildcards on the resource names. Is it possible to have an output like this? My current solution is to just list outputs for every resource defined.
Terraform's splat syntax is for keeping track of each thing created by a resource using the count meta parameter.
If you want to be able to get at all of the respoitory URLs you could have a single aws_ecr_repository resource and use the count meta parameter with something like this:
variable "images" {
default = [
"nginx-test",
"oracle-test",
]
}
resource "aws_ecr_repository" "images" {
count = "${length(var.images)}"
name = "${var.images[count.index]}"
}
output "ecr_repository_urls" {
value = "[${aws_ecr_repository.images.*.repository_url}]"
}
You can combine them manually as a list:
output "ecr_repository_urls" {
value = ["${aws_ecr_repository.nginx_images.repository_url}", "${aws_ecr_repository.oracle_images.repository_url}"]
}
Although it probably won't be pretty in code.
You could also do something like this:
variable "ecr_repos" {
default = {
"0" = "foo"
"1" = "bar"
}
}
resource "aws_ecr_repository" "images" {
count = "${length(var.ecr_repos)}"
name = "${lookup(var.ecr_repos,count.index)}-test"
}
output "ecr_repository_urls" {
value = "${aws_ecr_repository.images.*.repository_url}"
}
But the problem is if the list order changes it's going to recreate resources and get really ugly really fast since each repo is assigned to an index number.