Terraform : removal of identity block does not remove identity assigned from resource azure logic app - terraform

I have this in my main.tf and
dynamic "identity" {
for_each = var.identity == [] ? [] : [1]
content {
type = lookup(var.identity, "type", null)
#identity_ids = lookup(var.identity, "identity_ids", null)
}
}
I have defined variable as below.
variable "identity" {
description = "creates the identity for Logic App."
type = any
default = []
}
Removing identity block from input does not remove assigned identity. Terraform does not detect the change. Can some1 help ?
Also Logic App standard only supports SystemAssigned but doc says something else :
https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/logic_app_standard

There seems to be some type confusion in your configuration here, but Terraform isn't able to detect and report it because you didn't give a specific type constraint for your variable.
Specifically, it's not clear whether you intended var.identity to be a list of objects or a single object. You declared the default as [], suggesting you meant a list, but the content of the dynamic "identity" block treats var.identity as if it's just a single object.
I'm going to write this out both ways, so you can choose which one meets your actual requirement.
For a list of "identities" with one identity block each:
variable "identities" {
type = list(object({
type = string
identity_ids = set(string)
}))
default = []
}
resource "example" "example" {
dynamic "identity" {
for_each = var.identities
content {
type = each.value.type
identity_ids = each.value.identity_ids
}
}
}
For a single "identity" object that is optional:
variable "identities" {
type = object({
type = string
identity_ids = set(string)
})
default = null
}
resource "example" "example" {
dynamic "identity" {
for_each = var.identities[*]
content {
type = each.value.type
identity_ids = each.value.identity_ids
}
}
}
In this second example, notice that:
The type constraint for variable "identities" is now just for an object type directly, without the list(...) from the first example.
The default value for that variable is now null, which is the typical way to represent the absence of a single value.
The dynamic "identity" block's for_each expression uses the [*] operator, called the "splat operator", which has a special behavior where it'll convert a null value into an empty list and a non-null value into a single-element list, thus producing a suitable collection value for the for_each argument.
I would recommend always writing type constraints for your input variables, because then Terraform can give you better feedback in situations like yours where you were not consistent in the types you were using. If you use any in a type constraint then Terraform will have less insight into what you are intending and so its error messages will typically be less specific and possibly even misleading, if it makes an incorrect assumption about what your goals were.

Related

How to select the value of a specific resource in tuple based on a property value?

Hello im struggling a little to solve this challenge and hope someone can provide insights. I need to pick a specific resource out of a tuple of those resources based on a property on that resource. How would one go about achieving something like that?
Code looks something like:
resource "aws_network_interface" "network_interface" {
for_each = var.counter_of_2
// stuff
}
resource "aws_network_interface_attachment" "currently_used_eni" {
instance_id = var.instance_id
network_interface_id = <the aws_network_interface with tag.Name = "thisone">
device_index = 0
}
Because tag is not ID of resource something like that would be impossible. Imagine if you have two network interfaces with same tag. Which one should it take?
But your case might be not lost. (yet it might... depends on case)
I assume that if you want to find specific aws_network_interface then tags are unique. And if they are unique then every network interface have different tag. So you can simply use something like that:
aws_network_interface.network_interface["value_from_for_each"]
For simplicity (and assuming that one network interface = one tag) I'll make this for_each collection to be set of tag names.
variable "interface_tags" {
type = set(string)
default = ["tag1", "tag2", "thisone"]
}
resource "aws_network_interface" "network_interface" {
for_each = var.interface_tags
// stuff
}
resource "aws_network_interface_attachment" "currently_used_eni" {
instance_id = var.instance_id
network_interface_id = aws_network_interface.network_interface["thisone"].id
device_index = 0
}
And this should work (and I hope it can be used in your case)

Terraform : How to avoid code duplication of variables?

I have two modules and one root module that pretty much use the same "blueprint" of a variable, namely to instantiate projects within my infrastructure. As I'm in a test and learn process, I have to go back to all the occurences of variables.tf where they are declared. Therefore, I must change everything every time I want to add an attribute or remove it from the modules. It's a pain and waste of time.
Either within module defined inputs
Or within root-module variables
How I wish to use this variable :
Global blueprint declaration (sort of how you would declare a class in python or java)
"blueprint" project" {
type = object({
name = string
id_suffix = string
auto_create_network = bool
apis_to_enable = list(string)
attached_principals_info = object({
service_account_principals = map(object({
name = string
description = string
disabled = bool
roles = list(string)
impersonators = list(string)
}))
user_principals = map(object({
email = string
description = string
full_name = string
roles = list(string)
}))
})
})
}
"blueprint" "projects" {
type = map(project)
}
Usage within the module input .tfs:
variable "project" {
type = blueprint.project
}
variable "projects" {
type = blueprint.projects
}
How I currently use it:
The variable project and variable projects are explicitely detailed within each .tf of each module, similarly to what I declared above...
Side note : I've been following the credo write as little code as possible, be as lazy-efficient as possible within all my coding
endeavors, it's quite hard to do it in Terraform.

Can't get global_parameter to work with Terraform azurerm_data_factory

According to the documentation .. global_parameter is indeed a valid argument. However when trying to use it, my validate command reports that An argument named "global_parameter" is not expected here. Did you mean to define a block of type "global_parameter"?
My config is simply
resource "azurerm_data_factory" "adf" {
name = "adf-${var.project}"
location = var.az_location
resource_group_name = azurerm_resource_group.rg.name
tags = {
environment = var.environment
project = var.project
}
global_parameter = {}
}
I am using version 2.81 of the azurerm provider.
The documentation doesn't seem correct. It's not supposed to be an argument; it's actually supposed to be declared as a block. Hence this is incorrect:
global_paramter = {}
and this is correct:
global_parameter {}
(No equals assignment here)
The documentation says it's an argument while the error suggests you probably wanted a block instead of an argument.

Pass complex, non-primitive data types to Terraform template provider

Having a more complex list object like this
variable "proxy" {
type = list(object({
enabled = bool
host = string
port = number
user = string
password = string
}))
default = [
{
enabled = false
host = ""
port = 0
user = ""
password = ""
}
]
}
I want to use this in a external template (cloudinit in my case). The template_file directive allows passing variables to a template. Sadly, not for more complex types:
Note that variables must all be primitives. Direct references to lists or maps will cause a validation error.
So something like this
data "template_file" "cloudinit_data" {
template = file("cloudinit.cfg")
vars = {
proxy = var.proxy
}
}
cause the error
Inappropriate value for attribute "vars": element "proxy": string required.
This leads me to two questions:
How can I pass the variable to the template? I assume that I need to convert it to a primitive type like this:
vars = {
proxy_host = var.proxy.host
}
This doesn't work:
This value does not have any attributes.
Is there an alternative way to pass this object directly to the template?
I'm using v0.12.17.
The template_file data source continues to exist only for compatibility with configurations written for Terraform 0.11. Since you are using Terraform 0.12, you should use the templatefile function instead, which is a built-in part of the language and supports all value types.
Because templatefile is a function, you can call it from anywhere expressions are expected. If you want to use the rendered result multiple times then you could define it as a named local value, for example:
locals {
cloudinit_data = templatefile("${path.module}/cloudinit.cfg", {
proxy = var.proxy
})
}
If you only need this result once -- for example, if you're using it just to populate the user_data of a single aws_instance resource -- then you can just write this expression inline in the resource block, to keep everything together and make the configuration (subjectively) easier to read:
resource "aws_instance" "example" {
# ...
user_data = templatefile("${path.module}/cloudinit.cfg", {
proxy = var.proxy
})
}

Terraform how to interpolate map types in a template_file?

I am trying to pass a map variable into a template_file, and am being thrown this error:
vars (varsname): '' expected type 'string', got unconvertible type 'map[string]interface {}'
data "template_file" "app" {
template = "${file("./app_template.tpl")}"
vars {
container = "${var.container-configuration}"
}
}
variables.tf
variable "container-configuration" {
description = "Configuration for container"
type = "map"
default = {
image = "blahblah.dkr.ecr.us-east-2.amazonaws.com/connect"
container-port = "3000"
host-port = "3000"
cpu = "1024"
memory = "2048"
log-group = "test"
log-region = "us-east-2a"
}
}
Is there a way to pass the map into the template file for interpolation? I haven't found anything clear in the documentation.
Terraform v0.12 introduced the templatefile function, which absorbs the main use-cases of the template_file data source, and accepts values of any type:
templatefile("${path.module}/app_template.tpl", {
container = var.container-configuration
})
Terraform v0.11 and earlier do not have any means to render a template with non-string values. The limitation exists due to the nature of the protocol used to represent map values in the configuration: it is only capable of representing maps of string until the new protocol that was introduced in Terraform v0.12.
Passing maps is not yet supported, see template_file documentation.
From that article:
Variables must all be primitives. Direct references to lists or maps will cause a validation error.
It means you need to pass variables one by one individually.

Resources