

Las traducciones son generadas a través de traducción automática. En caso de conflicto entre la traducción y la version original de inglés, prevalecerá la version en inglés.

# Comprensión de las funciones, expresiones y metaargumentos de Terraform
<a name="functions-expressions"></a>

Una crítica a las herramientas de IaC que utilizan archivos de configuración declarativos en lugar de lenguajes de programación comunes es que dificultan la implementación de una lógica programática personalizada. En las configuraciones de Terraform, este problema se resuelve mediante funciones, expresiones y metaargumentos.

## Funciones
<a name="functions"></a>

Una de las grandes ventajas de usar código para aprovisionar la infraestructura es la capacidad de almacenar flujos de trabajo comunes y reutilizarlos una y otra vez, con frecuencia utilizando argumentos diferentes cada vez. Las funciones de Terraform son similares a [las funciones AWS CloudFormation intrínsecas](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference.html), aunque su sintaxis es más parecida a la forma en que se denominan las funciones en los lenguajes de programación. [Es posible que ya hayas visto algunas funciones de Terraform, como [substr](https://developer.hashicorp.com/terraform/language/functions/substr), [concat](https://developer.hashicorp.com/terraform/language/functions/concat), length y [base64decode](https://developer.hashicorp.com/terraform/language/functions/base64decode), en los ejemplos de esta guía.](https://developer.hashicorp.com/terraform/language/functions/length) Al igual que CloudFormation las funciones intrínsecas, Terraform tiene una serie de [funciones integradas](https://developer.hashicorp.com/terraform/language/functions) que están disponibles para su uso en sus configuraciones. Por ejemplo, si un atributo de recurso concreto ocupa un objeto JSON muy grande y sería ineficiente pegarlo directamente en el archivo, podrías poner el objeto en un **archivo.json** y usar las funciones de Terraform para acceder a él. En el siguiente ejemplo, la `file` función devuelve el contenido del archivo en forma de cadena y, a continuación, lo convierte en un tipo de objeto. `jsondecode`

```
resource "example_resource" "example_resource_name" {
  json_object = jsondecode(file("/path/to/file.json"))
}
```

## Expressions
<a name="expressions"></a>

Terraform también admite [expresiones condicionales](https://developer.hashicorp.com/terraform/language/expressions/conditionals), que son similares a CloudFormation `condition` las funciones, excepto que utilizan la sintaxis de [operador ternario](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Conditional_operator) más tradicional. En el siguiente ejemplo, las dos expresiones devuelven exactamente el mismo resultado. El segundo ejemplo es lo que Terraform denomina expresión [splat](https://developer.hashicorp.com/terraform/language/expressions/splat). El asterisco hace que Terraform recorra la lista y cree una nueva lista utilizando solo la `id` propiedad de cada elemento.

```
resource "example_resource" "example_resource_name" {
  boolean_value  = var.value ? true : false
  numeric_value  = var.value > 0 ? 1 : 0
  string_value   = var.value == "change_me" ? "New value" : var.value
  string_value_2 = var.value != "change_me" ? var.value : "New value"
}
There are two ways to express for loops in a Terraform configuration:
resource "example_resource" "example_resource_name" {
  list_value   = [for object in var.ids : object.id]
  list_value_2 = var.ids[*].id
}
```

## Metaargumentos
<a name="meta-arguments"></a>

*En el ejemplo de código anterior, `list_value` y se `list_value_2` denominan argumentos.* Es posible que ya estés familiarizado con algunos de estos metaargumentos. Terraform también tiene algunos *metaargumentos, que actúan como argumentos* pero con alguna funcionalidad adicional:
+ [El [metaargumento depends\$1on](https://developer.hashicorp.com/terraform/language/meta-arguments/depends_on) es muy similar al atributo. CloudFormation DependsOn](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-attribute-dependson.html)
+ El metaargumento del [proveedor](https://developer.hashicorp.com/terraform/language/meta-arguments#provider) le permite usar múltiples configuraciones de proveedores a la vez.
+ [El metaargumento [del ciclo](https://developer.hashicorp.com/terraform/language/meta-arguments/lifecycle) de vida permite personalizar la configuración de los recursos, de forma similar a como se hace en las políticas de [eliminación y eliminación](https://docs.aws.amazon.com/cdk/api/v2/python/aws_cdk/RemovalPolicy.html).](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-attribute-deletionpolicy.html) CloudFormation

Otros metaargumentos permiten añadir funciones y expresiones directamente a un recurso. Por ejemplo, el metaargumento [count](https://developer.hashicorp.com/terraform/language/meta-arguments/count) es un mecanismo útil para crear varios recursos similares al mismo tiempo. En el siguiente ejemplo, se muestra cómo crear dos clústeres de Amazon Elastic Container Service (Amazon EKS) sin utilizar el `count` metaargumento.

```
resource "aws_eks_cluster" "example_0" {
  name     = "example_0"
  role_arn = aws_iam_role.cluster_role.arn
  vpc_config {
    endpoint_private_access = true
    endpoint_public_access  = true
    subnet_ids              = var.subnet_ids[0]
  }
}

resource "aws_eks_cluster" "example_1" {
  name     = "example_1"
  role_arn = aws_iam_role.cluster_role.arn
  vpc_config {
    endpoint_private_access = true
    endpoint_public_access  = true
    subnet_ids              = var.subnet_ids[1]
  }
}
```

El siguiente ejemplo muestra cómo utilizar el `count` metaargumento para crear dos clústeres de Amazon EKS.

```
resource "aws_eks_cluster" "clusters" {
  count    = 2
  name     = "cluster_${count.index}"
  role_arn = aws_iam_role.cluster_role.arn
  vpc_config {
    endpoint_private_access = true
    endpoint_public_access  = true
    subnet_ids              = var.subnet_ids[count.index]
  }
}
```

Para asignar a cada uno un nombre de unidad, puede acceder al índice de la lista dentro del bloque de recursos en. `count.index` Pero, ¿qué pasa si quieres crear varios recursos similares que sean un poco más complejos? Ahí es donde entra en juego el [metaargumento for\$1each](https://developer.hashicorp.com/terraform/language/meta-arguments/for_each). El `for_each` metaargumento es muy similar a`count`, excepto que se pasa una lista o un objeto en lugar de un número. Terraform crea un nuevo recurso para cada miembro de la lista u objeto. Es similar a si lo configuras`count = length(list)`, excepto que puedes acceder al contenido de la lista en lugar del índice del bucle.

Esto funciona tanto para una lista de elementos como para un solo objeto. El siguiente ejemplo crearía dos recursos que tienen `id-0` y `id-1` como sus IDs.

```
variable "ids" {
  default = [
    { id = "id-0" },
    { id = "id-1" },
  ]
}

resource "example_resource" "example_resource_name" {
  # If your list fails, you might have to call "toset" on it to convert it to a set
  for_each = toset(var.ids)
  id       = each.value
}
```

En el ejemplo siguiente se crearían también dos recursos, uno para Sparky, el caniche, y otro para Fluffy, el chihuahua.

```
variable "dogs" {
  default = {
    poodle    = "Sparky"
    chihuahua = "Fluffy"
  }
}

resource "example_resource" "example_resource_name" {
  for_each = var.dogs
  breed    = each.key
  name     = each.value
}
```

Del mismo modo que puedes acceder al índice de bucles en count mediante count.index, puedes acceder a la clave y al valor de cada elemento de un bucle for\$1each utilizando cada objeto. Como for\$1each recorre listas y objetos, puede resultar un poco confuso realizar un seguimiento de cada clave y valor. En la siguiente tabla se muestran las distintas formas en que se puede utilizar el metaargumento for\$1each y cómo se puede hacer referencia a los valores en cada iteración.


****  

| Ejemplo | Tipo de `for_each` | Primera iteración | Segunda iteración | 
| --- | --- | --- | --- | 
| A | <pre>["poodle", "chihuahua"]</pre> | <pre>each.key = "poodle"<br /><br />each.value = null</pre> | <pre>each.key = "chihuahua"<br /><br />each.value = null</pre> | 
| B | <pre>[<br /><br />{<br /><br />type = "poodle",<br /><br />name = "Sparky"<br /><br />},<br /><br />{<br /><br />type = "chihuahua",<br /><br />name = "Fluffy"<br /><br />}<br /><br />]</pre> | <pre>each.key = {<br /><br />type = "poodle",<br /><br />name = "Sparky"<br /><br />}<br /><br />each.value = null</pre> | <pre>each.key = {<br /><br />type = "chihuahua",<br /><br />name = "Fluffy"<br /><br />}<br /><br />each.value = null</pre> | 
| C | <pre>{<br /><br />poodle = "Sparky",<br /><br />chihuahua = "Fluffy"<br /><br />}</pre> | <pre>each.key = "poodle"<br /><br />each.value = "Sparky"</pre> | <pre>each.key = "chihuahua"<br /><br />each.value = "Fluffy"</pre> | 
| D | <pre>{<br /><br />dogs = {<br /><br />poodle = "Sparky",<br /><br />chihuahua = "Fluffy"<br /><br />},<br /><br />cats = {<br /><br />persian = "Felix",<br /><br />burmese = "Morris"<br /><br />}<br /><br />}</pre> | <pre>each.key = "dogs"<br /><br />each.value = {<br /><br />poodle = "Sparky",<br /><br />chihuahua = "Fluffy"<br /><br />}</pre> | <pre>each.key = "cats"<br /><br />each.value = {<br /><br />persian = "Felix",<br /><br />burmese = "Morris"<br /><br />}</pre> | 
| E | <pre>{<br /><br />dogs = [<br /><br />{<br /><br />type = "poodle",<br /><br />name = "Sparky"<br /><br />},<br /><br />{<br /><br />type = "chihuahua",<br /><br />name = "Fluffy"<br /><br />}<br /><br />],<br /><br />cats = [<br /><br />{<br /><br />type = "persian",<br /><br />name = "Felix"<br /><br />},<br /><br />{<br /><br />type = "burmese",<br /><br />name = "Morris"<br /><br />}<br /><br />]<br /><br />}</pre> | <pre>each.key = "dogs"<br /><br />each.value = [<br /><br />{<br /><br />type = "poodle",<br /><br />name = "Sparky"<br /><br />},<br /><br />{<br /><br />type = "chihuahua",<br /><br />name = "Fluffy"<br /><br />}<br /><br />]</pre> | <pre>each.key = "cats"<br /><br />each.value = [<br /><br />{<br /><br />type = "persian",<br /><br />name = "Felix"<br /><br />},<br /><br />{<br /><br />type = "burmese",<br /><br />name = "Morris"<br /><br />}<br /><br />]</pre> | 

 

Entonces, si `var.animals` fuera igual a la fila E, entonces podrías crear un recurso por animal usando el siguiente código.

```
resource "example_resource" "example_resource_name" {
  for_each = var.animals
  type     = each.key
  breeds   = each.value[*].type
  names    = each.value[*].name
}
```

Como alternativa, puedes crear dos recursos por animal mediante el siguiente código.

```
resource "example_resource" "example_resource_name" {
  for_each = var.animals.dogs
  type     = "dogs"
  breeds   = each.value.type
  names    = each.value.name
}

resource "example_resource" "example_resource_name" {
  for_each = var.animals.cats
  type     = "cats"
  breeds   = each.value.type
  names    = each.value.name
}
```