terraform replace() - Invalid value for "str" parameter: string required - terraform

When attempting to upgrade to Terraform 0.12 I get the following error:
Error: Invalid function argument
on ../../../../../modules/aws/mybox/main.tf line 85, in resource "aws_route53_record" "this":
85: name = "ip-${replace(module.this_mybox.private_ip[0], ".", "-")}"
|----------------
| module.this_mybox.private_ip[0] is tuple with 1 element
Invalid value for "str" parameter: string required.
Looking at the custom module below, I can't seem to use the replace() function in the string...
resource "aws_route53_record" "this" {
name = "ip-${replace(module.this_mybox.private_ip[0], ".", "-")}"
type = "A"
zone_id = "${var.dns_zone_id}"
records = "${module.this_mybox.private_ip[0]}"
ttl = "600"
}
The goal of the module is to spin up an EC2 based on custom parameters. Along with that, there's a few moving parts including adding a private dns record. I've named it based off of this_mybox.private_ip[0]. In Terraform 0.11.14 it worked fine; but I am roadblocked on the upgrade due to this.
Is there another approach for using replace() in the aws_route53_record name?

The error message says that module.this_mybox.private_ip[0] is a tuple and that is why replace fails. This value is also used here records = "${module.this_mybox.private_ip[0]}", which requires a list. We cannot see the value of module.this_mybox.private_ip[0] in your question, but based on the error message I would suggest to access the IP address within the tuple with module.this_mybox.private_ip[0][0].

Related

How to pass list of s3 arns inside the terraform data resource aws_iam_policy_document

I am trying to pass multiple values to pricipals's identifiers in the data resource "aws_iam_policy_document". getting the following error
Inappropriate value for attribute "identifiers": element 0: string required.
s3_values variable is defined type = any and set the values as
....
s3_values:
bucket: bucketname1
s3_arns:
- arn:aws:iam::1234567890:root
- arn:aws:iam::2345678901:role/s3-read-role
data "aws_iam_policy_document" "s3_policy" {
count = length(var.s3_arns)
statement {
sid = "1"
effect = "Allow"
principals {
type = "AWS"
identifiers = ["${var.s3_values[count.index]["s3_arns"]}"]
}
actions = ["s3:PutObject"]
resources = ["arn:aws:s3:::${var.s3_values[count.index]["bucket"]}/*"]
}
}
I get the following error
Inappropriate value for attribute "identifiers": element 0: string required.
its working , when only one value is passed , but not working when we pass multiple values to the variable s3_arns.
It looks like you're trying to create multiple policy documents for a single S3 bucket. Rather than using count to create many documents, it would be best if you created a single policy document that gives access to each ARN you pass.
Currently it works for one ARN because the identifiers field gets passed a single string and creates a list with one string element. When you pass a list of ARNs, the identifiers field is instead creating a list with a list element that contains the ARN strings.
I would fix this by making the s3_arns field always be a list of strings, and removing the count field on the data resource. Once you do that you can change the line identifiers to be identifiers = var.s3_values.s3_arns and the resources line to be resources = ["arn:aws:s3:::${var.s3_values.bucket}/*"]

Using splat operator in terraform azurerm_monitor_metric_alert scope setting

I'm trying to setup an azurerm_monitor_metric_alert for my app services, I'd like to define one alert which covers all my app services which terraform is building.
I have two dimensions to my app services that are build, one based on regions (max of two) and the other on the number of app services deployed to each app service plan (unknown number, two in the below example).
I'd hoped I could do something like:
resource "azurerm_monitor_metric_alert" "disk1" {
name = "AppService-diskSpace-Sev1"
resource_group_name = azurerm_resource_group.location1[0].name
scopes = ["${azurerm_app_service.location1.*.id}","${azurerm_app_service.location2.*.id}"]
description = "Disk space over 90 percent"
window_size = "PT6H"
frequency = "PT1H"
criteria {
metric_namespace = "Microsoft.Web/sites"
metric_name = "FileSystemUsage"
aggregation = "Average"
operator = "GreaterThan"
threshold = 241591910400 # 90% of 250Gb in bytes
}
severity = 1
}
But I get an error like:
Error: Incorrect attribute value type
on ..\..\..\infra\terraform\global\web\main.tf line 343, in resource "azurerm_monitor_metric_alert" "disk1":
343: scopes = ["${azurerm_app_service.location1.*.id}","${azurerm_app_service.location2.*.id}"]
|----------------
| azurerm_app_service.location is tuple with 2 elements
| azurerm_app_service.location2 is tuple with 2 elements
Inappropriate value for attribute "scopes": element 0: string required.
I've tried a number of different options but all produce errors, the doc says
"A set of strings of resource IDs at which the metric criteria should be applied"
but I'm not sure what a "set of strings" means in this context.
-- EDIT
After comments below I tried what I hoped was being suggested but I'm still getting errors:
concat(azurerm_app_service.location.*.id)
returns
Error: scopes: attribute supports 1 item maximum, config has 2 declared.
["${azurerm_app_service.location.*.id}"]
returns
Inappropriate value for attribute "scopes": element 0: string required.
"${azurerm_app_service.web.*.id}"
returns
Error: scopes: attribute supports 1 item maximum, config has 2 declare
this question is quite old, but still no answer, and I had a similar problem, so I give you the results of my research:
First, the splat expression syntax changed in terraform 0.12, so resource.*.attribute is now resource[*].attribute. This returns a list, that's why you get the "Inappropriate value" errors:
scopes = concat(azurerm_app_service.location1[*].id, azurerm_app_service.location2[*].id)
would be correct.
The other error: "scopes: attribute supports 1 item maximum, config has 2 declare" is because of other required attributes, if you use more than one value for scopes. Have a look at the provider documentation of this ressource at the attributes target_resource_type and target_resource_location. These two are required if using more than one scope:
https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/monitor_metric_alert#target_resource_type
I couldn't test this on azure, because we don't use it, but I hope it helps.

how to construct name on terraform v0.12

previously on v0.11 these works on my deployment
resource "aws_alb_target_group" "my_tg" {
name = "${var.SCHOOL}-${var.DEPT}-${var.ID}-tg"
However on v0.12 I'm kinda lost how to adjust with thier update, I'm trying these however gives me error
resource "aws_alb_target_group" "my_tg" {
name = "{"var.SCHOOL"}-{"var.DEPT"}-{"var.ID"}-tg"
ERROR
on alb-tg.tf line 2, in resource "aws_alb_target_group" "my_tg":
2: name = "{"var.SCHOOL"}-{"var.DEPT"}-{"var.ID"}-tg"
An argument definition must end with a newline.
In terraform v0.12 the way you interpolate variables in a string did not change.
The example you provided is still valid.
resource "aws_alb_target_group" "my_tg" {
name = "${var.SCHOOL}-${var.DEPT}-${var.ID}-tg"
The only change in v0.12 is when you are passing only a variable as the name. So the previous name = ”${var.name}” changed in name = var.name. But seeing that you are adding the dash between variables the first example you provided is a valid string and should work.

Terraform - How to restrict an input variable to a list of possible choices

I have a variable that the user will input during run time. Lets say the variable name is region. However, I want the execution to be only successful if the user picks a value from one of the values defined in a list/ choices.
how can I restrict it so the user's selection has to match values that are considered acceptable in the variable definition?
Stumbled across this question.
Since v0.13.0 input validation has been possible directly via the input variables. Thus you can actually achieve this with a snippet such as below.
variable "test_variable" {
type = string
description = "some test value"
validation {
condition = contains(["item1", "item2", "item3"], var.test_variable)
error_message = "Valid values for var: test_variable are (item1, item2, item3)."
}
}
Read more here - https://www.hashicorp.com/blog/custom-variable-validation-in-terraform-0-13
One solution:
variable "values_list" {
description = "acceptable values"
type = "list"
default = ["true", "false"]
}
variable "somevar" {
description = "must be true or false"
}
resource "null_resource" "is_variable_value_valid" {
count = "${contains(var.values_list, var.somevar) == true ? 0 : 1}"
"ERROR: The somevar value can only be: true or false" = true
}
If you pass a value different than "true" or "false" for the "somevar" variable, Terraform will throw an error and stop. The disadvantage is that you have to list all values in the default block of values_list.
Source: https://stackoverflow.com/a/54256780/1364793
Terraform currently has no first-class feature for this, but you can achieve the desired effect (albeit with a less-helpful error message) by asking Terraform to look the value up in a map:
variable "example" {
description = "must be a, b, or c"
}
locals {
allowed_example_values = { for v in ["a", "b", "c"] : v => v }
checked_example = local.allowed_example_values[var.example] # will fail if var.example is invalid
}
Because the values in the allowed_example_values map are the same as the keys, you can then use local.checked_example in place of var.example everywhere else in the module to set up the dependency graph such that it's impossible for an invalid value to be used.
Some caveats/limitations:
You can't customize the error message that Terraform will return when the value is invalid. Instead, Terraform will return the generic error about the key not matching any element in the map. However, it will include the source code snippet from the affected line in the error message (in Terraform 0.12 or later) so the comment at the end of that line should be visible in the error message and thus provide an additional clue to the user as to what might be wrong.
This works fully only for string values, because map keys are always strings in Terraform. Using other primitive types can work as a result of Terraform's automatic conversions from bool and number to string, but you should be sure to explicitly declare the type of the variable (using e.g. type = number) to ensure that Terraform will normalize incoming values into the expected type before looking them up in the map. This technique will not work at all for collection and structural types.
I wouldn't suggest using strings "true" and "false" since Terraform has a bool type which can represent that more intuitively. If you are using Terraform 0.11 and earlier then it's not possible to constrain to bool, but in Terraform 0.12 and later you can declare a variable as type = bool and then Terraform will handle the validation automatically.

unknown token IDENT list error for IP address variable

I have defined variable in my .tfvars variable as
variables.tfvars
address_space = ["10.197.0.0/16"]
build-windows.tf
variable "address_space" {
type = list
}
In build-windows.tf file I get the error as Unknow token ident list?
Not sure what I am doing wrong here, I even do not understand why terraform wants me to use the list instead of a string. When I use string I get an error in terraform plan stating that I have to use list.
Not going anywhere.
Please assist
The type parameter is a string - try passing "list" into it.
variable "address_space" {
type = "list"
}

Resources