| --- |
| page_title: Machine-readable output reference |
| description: >- |
| Terraform streams machine-readable output in JSON format, letting you use third-party tools to monitor operations. |
| --- |
| |
| # Machine-readable UI Output Reference |
| |
| This topic provides reference information about the machine-readable output Terraform prints. |
| |
| ## Introduction |
| |
| By default, many Terraform commands display UI output as unstructured text that is intended to be read in a terminal emulator. This text stream is not a stable interface for integrations. Some commands support a `-json` flag, which enables a structured JSON output mode with a defined interface. |
| |
| For long-running commands such as `plan`, `apply`, `refresh`, and `test`, the `-json` flag outputs a stream of JSON UI messages. The ouptut messages appear one per line so that you can process the messages by integrating software filtering, combining, or modifying the output as desired. |
| |
| The first message output has type `version`, and includes a `ui` key, which as of Terraform 1.1.0 has |
| value `"1.0"`. The semantics of this version are: |
| |
| - We will increment the minor version, e.g. `"1.1"`, for backward-compatible |
| changes or additions. Ignore any object properties with unrecognized names to |
| remain forward-compatible with future minor versions. |
| - We will increment the major version, e.g. `"2.0"`, for changes that are not |
| backward-compatible. Reject any input which reports an unsupported major |
| version. |
| |
| Refer to |
| [Terraform 1.0 Compatibility Promises](/terraform/language/v1-compatibility-promises) for additional information. |
| |
| ## Sample JSON Output |
| |
| Below is sample output from running `terraform apply -json`: |
| |
| ```javascript |
| {"@level":"info","@message":"Terraform 0.15.4","@module":"terraform.ui","@timestamp":"2021-05-25T13:32:41.275359-04:00","terraform":"0.15.4","type":"version","ui":"0.1.0"} |
| {"@level":"info","@message":"random_pet.animal: Plan to create","@module":"terraform.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":"terraform.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":"terraform.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":"terraform.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":"terraform.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":"terraform.ui","@timestamp":"2021-05-25T13:32:41.869280-04:00","outputs":{"pets":{"sensitive":false,"type":"string","value":"smart-lizard"}},"type":"outputs"} |
| ``` |
| |
| Each line consists of a JSON object with several keys common to all messages. These are: |
| |
| - `@level`: this is normally "info", but can be "error" or "warn" when showing diagnostics |
| - `@message`: a human-readable summary of the contents of this message |
| - `@module`: always "terraform.ui" when rendering UI output |
| - `@timestamp`: an RFC3339 timestamp of when the message was output |
| - `type`: defines which kind of message this is and determines how to interpret other keys which may be present |
| |
| Clients presenting the logs as a user interface should handle unexpected message types by presenting at least the `@message` field to the user. |
| |
| Messages will be emitted as events occur to trigger them. This means that messages related to several resources may be interleaved (if Terraform is running with concurrency above 1). The [`resource` object value](#resource-object) can be used to link multiple messages about a single resource. |
| |
| ## Message Types |
| |
| The following message types are supported: |
| |
| ### Generic Messages |
| |
| - `version`: information about the Terraform version and the version of the schema used for the following messages |
| - `log`: unstructured human-readable log lines |
| - `diagnostic`: diagnostic warning or error messages; [see the `terraform validate` docs for more details on the format](/terraform/cli/commands/validate#json) |
| |
| ### Operation Results |
| |
| - `resource_drift`: describes a detected change to a single resource made outside of Terraform |
| - `planned_change`: describes a planned change to a single resource |
| - `change_summary`: summary of all planned or applied changes |
| - `outputs`: list of all root module outputs |
| |
| ### Resource Progress |
| |
| - `apply_start`, `apply_progress`, `apply_complete`, `apply_errored`: sequence of messages indicating progress of a single resource through apply |
| - `provision_start`, `provision_progress`, `provision_complete`, `provision_errored`: sequence of messages indicating progress of a single provisioner step |
| - `refresh_start`, `refresh_complete`: sequence of messages indicating progress of a single resource through refresh |
| |
| ### Test Results |
| |
| - `test_abstract`: describes the test operation that Terraform executes |
| - `test_file`: describes the status of a completed test file |
| - `test_run`: describes the status of a completed `run` block within a test file |
| - `test_cleanup`: describes the result of the test cleanup after a completed test file |
| - `test_summary`: describes the overall status of the completed test operation |
| - `test_plan`: describes the output of a given `run` block when `command = plan` |
| - `test_state`: describes the output of a given `run` block when `command = apply` |
| - `test_interrupt`: describes the result of an interrupted test operation |
| |
| ## Version Message |
| |
| A machine-readable UI command output will always begin with a `version` message. The following message-specific keys are defined: |
| |
| - `terraform`: the Terraform version which emitted this message |
| - `ui`: the machine-readable UI schema version defining the meaning of the following messages |
| |
| ### Example |
| |
| ```json |
| { |
| "@level": "info", |
| "@message": "Terraform 0.15.4", |
| "@module": "terraform.ui", |
| "@timestamp": "2021-05-25T13:32:41.275359-04:00", |
| "terraform": "0.15.4", |
| "type": "version", |
| "ui": "0.1.0" |
| } |
| ``` |
| |
| ## Resource Drift |
| |
| If drift is detected during planning, Terraform will emit a `resource_drift` message for each resource which has changed outside of Terraform. This message has an embedded `change` object with the following keys: |
| |
| - `resource`: object describing the address of the resource to be changed; see [resource object](#resource-object) below for details |
| - `action`: the action planned to be taken for the resource. Values: `update`, `delete`. |
| |
| This message does not include details about the exact changes which caused the change to be planned. That information is available in [the JSON plan output](/terraform/internals/json-format). |
| |
| ### Example |
| |
| ```json |
| { |
| "@level": "info", |
| "@message": "random_pet.animal: Drift detected (update)", |
| "@module": "terraform.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" |
| } |
| ``` |
| |
| ## Planned Change |
| |
| At the end of a plan or before an apply, Terraform will emit a `planned_change` message for each resource which has changes to apply. This message has an embedded `change` object with the following keys: |
| |
| - `resource`: object describing the address of the resource to be changed; see [resource object](#resource-object) below for details |
| - `previous_resource`: object describing the previous address of the resource, if this change includes a configuration-driven move |
| - `action`: the action planned to be taken for the resource. Values: `noop`, `create`, `read`, `update`, `replace`, `delete`, `move`, `import`. |
| - `reason`: an optional reason for the change, only used when the action is `replace` or `delete`. Values: |
| - `tainted`: resource was marked as tainted |
| - `requested`: user requested that the resource be replaced, for example via the `-replace` plan flag |
| - `cannot_update`: changes to configuration force the resource to be deleted and created rather than updated |
| - `delete_because_no_resource_config`: no matching resource in configuration |
| - `delete_because_wrong_repetition`: resource instance key has no corresponding `count` or `for_each` in configuration |
| - `delete_because_count_index`: resource instance key is outside the range of the `count` argument |
| - `delete_because_each_key`: resource instance key is not included in the `for_each` argument |
| - `delete_because_no_module`: enclosing module instance is not in configuration |
| |
| This message does not include details about the exact changes which caused the change to be planned. That information is available in [the JSON plan output](/terraform/internals/json-format). |
| |
| ### Example |
| |
| ```json |
| { |
| "@level": "info", |
| "@message": "random_pet.animal: Plan to create", |
| "@module": "terraform.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" |
| } |
| ``` |
| |
| ## Change Summary |
| |
| Terraform outputs a change summary when a plan or apply operation completes. Both message types include a `changes` object, which has the following keys: |
| |
| - `add`: count of resources to be created (including as part of replacement) |
| - `change`: count of resources to be changed in-place |
| - `remove`: count of resources to be destroyed (including as part of replacement) |
| - `operation`: one of `plan`, `apply`, or `destroy` |
| |
| ### Example |
| |
| ```json |
| { |
| "@level": "info", |
| "@message": "Apply complete! Resources: 1 added, 0 changed, 0 destroyed.", |
| "@module": "terraform.ui", |
| "@timestamp": "2021-05-25T13:32:41.869168-04:00", |
| "changes": { |
| "add": 1, |
| "change": 0, |
| "remove": 0, |
| "operation": "apply" |
| }, |
| "type": "change_summary" |
| } |
| ``` |
| |
| ## Outputs |
| |
| After a successful plan or apply, a message with type `outputs` contains the values of all root module output values. This message contains an `outputs` object, the keys of which are the output names. The outputs values are objects with the following keys: |
| |
| - `action`: for planned outputs, the action which will be taken for the output. Values: `noop`, `create`, `update`, `delete` |
| - `value`: for applied outputs, the value of the output, encoded in JSON |
| - `type`: for applied outputs, the detected HCL type of the output value |
| - `sensitive`: boolean value, `true` if the output is sensitive and should be hidden from UI by default |
| |
| Note that `sensitive` outputs still include the `value` field, and integrating software should respect the sensitivity value as appropriate for the given use case. |
| |
| ### Example |
| |
| ```json |
| { |
| "@level": "info", |
| "@message": "Outputs: 1", |
| "@module": "terraform.ui", |
| "@timestamp": "2021-05-25T13:32:41.869280-04:00", |
| "outputs": { |
| "pets": { |
| "sensitive": false, |
| "type": "string", |
| "value": "smart-lizard" |
| } |
| }, |
| "type": "outputs" |
| } |
| ``` |
| |
| ## Operation Messages |
| |
| Performing Terraform operations to a resource will often result in several messages being emitted. The message types include: |
| |
| - `apply_start`: when starting to apply changes for a resource |
| - `apply_progress`: periodically, showing elapsed time output |
| - `apply_complete`: on successful operation completion |
| - `apply_errored`: when an error is encountered during the operation |
| - `provision_start`: when starting a provisioner step |
| - `provision_progress`: on provisioner output |
| - `provision_complete`: on successful provisioning |
| - `provision_errored`: when an error is enountered during provisioning |
| - `refresh_start`: when reading a resource during refresh |
| - `refresh_complete`: on successful refresh |
| - `ephemeral_op_start`: when starting an ephemeral resource operation |
| - `ephemeral_op_progress`: periodically showing elapsed time output during ephemeral resource operation |
| - `ephemeral_op_complete`: on successful ephemeral resource operation completion |
| - `ephemeral_op_errored`: when an error is encountered during ephemeral resource operation |
| |
| Each of these messages has a `hook` object, which has different fields for each type. All hooks have a [`resource` object](#resource-object) which identifies which resource is the subject of the operation. |
| |
| ## Apply Start |
| |
| The `apply_start` message `hook` object has the following keys: |
| |
| - `resource`: a [`resource` object](#resource-object) identifying the resource |
| - `action`: the action to be taken for the resource. Values: `noop`, `create`, `read`, `update`, `replace`, `delete` |
| - `id_key` and `id_value`: a key/value pair used to identify this instance of the resource, omitted when unknown |
| |
| ### Example |
| |
| ```json |
| { |
| "@level": "info", |
| "@message": "random_pet.animal: Creating...", |
| "@module": "terraform.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 |
| |
| The `apply_progress` message `hook` object has the following keys: |
| |
| - `resource`: a [`resource` object](#resource-object) identifying the resource |
| - `action`: the action being taken for the resource. Values: `noop`, `create`, `read`, `update`, `replace`, `delete` |
| - `elapsed_seconds`: time elapsed since the apply operation started, expressed as an integer number of seconds |
| |
| ### Example |
| |
| ```json |
| { |
| "@level": "info", |
| "@message": "null_resource.none[4]: Still creating... [30s elapsed]", |
| "@module": "terraform.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 |
| |
| The `apply_complete` message `hook` object has the following keys: |
| |
| - `resource`: a [`resource` object](#resource-object) identifying the resource |
| - `action`: the action taken for the resource. Values: `noop`, `create`, `read`, `update`, `replace`, `delete` |
| - `id_key` and `id_value`: a key/value pair used to identify this instance of the resource, omitted when unknown |
| - `elapsed_seconds`: time elapsed since the apply operation started, expressed as an integer number of seconds |
| |
| ### Example |
| |
| ```json |
| { |
| "@level": "info", |
| "@message": "random_pet.animal: Creation complete after 0s [id=smart-lizard]", |
| "@module": "terraform.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 Errored |
| |
| The `apply_complete` message `hook` object has the following keys: |
| |
| - `resource`: a [`resource` object](#resource-object) identifying the resource |
| - `action`: the action taken for the resource. Values: `noop`, `create`, `read`, `update`, `replace`, `delete` |
| - `elapsed_seconds`: time elapsed since the apply operation started, expressed as an integer number of seconds |
| |
| The exact detail of the error will be rendered as a separate `diagnostic` message. |
| |
| ### Example |
| |
| ```json |
| { |
| "@level": "info", |
| "@message": "null_resource.none[0]: Creation errored after 10s", |
| "@module": "terraform.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 |
| |
| The `provision_start` message `hook` object has the following keys: |
| |
| - `resource`: a [`resource` object](#resource-object) identifying the resource |
| - `provisioner`: the type of provisioner |
| |
| ### Example |
| |
| ```json |
| { |
| "@level": "info", |
| "@message": "null_resource.none[0]: Provisioning with 'local-exec'...", |
| "@module": "terraform.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 |
| |
| The `provision_progress` message `hook` object has the following keys: |
| |
| - `resource`: a [`resource` object](#resource-object) identifying the resource |
| - `provisioner`: the type of provisioner |
| - `output`: the output log from the provisioner |
| |
| One `provision_progress` message is output for each log line received from the provisioner. |
| |
| ### Example |
| |
| ```json |
| { |
| "@level": "info", |
| "@message": "null_resource.none[0]: (local-exec): Executing: [\"/bin/sh\" \"-c\" \"sleep 10 && exit 1\"]", |
| "@module": "terraform.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 |
| |
| The `provision_complete` message `hook` object has the following keys: |
| |
| - `resource`: a [`resource` object](#resource-object) identifying the resource |
| - `provisioner`: the type of provisioner |
| |
| ### Example |
| |
| ```json |
| { |
| "@level": "info", |
| "@message": "null_resource.none[0]: (local-exec) Provisioning complete", |
| "@module": "terraform.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 |
| |
| The `provision_errored` message `hook` object has the following keys: |
| |
| - `resource`: a [`resource` object](#resource-object) identifying the resource |
| - `provisioner`: the type of provisioner |
| |
| ### Example |
| |
| ```json |
| { |
| "@level": "info", |
| "@message": "null_resource.none[0]: (local-exec) Provisioning errored", |
| "@module": "terraform.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 |
| |
| The `refresh_start` message `hook` object has the following keys: |
| |
| - `resource`: a [`resource` object](#resource-object) identifying the resource |
| - `id_key` and `id_value`: a key/value pair used to identify this instance of the resource |
| |
| ### Example |
| |
| ```json |
| { |
| "@level": "info", |
| "@message": "null_resource.none[0]: Refreshing state... [id=1971614370559474622]", |
| "@module": "terraform.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 |
| |
| The `refresh_complete` message `hook` object has the following keys: |
| |
| - `resource`: a [`resource` object](#resource-object) identifying the resource |
| - `id_key` and `id_value`: a key/value pair used to identify this instance of the resource |
| |
| ### Example |
| |
| ```json |
| { |
| "@level": "info", |
| "@message": "null_resource.none[0]: Refresh complete [id=1971614370559474622]", |
| "@module": "terraform.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" |
| } |
| ``` |
| |
| ## Ephemeral Operation Start |
| |
| The `ephemeral_op_start` message `hook` object has the following keys: |
| |
| - `resource`: a [`resource` object](#resource-object) identifying the resource |
| - `action`: the action the ephemeral resource is going through. Values: `open`, `renew`, `close` |
| |
| ### Example |
| |
| ```json |
| { |
| "@level": "info", |
| "@message": "ephemeral.random_password.example: Opening...", |
| "@module": "terraform.ui", |
| "@timestamp": "2024-10-30T10:34:26.222465-00:00", |
| "hook": { |
| "resource": { |
| "addr": "ephemeral.random_password.example", |
| "module": "", |
| "resource": "ephemeral.random_password.example", |
| "implied_provider": "random", |
| "resource_type": "random_password", |
| "resource_name": "example", |
| "resource_key": null |
| }, |
| "action": "open" |
| }, |
| "type": "ephemeral_op_start" |
| } |
| ``` |
| |
| ## Ephemeral Operation Progress |
| |
| The `ephemeral_op_progress` message `hook` object has the following keys: |
| |
| - `resource`: a [`resource` object](#resource-object) identifying the resource |
| - `action`: the action the ephemeral resource is going through. Values: `open`, `renew`, `close` |
| - `elapsed_seconds`: time elapsed since the operation started, expressed as an integer number of seconds |
| |
| ### Example |
| |
| ```json |
| { |
| "@level": "info", |
| "@message": "ephemeral.random_password.example: Closing... [3s elapsed]", |
| "@module": "terraform.ui", |
| "@timestamp": "2024-10-30T10:34:26.222465-00:00", |
| "hook": { |
| "resource": { |
| "addr": "ephemeral.random_password.example", |
| "module": "", |
| "resource": "ephemeral.random_password.example", |
| "implied_provider": "random", |
| "resource_type": "random_password", |
| "resource_name": "example", |
| "resource_key": null |
| }, |
| "action": "close", |
| "elapsed_seconds": 3 |
| }, |
| "type": "ephemeral_op_progress" |
| } |
| ``` |
| |
| ## Ephemeral Operation Complete |
| |
| The `ephemeral_op_start` message `hook` object has the following keys: |
| |
| - `resource`: a [`resource` object](#resource-object) identifying the resource |
| - `action`: the action the ephemeral resource is going through. Values: `open`, `renew`, `close` |
| - `elapsed_seconds`: time elapsed since the operation started, expressed as an integer number of seconds |
| |
| ### Example |
| |
| ```json |
| { |
| "@level": "info", |
| "@message": "ephemeral.random_password.example: Opening complete after 1s", |
| "@module": "terraform.ui", |
| "@timestamp": "2024-10-30T10:34:26.222465-00:00", |
| "hook": { |
| "resource": { |
| "addr": "ephemeral.random_password.example", |
| "module": "", |
| "resource": "ephemeral.random_password.example", |
| "implied_provider": "random", |
| "resource_type": "random_password", |
| "resource_name": "example", |
| "resource_key": null |
| }, |
| "action": "open", |
| "elapsed_seconds": 1 |
| }, |
| "type": "ephemeral_op_complete" |
| } |
| ``` |
| |
| ## Ephemeral Operation Errored |
| |
| The `ephemeral_op_start` message `hook` object has the following keys: |
| |
| - `resource`: a [`resource` object](#resource-object) identifying the resource |
| - `action`: the action the ephemeral resource is going through. Values: `open`, `renew`, `close` |
| - `elapsed_seconds`: time elapsed since the operation started, expressed as an integer number of seconds |
| |
| The exact detail of the error will be rendered as a separate `diagnostic` message. |
| |
| ### Example |
| |
| ```json |
| { |
| "@level": "info", |
| "@message": "ephemeral.random_password.example: Opening errored after 2s", |
| "@module": "terraform.ui", |
| "@timestamp": "2024-10-30T10:34:26.222465-00:00", |
| "hook": { |
| "resource": { |
| "addr": "ephemeral.random_password.example", |
| "module": "", |
| "resource": "ephemeral.random_password.example", |
| "implied_provider": "random", |
| "resource_type": "random_password", |
| "resource_name": "example", |
| "resource_key": null |
| }, |
| "action": "open", |
| "elapsed_seconds": 2 |
| }, |
| "type": "ephemeral_op_errored" |
| } |
| ``` |
| |
| ## Resource Object |
| |
| The `resource` object is a decomposed structure representing a resource address in configuration, which is used to identify which resource a given message is associated with. The object has the following keys: |
| |
| - `addr`: the full unique address of the resource as a string |
| - `module`: the address of the module containing the resource, in the form `module.foo.module.bar`, or an empty string for a root module resource |
| - `resource`: the module-relative address, which is identical to `addr` for root module resources |
| - `resource_type`: the type of resource being addressed |
| - `resource_name`: the name label for the resource |
| - `resource_key`: the address key (`count` or `for_each` value), or `null` if the neither are used |
| - `implied_provider`: the provider type implied by the resource type; this may not reflect the resource's provider if provider aliases are used |
| |
| ### Example |
| |
| ```json |
| { |
| "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" |
| } |
| ``` |
| |
| ## Test Abstract |
| |
| The `terraform test` command emits a `test_abstract` message describing the test files and `run` blocks that Terraform executes during the upcoming operation. |
| |
| ### Example |
| |
| ```json |
| { |
| "@level": "info", |
| "@message": "Found 1 file and 2 run blocks", |
| "@module": "terraform.ui", |
| "@timestamp": "2023-08-09T16:12:30.325582+02:00", |
| "test_abstract": { |
| "validation.tftest.hcl": [ |
| "passed_validation", |
| "failed_validatation" |
| ] |
| }, |
| "type": "test_abstract" |
| } |
| ``` |
| |
| ## Test File |
| |
| Throughout a `terraform test` execution, Terraform will produce several progress updates for each test file. The progress field can be `starting`, `teardown`, or `complete`. Each test file will emit each progress update exactly once. When a test file emits the `complete` progress update, it will also include a status field containing one of `pass`, `error`, `fail`, or `skip` denoting the overall status of the completed test file. |
| |
| ### Example |
| |
| ```json |
| { |
| "@level": "info", |
| "@message": "main.tftest.hcl... pass", |
| "@module": "terraform.ui", |
| "@testfile": "validation.tftest.hcl", |
| "@timestamp": "2023-08-09T16:12:30.724368+02:00", |
| "test_file": { |
| "path": "validation.tftest.hcl", |
| "progress": "complete", |
| "status": "pass" |
| }, |
| "type": "test_file" |
| } |
| ``` |
| |
| ## Test Run |
| |
| While executing `run` blocks within a test file, Terraform will also produce several status updates for each `run` block. The progress field for a `run` block progress update can be `starting`, `running`, `teardown`, and `complete`. The `starting` and `complete` progress updates will be emitted exactly once. While the `running` and `teardown` progress updates can be emitted multiple times. |
| |
| The `starting`, `running` and `teardown` updates will also include an `elapsed` field indicating the number of milliseconds the current test operation (for `starting` and `running`) or the current destroy operation (for `teardown`) has been in progress. |
| |
| The `complete` progress update will also include a `status` field containing one of `pass`, `error`, `fail`, or `skip` denoting the overall status of the completed `run` block`. |
| |
| Not every `run` block will emit `teardown` progress updates, as only the most recently executed `run` blocks reference the latest in-memory state files that need to be torn down. In addition, the `run` block tear down process is only initiated once the overall test file has already emitted its `teardown` status update. This means you can expect the `complete` progress update to be issued for a `run` block before any `teardown` updates are provided. There will always be a `complete` progress update issued by the enclosing test file when the tear down process for all `run` blocks is complete. |
| |
| ### Examples |
| |
| ```json |
| { |
| "@level": "info", |
| "@message": " \"successful_validation\"... pass", |
| "@module": "terraform.ui", |
| "@testfile": "validation.tftest.hcl", |
| "@testrun": "successful_validation", |
| "@timestamp": "2023-08-09T16:12:30.724407+02:00", |
| "test_run": { |
| "path": "main.tftest.hcl", |
| "run": "successful_validation", |
| "progress": "complete", |
| "status": "pass" |
| }, |
| "type": "test_run" |
| } |
| ``` |
| |
| ```json |
| { |
| "@level": "info", |
| "@message": " \"successful_validation\"... in progress", |
| "@module": "terraform.ui", |
| "@testfile": "validation.tftest.hcl", |
| "@testrun": "successful_validation", |
| "@timestamp": "2023-08-09T16:12:30.724407+02:00", |
| "test_run": { |
| "path": "main.tftest.hcl", |
| "run": "successful_validation", |
| "progress": "running", |
| "elapsed": 2024 |
| }, |
| "type": "test_run" |
| } |
| ``` |
| |
| ## Test Cleanup |
| |
| After Terraform completes the execution of each test file, `terraform test` may emit a series of `test_cleanup` messages detailing any state it could not destroy. You must locate and destroy the resources listed in these resources manually. |
| |
| As the test framework can manage multiple state files for each test file, you can see multiple versions of this message for each state file that holds resources that Terraform could not destroy. Using the `@testrun` field, you can pinpoint the run block that last updated the state file to locate the resources that Terraform could not destroy. |
| |
| ### Example |
| |
| ```json |
| { |
| "@level": "info", |
| "@message": "Terraform left some resources in state after executing main.tftest.hcl, they need to be cleaned up manually.", |
| "@module": "terraform.ui", |
| "@testfile": "validation.tftest.hcl", |
| "@testrun": "successful_validation", |
| "@timestamp": "2023-08-09T16:12:30.724407+02:00", |
| "test_cleanup": { |
| "failed_resources": [ |
| { |
| "instance": "aws_instance.primary" |
| }, |
| { |
| "instance": "aws_instance.secondary" |
| } |
| ] |
| }, |
| "type": "test_cleanup" |
| } |
| ``` |
| |
| ## Test Summary |
| |
| After the test operation has completed all test files, `terraform test` emits a `test_summary` message with the status of the overall test operation. |
| |
| ### Example |
| |
| ```json |
| { |
| "@level": "info", |
| "@message": "Success! 2 passed, 0 failed.", |
| "@module": "terraform.ui", |
| "@timestamp": "2023-08-09T16:26:45.482070+02:00", |
| "test_summary": { |
| "status": "pass", |
| "passed": 2, |
| "failed": 0, |
| "errored": 0, |
| "skipped": 0 |
| }, |
| "type": "test_summary" |
| } |
| ``` |
| |
| ## Test Plan |
| |
| In `-verbose` mode, `terraform test` emits a `test_plan` message for all `run` blocks that executed a plan operation. The `test_plan` message contains a subset of the attributes from the `terraform show -json <planfile>` command [output](/terraform/internals/json-format#plan-representation) and the `terraform providers schema -json` command [output](/terraform/cli/commands/providers/schema#providers-schema-representation). |
| |
| The message contains the following fields representing the plan: `plan_format_version`, `output_changes`, `resource_changes`, `resource_drift` and `relevant_attributes`. These match the respective fields in the [JSON Plan Representation](/terraform/internals/json-format#plan-representation). |
| |
| The message contains the following fields representing the provider schemas: `provider_format_version` and `provider_schemas`. These match the respective fields in the [JSON Providers Schema Representation](/terraform/cli/commands/providers/schema#providers-schema-representation). |
| |
| ### Example |
| |
| ```json |
| { |
| "@level": "info", |
| "@message": "-verbose flag enabled, printing plan", |
| "@module": "terraform.ui", |
| "@testfile": "validation.tftest.hcl", |
| "@testrun": "successful_validation", |
| "@timestamp": "2023-08-09T17:10:06.211942+02:00", |
| "test_plan": { |
| "plan_format_version": "1.2", |
| "resource_changes": [ |
| { |
| "address": "aws_instance.primary", |
| "mode": "managed", |
| "type": "aws_instance", |
| "name": "primary", |
| "provider_name": "registry.terraform.io/hashicorp/aws", |
| "change": { |
| "actions": [ |
| "create" |
| ], |
| "before": null, |
| "after": { |
| "ami": "af84f887-e3eb-9e52-5f8b-8a2803734fd0" |
| }, |
| "after_unknown": {}, |
| "before_sensitive": false, |
| "after_sensitive": {} |
| } |
| } |
| ], |
| "provider_format_version": "1.0", |
| "provider_schemas": { |
| "registry.terraform.io/hashicorp/aws": { |
| "provider": { |
| "version": 0 |
| }, |
| "resource_schemas": { |
| "aws_instance": { |
| "version": 0, |
| "block": { |
| "attributes": { |
| "ami": { |
| "type": "string", |
| "description_kind": "plain", |
| "required": true |
| } |
| }, |
| "description_kind": "plain" |
| } |
| } |
| } |
| } |
| } |
| }, |
| "type": "test_plan" |
| } |
| ``` |
| |
| ## Test State |
| |
| In `-verbose` mode, `terraform test` emits a `test_state` message for all `run` blocks that executed an apply operation. The `test_state` message contains a subset of the `terraform show -json` command [output](/terraform/internals/json-format#state-representation) and the `terraform providers schema -json` command [output](/terraform/cli/commands/providers/schema#providers-schema-representation). |
| |
| The message contains the following fields representing the state: `state_format_version`, `root_module`, and `outputs`. These match the respective fields in the [JSON Values Representation](/terraform/internals/json-format#values-representation) that are embedded in complete JSON state representation. |
| |
| The message contains the following fields representing the provider schemas: `provider_format_version` and `provider_schemas`. These match the respective fields in the [JSON Providers Schema Representation](/terraform/cli/commands/providers/schema#providers-schema-representation). |
| |
| ### Example |
| |
| ```json |
| { |
| "@level": "info", |
| "@message": "-verbose flag enabled, printing state", |
| "@module": "terraform.ui", |
| "@testfile": "validation.tftest.hcl", |
| "@testrun": "successful_validation", |
| "@timestamp": "2023-08-09T17:18:21.173008+02:00", |
| "test_state": { |
| "state_format_version": "1.0", |
| "root_module": { |
| "resources": [ |
| { |
| "address": "aws_instance.primary", |
| "mode": "managed", |
| "type": "aws_instance", |
| "name": "primary", |
| "provider_name": "registry.terraform.io/hashicorp/aws", |
| "schema_version": 0, |
| "values": { |
| "ami": "af84f887-e3eb-9e52-5f8b-8a2803734fd0" |
| }, |
| "sensitive_values": {} |
| } |
| ] |
| }, |
| "provider_format_version": "1.0", |
| "provider_schemas": { |
| "registry.terraform.io/hashicorp/aws": { |
| "provider": { |
| "version": 0 |
| }, |
| "resource_schemas": { |
| "aws_instance": { |
| "version": 0, |
| "block": { |
| "attributes": { |
| "ami": { |
| "type": "string", |
| "description_kind": "plain", |
| "required": true |
| } |
| }, |
| "description_kind": "plain" |
| } |
| } |
| } |
| } |
| } |
| }, |
| "type": "test_state" |
| } |
| ``` |
| |
| ## Test Interrupt |
| |
| When `terraform test` is impeded or canceled, it emits a `test_interrupt` message that describes the interrupted operation. This message includes any state that Terraform could not destroy before exiting and any leftover resources that Terraform did not finish creating. |
| |
| As with the [Test Cleanup](#test-cleanup) message, Terraform might have been maintaining multiple state files. The `state` field contains the resources from the main state for the test configuration, while the `states` field contains a map of `run` block names to the resources that each `run` block created, which Terraform could not destroy. |
| |
| Finally, the `planned` field contains any resources that were in the process of being created by the interrupted `run` block, which you can identify using the `@testrun` field. |
| |
| ### Example |
| |
| ```json |
| { |
| "@level": "info", |
| "@message": "-verbose flag enabled, printing state", |
| "@module": "terraform.ui", |
| "@testfile": "validation.tftest.hcl", |
| "@testrun": "successful_validation", |
| "@timestamp": "2023-08-09T17:18:21.173008+02:00", |
| "test_interrupt": { |
| "state": [ |
| { |
| "instance": "aws_instance.primary" |
| } |
| ], |
| "states": { |
| "unsuccessful_validation": [ |
| { |
| "instance": "aws_instance.secondary" |
| } |
| ] |
| }, |
| "planned": [ |
| "aws_instance.secondary" |
| ] |
| }, |
| "type": "test_interrupt" |
| } |
| ``` |