跳至主要内容

机器可读 UI

默认情况下,许多 OpenTofu 命令将 UI 输出显示为非结构化文本,旨在通过终端模拟器供用户阅读。此文本流不是集成稳定接口。一些命令支持 -json 标志,该标志启用具有已定义接口的结构化 JSON 输出模式。

对于诸如 planapplyrefresh 之类的长时间运行的命令,-json 标志输出 JSON UI 消息流,每行一条。这些可以一次处理一条消息,集成软件可以根据需要过滤、组合或修改输出。

第一个输出的消息类型为 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:在渲染 UI 输出时始终为“tofu.ui”
  • @timestamp:输出消息时的 RFC3339 时间戳
  • type:定义此消息的类型并确定如何解释可能存在的其他键

将日志作为用户界面呈现的客户端应通过向用户呈现至少 @message 字段来处理意外的消息类型。

消息将在事件发生时作为事件发出以触发它们。这意味着与多个资源相关的消息可能会交错(如果 OpenTofu 以超过 1 的并发性运行)。resource 对象值 可用于链接有关单个资源的多个消息。

消息类型

支持以下消息类型

通用消息

操作结果

  • resource_drift:描述在 OpenTofu 之外对单个资源进行的检测到的更改
  • planned_change:描述对单个资源的计划更改
  • change_summary:所有计划或应用更改的摘要
  • outputs:所有根模块输出的列表

资源进度

  • apply_startapply_progressapply_completeapply_errored:一系列消息,指示单个资源在应用过程中的进度
  • provision_startprovision_progressprovision_completeprovision_errored:一系列消息,指示单个供应程序步骤的进度
  • refresh_startrefresh_complete:一系列消息,指示单个资源在刷新过程中的进度

版本消息

机器可读 UI 命令输出将始终以 version 消息开头。定义了以下特定于消息的键

  • tofu:发出此消息的 OpenTofu 版本
  • ui:定义以下消息含义的机器可读 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 将为在 OpenTofu 之外发生更改的每个资源发出 resource_drift 消息。此消息包含一个嵌入式 change 对象,其中包含以下键

  • resource:描述要更改的资源地址的对象;有关详细信息,请参阅下面的 资源对象
  • action:计划对资源采取的操作。值:updatedelete

此消息不包含导致计划更改的确切更改的详细信息。该信息可在 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:计划对资源采取的操作。取值:noopcreatereadupdatereplacedeletemove
  • reason:更改的可选原因,仅在操作为replacedelete时使用。取值
    • tainted:资源被标记为受污染的
    • requested:用户请求替换资源,例如通过-replace计划标志
    • cannot_update:配置更改强制删除并创建资源,而不是更新
    • delete_because_no_resource_config:配置中没有匹配的资源
    • delete_because_wrong_repetition:资源实例键在配置中没有对应的countfor_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:要销毁的资源数量(包括作为替换的一部分)
  • operationplanapplydestroy之一

示例

代码块
{
"@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:对于计划输出,将对输出采取的操作。取值:noopcreateupdatedelete
  • value:对于应用输出,输出的数值,以 JSON 编码
  • type:对于应用输出,检测到的输出值的 HCL 类型
  • sensitive:布尔值,如果输出是敏感的并且默认情况下应从 UI 中隐藏,则为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:开始执行供应程序步骤时
  • provision_progress:在供应程序输出时
  • provision_complete:成功供应时
  • provision_errored:供应过程中遇到错误时
  • refresh_start:在刷新期间读取资源时
  • refresh_complete:刷新成功时

这些消息中的每一个都具有一个hook对象,该对象对于每种类型具有不同的字段。所有钩子都有一个resource对象,用于识别哪个资源是操作的主体。

应用开始

apply_start消息的hook对象具有以下键

  • resource:一个resource对象,用于识别资源
  • action:要对资源采取的操作。取值:noopcreatereadupdatereplacedelete
  • id_keyid_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"
}

应用进度

apply_progress消息的hook对象具有以下键

  • resource:一个resource对象,用于识别资源
  • action:对资源执行的操作。取值:noopcreatereadupdatereplacedelete
  • 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"
}

应用完成

apply_complete消息的hook对象具有以下键

  • resource:一个resource对象,用于识别资源
  • action:对资源采取的操作。取值:noopcreatereadupdatereplacedelete
  • id_keyid_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"
}

应用出错

apply_complete消息的hook对象具有以下键

  • resource:一个resource对象,用于识别资源
  • action:对资源采取的操作。取值:noopcreatereadupdatereplacedelete
  • 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"
}

供应开始

provision_start消息的hook对象具有以下键

  • resource:一个resource对象,用于识别资源
  • 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"
}

供应进度

provision_progress消息的hook对象具有以下键

  • resource:一个resource对象,用于识别资源
  • provisioner:供应程序的类型
  • output:供应程序的输出日志

从供应程序接收到的每个日志行都会输出一条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"
}

供应完成

provision_complete消息的hook对象具有以下键

  • resource:一个resource对象,用于识别资源
  • 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"
}

供应出错

provision_errored消息的hook对象具有以下键

  • resource:一个resource对象,用于识别资源
  • 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"
}

刷新开始

refresh_start消息的hook对象具有以下键

  • resource:一个resource对象,用于识别资源
  • id_keyid_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"
}

刷新完成

refresh_complete消息的hook对象具有以下键

  • resource:一个resource对象,用于识别资源
  • id_keyid_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:地址键(countfor_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"
}