Spec-Zone.ru › OpenTofu 1.10

Синтаксис конфигурации JSON

Большинство конфигураций OpenTofu записываются с использованием собственного синтаксиса языка OpenTofu, который разработан так, чтобы его было относительно легко читать и изменять.

OpenTofu также поддерживает альтернативный синтаксис, совместимый с JSON. Этот синтаксис полезен при программном создании частей конфигурации, поскольку для подготовки создаваемых файлов конфигурации можно использовать существующие библиотеки JSON.

Синтаксис JSON определяется через собственный синтаксис. Всё, что можно выразить с помощью собственного синтаксиса, можно также выразить с помощью синтаксиса JSON, но некоторые конструкции сложнее представить в JSON из-за ограничений грамматики JSON.

OpenTofu ожидает собственный синтаксис в файлах с суффиксом .tf или .tofu и синтаксис JSON в файлах с суффиксом .tf.json или .tofu.json.

Низкоуровневый синтаксис JSON, как и собственный синтаксис, определяется спецификацией под названием HCL. Для использования OpenTofu необязательно знать все детали синтаксиса HCL или его представления в JSON, поэтому на этой странице кратко изложены наиболее важные различия между собственным синтаксисом и синтаксисом JSON. Если вас интересуют подробности, полное описание синтаксиса JSON для HCL можно найти в спецификации.

Приоритет расширений​

Если в каталоге присутствуют файлы .tf.json и .tofu.json с одинаковым базовым именем, OpenTofu отдаёт приоритет файлу .tofu.json и игнорирует файл .tf.json. Например:

  • Если в одном каталоге существуют файлы foo.tf.json и foo.tofu.json, OpenTofu загрузит только foo.tofu.json и проигнорирует foo.tf.json.

Это гарантирует, что файлы .tofu.json всегда имеют приоритет над файлами .tf.json, если присутствуют оба варианта. Это может быть полезно авторам модулей, которые хотят, чтобы их модули поддерживали и OpenTofu, и Terraform.

Структура файла JSON​

В корне любой конфигурации OpenTofu на основе JSON находится объект JSON. Свойства этого объекта соответствуют типам блоков верхнего уровня языка OpenTofu. Например:

Блок кода
{
  "variable": {
    "example": {
      "default": "hello"
    }
  }
}

Каждое свойство объекта верхнего уровня должно соответствовать имени одного из ожидаемых типов блоков верхнего уровня. Типы блоков, для которых требуются метки, например variable выше, представлены вложенным объектом для каждого уровня метки. Для блоков resource требуются две метки, поэтому необходимо два уровня вложенности:

Блок кода
{
  "resource": {
    "aws_instance": {
      "example": {
        "instance_type": "t2.micro",
        "ami": "ami-abc123"
      }
    }
  }
}

После всех вложенных объектов, представляющих метки, ещё один вложенный объект представляет тело самого блока. В приведённых выше примерах заданы аргумент default для variable "example" и аргументы instance_type и ami для resource "aws_instance" "example".

Вместе приведённые выше два файла конфигурации эквивалентны следующим блокам в собственном синтаксисе:

Блок кода
variable "example" {
  default = "hello"
}

resource "aws_instance" "example" {
  instance_type = "t2.micro"
  ami           = "ami-abc123"
}

Для каждого типа блока верхнего уровня правила преобразования в JSON немного отличаются (см. приведённые ниже исключения для конкретных типов блоков), но в большинстве случаев применимы следующие общие правила:

  • Объект JSON, представляющий тело блока, содержит свойства, соответствующие либо именам аргументов, либо именам типов вложенных блоков.

  • Если свойство соответствует аргументу, принимающему произвольные выражения в собственном синтаксисе, значение свойства преобразуется в выражение, как описано ниже в разделе Преобразование выражений. Для аргументов, которые не принимают произвольные выражения, интерпретация значения свойства зависит от аргумента, как описано далее на этой странице в разделе исключений для конкретных типов блоков.

  • Если имя свойства соответствует имени ожидаемого типа вложенного блока, значение интерпретируется, как описано ниже в разделе Преобразование вложенных блоков, если далее на этой странице в разделе исключений для конкретных типов блоков не указано иное.

Преобразование выражений​

Поскольку грамматика JSON не позволяет представить весь синтаксис выражений языка OpenTofu, значения JSON, интерпретируемые как выражения, преобразуются следующим образом:

JSON Интерпретация в языке OpenTofu
Логическое значение Литеральное значение bool.
Число Литеральное значение number.
Строка Анализируется как шаблон строки, а затем вычисляется, как описано ниже.
Объект Значение каждого свойства преобразуется согласно этой таблице, в результате чего получается значение object(...) с подходящими типами атрибутов.
Массив Каждый элемент преобразуется согласно этой таблице, в результате чего получается значение tuple(...) с подходящими типами элементов.
Null Литеральное значение null.

Если строка JSON встречается в месте, где ожидаются произвольные выражения, её значение сначала анализируется как [шаблон строки][], а затем вычисляется для получения конечного результата.

Если заданный шаблон состоит только из одной последовательности интерполяции, результат выражения используется напрямую, без предварительного преобразования в строку. Это позволяет использовать в синтаксисе JSON выражения, результатом которых являются значения нестрокового типа:

Блок кода
{
  "output": {
    "example": {
      "value": "${aws_instance.example}"
    }
  }
}

Объявленная выше переменная output "example" имеет в качестве значения объект, представляющий указанный блок ресурса aws_instance, а не строковое значение. Это особое поведение не применяется, если в шаблоне присутствуют какие-либо литеральные последовательности или управляющие последовательности; в таких случаях всегда получается строковое значение.

Преобразование вложенных блоков​

Если свойство объекта JSON названо в соответствии с типом вложенного блока, его значение представляет один или несколько блоков этого типа. Значением свойства должен быть объект JSON или массив JSON.

Самый простой случай — представление одного блока заданного типа, если для этого типа не требуются метки, как в случае вложенного блока lifecycle, используемого в блоках resource:

Блок кода
{
  "resource": {
    "aws_instance": {
      "example": {
        "lifecycle": {
          "create_before_destroy": true
        }
      }
    }
  }
}

Приведённый выше пример эквивалентен следующей конфигурации на собственном синтаксисе:

Блок кода
resource "aws_instance" "example" {
  lifecycle {
    create_before_destroy = true
  }
}

Если для типа вложенного блока требуется одна или несколько меток либо можно указать несколько блоков одного типа, преобразование становится немного сложнее. Например, для типа вложенного блока provisioner, используемого в блоках resource, требуется метка, указывающая используемый провижионер, а порядок блоков провижионеров имеет значение для определения порядка операций.

В следующем примере на собственном синтаксисе показан блок resource с несколькими провижионерами разных типов:

Блок кода
resource "aws_instance" "example" {
  # (resource configuration omitted for brevity)

  provisioner "local-exec" {
    command = "echo 'Hello World' >example.txt"
  }
  provisioner "file" {
    source      = "example.txt"
    destination = "/tmp/example.txt"
  }
  provisioner "remote-exec" {
    inline = [
      "sudo install-something -f /tmp/example.txt",
    ]
  }
}

Чтобы сохранить порядок этих блоков, необходимо использовать массив JSON в качестве непосредственного значения свойства, представляющего этот тип блока, как в следующем эквиваленте на JSON:

Блок кода
{
  "resource": {
    "aws_instance": {
      "example": {
        "provisioner": [
          {
            "local-exec": {
              "command": "echo 'Hello World' >example.txt"
            }
          },
          {
            "file": {
              "source": "example.txt",
              "destination": "/tmp/example.txt"
            }
          },
          {
            "remote-exec": {
              "inline": ["sudo install-something -f /tmp/example.txt"]
            }
          }
        ]
      }
    }
  }
}

Каждый элемент массива provisioner — это объект с одним свойством, имя которого представляет метку каждого блока provisioner. Для типов блоков, которым требуется несколько меток, этот шаблон чередования вложенных массивов и объектов можно использовать для каждого дополнительного уровня.

Если для типа вложенного блока требуются метки, но их порядок не имеет значения, массив можно опустить и указать только один объект, имена свойств которого соответствуют уникальным меткам блоков. В простых случаях это разрешено как сокращённая форма приведённого выше варианта, но чередование массивов и объектов является наиболее универсальным подходом. При систематическом преобразовании собственного синтаксиса в JSON рекомендуем использовать наиболее универсальную форму, чтобы точно сохранить смысл конфигурации.

Свойства-комментарии​

Хотя мы не рекомендуем редактировать файлы конфигурации на синтаксисе JSON вручную — этот формат предназначен главным образом для программного создания и обработки, — внутри объектов JSON, представляющих тела блоков, допускается ограниченная форма комментариев с использованием специального имени свойства:

Блок кода
{
  "resource": {
    "aws_instance": {
      "example": {
        "//": "This instance runs the scheduled tasks for backup",

        "instance_type": "t2.micro",
        "ami": "ami-abc123"
      }
    }
  }
}

В любом объекте, представляющем тело блока, свойства с именем "//" полностью игнорируются OpenTofu. Это исключение не применяется к объектам, которые интерпретируются как выражения: в этом случае свойство будет интерпретировано как атрибут типа объекта с именем "//".

Это специальное имя свойства также можно использовать в корне файла конфигурации на основе JSON. Это может быть полезно, чтобы указать, какая программа создала файл.

Блок кода
{
  "//": "This file is generated by generate-outputs.py. DO NOT HAND-EDIT!",

  "output": {
    "example": {
      "value": "${aws_instance.example}"
    }
  }
}

Исключения для конкретных типов блоков​

Некоторые аргументы в определённых типах блоков обрабатываются OpenTofu особым образом, поэтому их преобразование в синтаксис JSON не соответствует общим правилам, описанным выше. В следующих подразделах описаны специальные правила преобразования для каждого типа блока верхнего уровня.

Блоки resource и data​

Некоторые метааргументы типов блоков resource и data принимают прямые ссылки на объекты или литеральные ключевые слова. В представлении JSON ссылка или ключевое слово задаётся строкой JSON без окружающих пробелов или символов.

Например, метааргумент provider принимает ссылку <PROVIDER>.<ALIAS> на конфигурацию провайдера. В собственном синтаксисе она указывается без кавычек, а в синтаксисе JSON должна быть представлена строкой:

Блок кода
{
  "resource": {
    "aws_instance": {
      "example": {
        "provider": "aws.foo"
      }
    }
  }
}

Такая специальная обработка применяется к следующим метааргументам:

  • provider: одна строка, как показано выше
  • depends_on: массив строк, содержащих ссылки на именованные сущности, например ["aws_instance.example"].
  • ignore_changes в блоке lifecycle: если задано значение all, необходимо указать одну строку "all". В противном случае необходимо использовать массив строк JSON, содержащих ссылки на свойства, например ["ami"].

Специальная обработка также применяется к аргументу type любого блока connection, независимо от того, находится ли он непосредственно внутри блока resource или вложен в блоки provisioner: заданная строка интерпретируется буквально, а не анализируется и вычисляется как шаблон строки.

Блоки variable​

Все аргументы внутри блоков variable имеют нестандартное представление в JSON:

  • type: строка с выражением типа, например "string" или "list(string)".
  • default: литеральное значение JSON, которое можно преобразовать в заданный тип. Строки внутри этого значения воспринимаются буквально и не интерпретируются как шаблоны строк.
  • description: литеральная строка JSON, которая не интерпретируется как шаблон.
Блок кода
{
  "variable": {
    "example": {
      "type": "string",
      "default": "hello"
    }
  }
}

Блоки output​

Аргументы description и sensitive интерпретируются как литеральные значения JSON. Строка description не интерпретируется как шаблон строки.

Аргумент value интерпретируется как выражение.

Блок кода
{
  "output": {
    "example": {
      "value": "${aws_instance.example}"
    }
  }
}

Блоки locals​

Значением свойства объекта JSON, представляющего тип блока locals, должен быть объект JSON, имена свойств которого соответствуют объявляемым именам локальных значений:

Блок кода
{
  "locals": {
    "greeting": "Hello, ${var.name}"
  }
}

Значение каждого из этих вложенных свойств интерпретируется как выражение.

Блоки module​

Метааргумент providers должен быть задан как объект JSON, свойства которого представляют краткие адреса провайдеров, доступных дочернему модулю, а значения — адреса провайдеров, используемых текущим модулем; и те и другие задаются литеральными строками:

Блок кода
{
  "module": {
    "example": {
      "source": "hashicorp/consul/azurerm",
      "version": "= 1.0.0",
      "providers": {
        "aws": "aws.usw1"
      }
    }
  }
}

Блоки provider​

Метааргументы alias и version должны быть заданы литеральными строками. Значения не интерпретируются как шаблоны строк.

Блок кода
{
  "provider": {
    "aws": [
      {
        "region": "us-east-1"
      },
      {
        "alias": "usw1",
        "region": "us-west-1"
      }
    ]
  }
}

Блоки terraform​

Параметры внутри блоков terraform обычно интерпретируются буквально, за исключением блока backend, который поддерживает выражения. Другие параметры не принимают ссылки на именованные объекты или вызовы функций, поэтому строковые значения не обрабатываются как шаблоны строк.

Поскольку в каждом блоке terraform разрешён только один блок backend, для его представления можно использовать компактное отображение блока с вложенным объектом, содержащим одно свойство, имя которого соответствует типу бэкенда.

Блок кода
{
  "terraform": {
    "required_version": ">= 0.12.0",
    "backend": {
      "s3": {
        "region": "us-west-2",
        "bucket": "acme-tofu-states"
      }
    }
  }
}

Copyright (c) The OpenTofu Authors
Copyright (c) 2014 HashiCorp, Inc.
Mozilla Public License, version 2.0
https://opentofu.org/docs/v1.10/language/syntax/json/

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API