Машиночитаемый интерфейс
По умолчанию многие команды OpenTofu отображают данные интерфейса в виде неструктурированного текста, предназначенного для чтения пользователем в эмуляторе терминала. Этот поток текста не является стабильным интерфейсом для интеграций. Некоторые команды поддерживают флаг -json, который включает режим структурированного вывода в формате JSON с определённым интерфейсом.
Для длительно выполняющихся команд, таких как plan, apply и refresh, флаг -json выводит поток сообщений интерфейса в формате JSON, по одному сообщению в строке. Их можно обрабатывать по одному сообщению, а интегрирующее программное обеспечение может фильтровать, объединять или изменять вывод по своему усмотрению.
Первое выводимое сообщение имеет тип version и содержит ключ ui со значением "1.0". Семантика этой версии такова:
- Для обратно совместимых изменений и дополнений мы будем увеличивать младшую версию, например
"1.1". Чтобы сохранить прямую совместимость с будущими младшими версиями, игнорируйте свойства объектов с неизвестными именами. - Для изменений, нарушающих обратную совместимость, мы будем увеличивать старшую версию, например
"2.0". Отклоняйте любые входные данные, в которых указана неподдерживаемая старшая версия.
Мы будем вводить новые старшие версии только в рамках гарантий совместимости OpenTofu 1.0.
Пример вывода JSON
Ниже приведён пример вывода команды tofu apply -json:
{"@level":"info","@message":"OpenTofu 1.6.0","@module":"tofu.ui","@timestamp":"2021-05-25T13:32:41.275359-04:00","tofu":"0.15.4","type":"version","ui":"0.1.0"}
{"@level":"info","@message":"random_pet.animal: Plan to create","@module":"tofu.ui","@timestamp":"2021-05-25T13:32:41.705503-04:00","change":{"resource":{"addr":"random_pet.animal","module":"","resource":"random_pet.animal","implied_provider":"random","resource_type":"random_pet","resource_name":"animal","resource_key":null},"action":"create"},"type":"planned_change"}
{"@level":"info","@message":"Plan: 1 to add, 0 to change, 0 to destroy.","@module":"tofu.ui","@timestamp":"2021-05-25T13:32:41.705638-04:00","changes":{"add":1,"change":0,"remove":0,"operation":"plan"},"type":"change_summary"}
{"@level":"info","@message":"random_pet.animal: Creating...","@module":"tofu.ui","@timestamp":"2021-05-25T13:32:41.825308-04:00","hook":{"resource":{"addr":"random_pet.animal","module":"","resource":"random_pet.animal","implied_provider":"random","resource_type":"random_pet","resource_name":"animal","resource_key":null},"action":"create"},"type":"apply_start"}
{"@level":"info","@message":"random_pet.animal: Creation complete after 0s [id=smart-lizard]","@module":"tofu.ui","@timestamp":"2021-05-25T13:32:41.826179-04:00","hook":{"resource":{"addr":"random_pet.animal","module":"","resource":"random_pet.animal","implied_provider":"random","resource_type":"random_pet","resource_name":"animal","resource_key":null},"action":"create","id_key":"id","id_value":"smart-lizard","elapsed_seconds":0},"type":"apply_complete"}
{"@level":"info","@message":"Apply complete! Resources: 1 added, 0 changed, 0 destroyed.","@module":"tofu.ui","@timestamp":"2021-05-25T13:32:41.869168-04:00","changes":{"add":1,"change":0,"remove":0,"operation":"apply"},"type":"change_summary"}
{"@level":"info","@message":"Outputs: 1","@module":"tofu.ui","@timestamp":"2021-05-25T13:32:41.869280-04:00","outputs":{"pets":{"sensitive":false,"type":"string","value":"smart-lizard"}},"type":"outputs"}Каждая строка содержит объект JSON с несколькими ключами, общими для всех сообщений. Это:
-
@level: обычно имеет значение "info", но при отображении диагностических сообщений может иметь значение "error" или "warn" -
@message: понятное человеку краткое описание содержимого этого сообщения -
@module: при отображении вывода интерфейса всегда имеет значение "tofu.ui" -
@timestamp: метка времени RFC3339, указывающая, когда было выведено сообщение -
type: определяет тип сообщения и способ интерпретации других присутствующих ключей
Клиенты, отображающие журналы как пользовательский интерфейс, должны обрабатывать неожиданные типы сообщений, показывая пользователю как минимум поле @message.
Сообщения выводятся по мере возникновения соответствующих событий. Это означает, что сообщения, относящиеся к нескольким ресурсам, могут перемежаться (если OpenTofu выполняется с параллелизмом больше 1). Значение объекта resource можно использовать для связывания нескольких сообщений об одном ресурсе.
Типы сообщений
Поддерживаются следующие типы сообщений:
Общие сообщения
-
version: сведения о версии OpenTofu и версии схемы, используемой для следующих сообщений -
log: неструктурированные понятные человеку строки журнала -
diagnostic: диагностические предупреждения или сообщения об ошибках; подробнее о формате см. в документацииtofu validate
Результаты операций
-
resource_drift: описывает обнаруженное изменение отдельного ресурса, выполненное вне OpenTofu -
planned_change: описывает запланированное изменение отдельного ресурса -
change_summary: сводка всех запланированных или применённых изменений -
outputs: список всех выходных данных корневого модуля
Ход выполнения операций с ресурсами
-
apply_start,apply_progress,apply_complete,apply_errored: последовательность сообщений, показывающих ход применения изменений для отдельного ресурса -
provision_start,provision_progress,provision_complete,provision_errored: последовательность сообщений, показывающих ход выполнения отдельного шага provisioner -
refresh_start,refresh_complete: последовательность сообщений, показывающих ход обновления состояния отдельного ресурса
Сообщение о версии
Вывод команды с машиночитаемым интерфейсом всегда начинается с сообщения version. Для этого типа сообщения определены следующие ключи:
-
tofu: версия OpenTofu, создавшая это сообщение -
ui: версия схемы машиночитаемого интерфейса, определяющая значение последующих сообщений
Пример
{
"@level": "info",
"@message": "OpenTofu 0.15.4",
"@module": "tofu.ui",
"@timestamp": "2021-05-25T13:32:41.275359-04:00",
"tofu": "0.15.4",
"type": "version",
"ui": "0.1.0"
}Расхождение состояния ресурса
Если при планировании обнаружено расхождение состояния, OpenTofu выдаст сообщение resource_drift для каждого ресурса, изменённого вне OpenTofu. Это сообщение содержит встроенный объект change со следующими ключами:
-
resource: объект с описанием адреса изменяемого ресурса; подробности см. ниже в разделе «Объект ресурса» -
action: действие, запланированное для ресурса. Значения:update,delete.
Это сообщение не содержит сведений о точных изменениях, из-за которых было запланировано изменение. Эта информация доступна в выводе плана в формате JSON.
Пример
{
"@level": "info",
"@message": "random_pet.animal: Drift detected (update)",
"@module": "tofu.ui",
"@timestamp": "2021-05-25T13:32:41.705503-04:00",
"change": {
"resource": {
"addr": "random_pet.animal",
"module": "",
"resource": "random_pet.animal",
"implied_provider": "random",
"resource_type": "random_pet",
"resource_name": "animal",
"resource_key": null
},
"action": "update"
},
"type": "resource_drift"
}Запланированное изменение
В конце планирования или перед применением изменений OpenTofu выдаст сообщение planned_change для каждого ресурса, изменения которого необходимо применить. Это сообщение содержит встроенный объект change со следующими ключами:
-
resource: объект с описанием адреса изменяемого ресурса; подробности см. ниже в разделе «Объект ресурса» -
previous_resource: объект с описанием предыдущего адреса ресурса, если это изменение включает перемещение, заданное конфигурацией -
action: действие, запланированное для ресурса. Значения:noop,create,read,update,replace,delete,move. -
reason: необязательная причина изменения, указываемая только если действие —replaceилиdelete. Значения:-
tainted: ресурс помечен как повреждённый -
requested: пользователь запросил замену ресурса, например с помощью флага плана-replace -
cannot_update: изменения конфигурации требуют удалить и создать ресурс вместо его обновления -
delete_because_no_resource_config: в конфигурации нет соответствующего ресурса -
delete_because_wrong_repetition: ключ экземпляра ресурса не соответствуетcountилиfor_eachв конфигурации -
delete_because_count_index: ключ экземпляра ресурса выходит за пределы диапазона аргументаcount -
delete_because_each_key: ключ экземпляра ресурса не включён в аргументfor_each -
delete_because_no_module: содержащий его экземпляр модуля отсутствует в конфигурации
-
Это сообщение не содержит сведений о точных изменениях, из-за которых было запланировано изменение. Эта информация доступна в выводе плана в формате JSON.
Пример
{
"@level": "info",
"@message": "random_pet.animal: Plan to create",
"@module": "tofu.ui",
"@timestamp": "2021-05-25T13:32:41.705503-04:00",
"change": {
"resource": {
"addr": "random_pet.animal",
"module": "",
"resource": "random_pet.animal",
"implied_provider": "random",
"resource_type": "random_pet",
"resource_name": "animal",
"resource_key": null
},
"action": "create"
},
"type": "planned_change"
}Сводка изменений
По завершении операции планирования или применения OpenTofu выводит сводку изменений. Оба типа сообщений содержат объект changes со следующими ключами:
-
add: количество создаваемых ресурсов (в том числе при замене) -
change: количество ресурсов, изменяемых на месте -
remove: количество удаляемых ресурсов (в том числе при замене) -
operation: одно из значенийplan,applyилиdestroy
Пример
{
"@level": "info",
"@message": "Apply complete! Resources: 1 added, 0 changed, 0 destroyed.",
"@module": "tofu.ui",
"@timestamp": "2021-05-25T13:32:41.869168-04:00",
"changes": {
"add": 1,
"change": 0,
"remove": 0,
"operation": "apply"
},
"type": "change_summary"
}Выходные данные
После успешного планирования или применения сообщение типа outputs содержит значения всех выходных данных корневого модуля. Сообщение содержит объект outputs, ключами которого являются имена выходных данных. Значения выходных данных — это объекты со следующими ключами:
-
action: для запланированных выходных данных — действие, которое будет выполнено. Значения:noop,create,update,delete -
value: для применённых выходных данных — значение выходных данных в формате JSON -
type: для применённых выходных данных — определённый тип HCL значения выходных данных -
sensitive: логическое значениеtrue, если выходные данные являются конфиденциальными и по умолчанию должны быть скрыты в интерфейсе
Обратите внимание: выходные данные sensitive по-прежнему содержат поле value, и интегрирующее программное обеспечение должно учитывать уровень конфиденциальности в соответствии с конкретным сценарием использования.
Пример
{
"@level": "info",
"@message": "Outputs: 1",
"@module": "tofu.ui",
"@timestamp": "2021-05-25T13:32:41.869280-04:00",
"outputs": {
"pets": {
"sensitive": false,
"type": "string",
"value": "smart-lizard"
}
},
"type": "outputs"
}Сообщения об операциях
Выполнение операций OpenTofu с ресурсом часто приводит к выводу нескольких сообщений. К ним относятся:
-
apply_start: начало применения изменений для ресурса -
apply_progress: периодический вывод прошедшего времени -
apply_complete: успешное завершение операции -
apply_errored: обнаружение ошибки во время операции -
provision_start: начало шага provisioner -
provision_progress: вывод provisioner -
provision_complete: успешное выполнение provisioner -
provision_errored: обнаружение ошибки во время выполнения provisioner -
refresh_start: чтение ресурса при обновлении состояния -
refresh_complete: успешное обновление состояния
Каждое из этих сообщений содержит объект hook с полями, различающимися в зависимости от типа сообщения. Все обработчики содержат объект resource, указывающий, к какому ресурсу относится операция.
Начало применения
Объект hook сообщения apply_start содержит следующие ключи:
-
resource: объектresource, идентифицирующий ресурс -
action: действие, которое будет выполнено для ресурса. Значения:noop,create,read,update,replace,delete -
id_keyиid_value: пара ключ-значение для идентификации экземпляра ресурса; не указывается, если значение неизвестно
Пример
{
"@level": "info",
"@message": "random_pet.animal: Creating...",
"@module": "tofu.ui",
"@timestamp": "2021-05-25T13:32:41.825308-04:00",
"hook": {
"resource": {
"addr": "random_pet.animal",
"module": "",
"resource": "random_pet.animal",
"implied_provider": "random",
"resource_type": "random_pet",
"resource_name": "animal",
"resource_key": null
},
"action": "create"
},
"type": "apply_start"
}Ход применения
Объект hook сообщения apply_progress содержит следующие ключи:
-
resource: объектresource, идентифицирующий ресурс -
action: выполняемое действие для ресурса. Значения:noop,create,read,update,replace,delete -
elapsed_seconds: время, прошедшее с начала операции применения, в виде целого числа секунд
Пример
{
"@level": "info",
"@message": "null_resource.none[4]: Still creating... [30s elapsed]",
"@module": "tofu.ui",
"@timestamp": "2021-03-17T09:34:26.222465-04:00",
"hook": {
"resource": {
"addr": "null_resource.none[4]",
"module": "",
"resource": "null_resource.none[4]",
"implied_provider": "null",
"resource_type": "null_resource",
"resource_name": "none",
"resource_key": 4
},
"action": "create",
"elapsed_seconds": 30
},
"type": "apply_progress"
}Применение завершено
Объект hook сообщения apply_complete содержит следующие ключи:
-
resource: объектresource, идентифицирующий ресурс -
action: выполненное действие для ресурса. Значения:noop,create,read,update,replace,delete -
id_keyиid_value: пара ключ-значение для идентификации экземпляра ресурса; не указывается, если значение неизвестно -
elapsed_seconds: время, прошедшее с начала операции применения, в виде целого числа секунд
Пример
{
"@level": "info",
"@message": "random_pet.animal: Creation complete after 0s [id=smart-lizard]",
"@module": "tofu.ui",
"@timestamp": "2021-05-25T13:32:41.826179-04:00",
"hook": {
"resource": {
"addr": "random_pet.animal",
"module": "",
"resource": "random_pet.animal",
"implied_provider": "random",
"resource_type": "random_pet",
"resource_name": "animal",
"resource_key": null
},
"action": "create",
"id_key": "id",
"id_value": "smart-lizard",
"elapsed_seconds": 0
},
"type": "apply_complete"
}Ошибка при применении
Объект hook сообщения apply_complete содержит следующие ключи:
-
resource: объектresource, идентифицирующий ресурс -
action: выполненное действие для ресурса. Значения:noop,create,read,update,replace,delete -
elapsed_seconds: время, прошедшее с начала операции применения, в виде целого числа секунд
Подробное описание ошибки будет выведено в отдельном сообщении diagnostic.
Пример
{
"@level": "info",
"@message": "null_resource.none[0]: Creation errored after 10s",
"@module": "tofu.ui",
"@timestamp": "2021-03-26T16:38:54.013910-04:00",
"hook": {
"resource": {
"addr": "null_resource.none[0]",
"module": "",
"resource": "null_resource.none[0]",
"implied_provider": "null",
"resource_type": "null_resource",
"resource_name": "none",
"resource_key": 0
},
"action": "create",
"elapsed_seconds": 10
},
"type": "apply_errored"
}Начало provisioner
Объект hook сообщения provision_start содержит следующие ключи:
-
resource: объектresource, идентифицирующий ресурс -
provisioner: тип provisioner
Пример
{
"@level": "info",
"@message": "null_resource.none[0]: Provisioning with 'local-exec'...",
"@module": "tofu.ui",
"@timestamp": "2021-03-26T16:38:43.997431-04:00",
"hook": {
"resource": {
"addr": "null_resource.none[0]",
"module": "",
"resource": "null_resource.none[0]",
"implied_provider": "null",
"resource_type": "null_resource",
"resource_name": "none",
"resource_key": 0
},
"provisioner": "local-exec"
},
"type": "provision_start"
}Ход выполнения provisioner
Объект hook сообщения provision_progress содержит следующие ключи:
-
resource: объектresource, идентифицирующий ресурс -
provisioner: тип provisioner -
output: журнал вывода provisioner
Для каждой полученной от provisioner строки журнала выводится отдельное сообщение provision_progress.
Пример
{
"@level": "info",
"@message": "null_resource.none[0]: (local-exec): Executing: [\"/bin/sh\" \"-c\" \"sleep 10 && exit 1\"]",
"@module": "tofu.ui",
"@timestamp": "2021-03-26T16:38:43.997869-04:00",
"hook": {
"resource": {
"addr": "null_resource.none[0]",
"module": "",
"resource": "null_resource.none[0]",
"implied_provider": "null",
"resource_type": "null_resource",
"resource_name": "none",
"resource_key": 0
},
"provisioner": "local-exec",
"output": "Executing: [\"/bin/sh\" \"-c\" \"sleep 10 && exit 1\"]"
},
"type": "provision_progress"
}Provisioner завершён
Объект hook сообщения provision_complete содержит следующие ключи:
-
resource: объектresource, идентифицирующий ресурс -
provisioner: тип provisioner
Пример
{
"@level": "info",
"@message": "null_resource.none[0]: (local-exec) Provisioning complete",
"@module": "tofu.ui",
"@timestamp": "2021-03-17T09:34:06.239043-04:00",
"hook": {
"resource": {
"addr": "null_resource.none[0]",
"module": "",
"resource": "null_resource.none[0]",
"implied_provider": "null",
"resource_type": "null_resource",
"resource_name": "none",
"resource_key": 0
},
"provisioner": "local-exec"
},
"type": "provision_complete"
}Ошибка provisioner
Объект hook сообщения provision_errored содержит следующие ключи:
-
resource: объектresource, идентифицирующий ресурс -
provisioner: тип provisioner
Пример
{
"@level": "info",
"@message": "null_resource.none[0]: (local-exec) Provisioning errored",
"@module": "tofu.ui",
"@timestamp": "2021-03-26T16:38:54.013572-04:00",
"hook": {
"resource": {
"addr": "null_resource.none[0]",
"module": "",
"resource": "null_resource.none[0]",
"implied_provider": "null",
"resource_type": "null_resource",
"resource_name": "none",
"resource_key": 0
},
"provisioner": "local-exec"
},
"type": "provision_errored"
}Начало обновления состояния
Объект hook сообщения refresh_start содержит следующие ключи:
-
resource: объектresource, идентифицирующий ресурс -
id_keyиid_value: пара ключ-значение для идентификации экземпляра ресурса
Пример
{
"@level": "info",
"@message": "null_resource.none[0]: Refreshing state... [id=1971614370559474622]",
"@module": "tofu.ui",
"@timestamp": "2021-03-26T14:18:06.508915-04:00",
"hook": {
"resource": {
"addr": "null_resource.none[0]",
"module": "",
"resource": "null_resource.none[0]",
"implied_provider": "null",
"resource_type": "null_resource",
"resource_name": "none",
"resource_key": 0
},
"id_key": "id",
"id_value": "1971614370559474622"
},
"type": "refresh_start"
}Обновление состояния завершено
Объект hook сообщения refresh_complete содержит следующие ключи:
-
resource: объектresource, идентифицирующий ресурс -
id_keyиid_value: пара ключ-значение для идентификации экземпляра ресурса
Пример
{
"@level": "info",
"@message": "null_resource.none[0]: Refresh complete [id=1971614370559474622]",
"@module": "tofu.ui",
"@timestamp": "2021-03-26T14:18:06.509371-04:00",
"hook": {
"resource": {
"addr": "null_resource.none[0]",
"module": "",
"resource": "null_resource.none[0]",
"implied_provider": "null",
"resource_type": "null_resource",
"resource_name": "none",
"resource_key": 0
},
"id_key": "id",
"id_value": "1971614370559474622"
},
"type": "refresh_complete"
}Объект ресурса
Объект resource — это разложенная на составляющие структура, представляющая адрес ресурса в конфигурации. Она используется для определения ресурса, к которому относится конкретное сообщение. Объект содержит следующие ключи:
-
addr: полный уникальный адрес ресурса в виде строки -
module: адрес модуля, содержащего ресурс, в форматеmodule.foo.module.barили пустая строка для ресурса корневого модуля -
resource: адрес относительно модуля; для ресурсов корневого модуля совпадает сaddr -
resource_type: тип адресуемого ресурса -
resource_name: метка имени ресурса -
resource_key: ключ адреса (значениеcountилиfor_each) либоnull, если не используется ни один из них -
implied_provider: тип провайдера, подразумеваемый типом ресурса; он может не соответствовать провайдеру ресурса, если используются псевдонимы провайдеров
Пример
{
"addr": "module.pets.random_pet.pet[\"friend\"]",
"module": "module.pets",
"resource": "random_pet.pet[\"friend\"]",
"implied_provider": "random",
"resource_type": "random_pet",
"resource_name": "pet",
"resource_key": "friend"
}Сообщения о тестировании
Запуск тестов OpenTofu приводит к выводу нескольких сообщений. К ним относятся:
-
test_abstract: сводка по найденным тестовым файлам и тестам -
test_file: сводка по выполнению тестового файла -
test_run: сводка по выполнению тестов -
test_summary: сводка об общем статусе и статистике выполнения тестовых файлов
Общие сведения о тестах
Объект test_abstract сообщения test_abstract содержит динамические ключи, составленные из имени тестового файла:
-
main.tftest.hcl: список тестов, найденных в тестовом файле
Пример
{
"@level": "info",
"@message": "Found 1 file and 1 run block",
"@module": "tofu.ui",
"@timestamp": "2024-04-20T17:24:48.418126+10:00",
"test_abstract": {
"main.tftest.hcl": [
"test"
]
},
"type": "test_abstract"
}Тестовый файл
Объект test_file сообщения test_file содержит следующие ключи:
-
path: относительный путь к тестовому файлу -
status: общий статус выполнения тестов
Пример
{
"@level": "info",
"@message": "main.tftest.hcl... pass",
"@module": "tofu.ui",
"@testfile": "main.tftest.hcl",
"@timestamp": "2024-04-20T17:24:48.588473+10:00",
"test_file": {
"path": "main.tftest.hcl",
"status": "pass"
},
"type": "test_file"
}Запуск теста
Объект сообщения test_run test_run содержит следующие ключи:
-
path: относительный путь к файлу теста -
run: название выполненного теста -
status: общий статус выполнения тестов
Пример
{
"@level": "info",
"@message": " \"test\"... pass",
"@module": "tofu.ui",
"@testfile": "main.tftest.hcl",
"@testrun": "test",
"@timestamp": "2024-04-20T17:24:48.588519+10:00",
"test_run": {
"path": "main.tftest.hcl",
"run": "test",
"status": "pass"
},
"type": "test_run"
}Сводка по тестам
Объект сообщения test_summary test_summary содержит следующие ключи:
-
status: общий статус всех выполненных тестов -
passed: общее количество успешно пройденных тестов -
failed: общее количество тестов, завершившихся неудачей -
errored: общее количество тестов, завершившихся с ошибкой -
skipped: общее количество пропущенных тестов
Пример
{
"@level": "info",
"@message": "Success! 1 passed, 0 failed.",
"@module": "tofu.ui",
"@timestamp": "2024-04-20T17:24:48.716977+10:00",
"test_summary": {
"status": "pass",
"passed": 1,
"failed": 0,
"errored": 0,
"skipped": 0
},
"type": "test_summary"
}
Copyright (c) The OpenTofu Authors
Copyright (c) 2014 HashiCorp, Inc.
Mozilla Public License, version 2.0
https://opentofu.org/docs/v1.11/internals/machine-readable-ui/