# Ссылки в HCL: как читать aws_s3_bucket.demo.bucket _Основы Terraform · TerraformLab Knowledge Base_ **TL;DR:** Любое значение в HCL можно получить через адрес: var.x, local.x, aws_s3_bucket.demo.arn, module.net.vpc_id, data.aws_region.current.name. Понимание этого синтаксиса, половина продуктивности в Terraform. ## Зачем понимать ссылки В HCL почти всё, это ссылки. Имя бакета зависит от региона? Ссылаемся на data.aws_region. Имя зависит от переменной? var.something. Атрибут одного ресурса нужен в другом? aws_s3_bucket.demo.arn. Без уверенного знания синтаксиса ссылок Terraform превращается в копипаст без понимания. С ним, наоборот. ## Главные пять префиксов | Префикс | Что | Пример | |---|---|---| | `var.имя` | Переменная | `var.region` | | `local.имя` | Локал | `local.name_prefix` | | `тип.имя.атрибут` | Resource | `aws_s3_bucket.demo.arn` | | `data.тип.имя.атрибут` | Data-источник | `data.aws_region.current.name` | | `module.имя.output_имя` | Output дочернего модуля | `module.network.vpc_id` | Плюс есть специальные внутри блоков: - `count.index`, внутри блока с `count`. - `each.key`, `each.value`, внутри блока с `for_each`. - `self.атрибут`, внутри `provisioner` (advanced). ## Простые примеры ```hcl variable "env" { default = "dev" } locals { prefix = "myapp-${var.env}" } data "aws_region" "current" {} resource "aws_s3_bucket" "logs" { bucket = "${local.prefix}-logs-${data.aws_region.current.name}" # myapp-dev-logs-us-east-1 } resource "aws_s3_bucket_versioning" "logs" { bucket = aws_s3_bucket.logs.id # ссылка на первый бакет versioning_configuration { status = "Enabled" } } ``` ## Внутри ${...} vs без них В современном HCL `${...}` нужны только если выражение, часть строки: ```hcl # interpolation внутри строки, обязательны bucket = "myapp-${var.env}-${local.region}" # выражение целиком, кавычки и ${...} НЕ нужны bucket = local.bucket_name count = var.instance_count region = data.aws_region.current.name ``` Старый стиль `"${var.foo}"` для одного выражения тоже работает, но Terraform будет ругаться warning'ом «Interpolation-only expressions are deprecated». ## Splat operator [*], взять одно поле от всех Если ресурс создан с `count` или `for_each`, он становится list/map. Чтобы получить, например, все `arn`: ```hcl resource "aws_s3_bucket" "logs" { count = 3 bucket = "logs-${count.index}" } # Все arn'ы списком output "all_arns" { value = aws_s3_bucket.logs[*].arn # = [aws_s3_bucket.logs[0].arn, aws_s3_bucket.logs[1].arn, aws_s3_bucket.logs[2].arn] } ``` Знак `[*]` называется splat operator. Применяется к count и for_each одинаково. Альтернативный синтаксис через `for`: ```hcl output "all_arns" { value = [for b in aws_s3_bucket.logs : b.arn] } ``` ## Адреса с индексом ```hcl # count aws_s3_bucket.logs[0] # первый aws_s3_bucket.logs[length(aws_s3_bucket.logs) - 1] # последний # for_each aws_s3_bucket.regional["us"] aws_s3_bucket.regional["eu"].arn # внутри resource с count resource "aws_s3_bucket" "logs" { count = 3 bucket = "logs-${count.index}" # 0, 1, 2 } # внутри resource с for_each resource "aws_s3_bucket" "regional" { for_each = toset(["us", "eu"]) bucket = "data-${each.key}" # us, eu tags = { region = each.value } # тот же us/eu, для toset } ``` ## Какой атрибут существует у ресурса Когда вы пишете `aws_s3_bucket.demo.X`, какие X доступны? Это зависит от провайдера. Список, в документации провайдера: - https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket Раздел **"Attributes Reference"**, что можно прочитать. Раздел **"Arguments"**, что можно задать. Совет: запомните адресацию `terraform.io/providers///latest/docs/resources/`, пригодится постоянно. ## Подводные камни - **`local` vs `locals` снова.** Объявление, `locals { ... }`, ссылка, `local.name`. Без `s`. - **Ресурс с count в state, list. Адрес без индекса работает не везде.** `aws_s3_bucket.logs.arn`, ошибка если count > 1. Нужно `aws_s3_bucket.logs[0].arn` или `aws_s3_bucket.logs[*].arn`. - **`var.имя`, для variable, не для locals.** Часто новички пишут `var.prefix` имея в виду local. Это два разных namespace. - **`(known after apply)` ломает интуицию.** Если вы ссылаетесь на атрибут, который вычисляется на стороне облака. Terraform знает что значение появится, но не показывает его в plan. Это нормально. - **Циклические зависимости, фатальны.** Если A ссылается на B, а B на A. Terraform упадёт с «cyclic dependency». Лечится через [tf-locals](/terraform/kb/tf-locals.md) или пересмотром архитектуры. - **Ссылаться на ресурс из самого блока, нельзя.** `resource "x" { foo = self.bar }`, `self` доступен только в `provisioner` блоках. Обычно, никак. ## Команды ```bash terraform console ``` Интерактивно проверить значение ссылки. Очень помогает с splat и for-выражениями. ```bash terraform state list ``` Полный список адресов в текущем state: копируй прямо из вывода. ```bash terraform state show aws_s3_bucket.demo ``` Все атрибуты ресурса: посмотреть на что можно ссылаться. ## См. также - [Блок resource: главный кирпич Terraform](/terraform/kb/tf-resource-block.md) - [Блок variable: вход в конфигурацию](/terraform/kb/tf-variable.md) - [locals: вычисляемые внутренние имена](/terraform/kb/tf-locals.md) - [Блок output: что Terraform возвращает наружу](/terraform/kb/tf-output.md) - [count и for_each: несколько ресурсов из одного блока](/terraform/kb/tf-count-for-each.md)