vscode-terraform
vscode-terraform copied to clipboard
Show data from config and state
Problem Statement
Users are provided with completion, hover data etc. today largely based on schemas for both Terraform itself (core) and individual providers.
There are situations in which schema will never be sufficient to provide enough guidance however.
- module outputs with interpolation targeting config value - such as
output "example" { value = aws_instance.test.instance_type } - resources with computed attributes - such as
resource "aws_instance" "test"w/public_ip - most data source attributes - such as
data "aws_ami" "example"w/image_id
Expected User Experience
Completion
Completing elements of computed maps/lists
Upon typing the opening bracket [ user will be presented with:
- all known map keys, including ones sourced from the state
- all known list element indexes, including ones sourced from the state
output "tag_value" {
value = data.aws_instance.foo.instance_tags[ # <-- HERE e.g. "Owner" is suggested, assuming such tag exists
}
output "first_instance_id" {
value = data.aws_instances.test.ids[ # <-- HERE e.g. 0, 1, 2, 3 etc. is suggested if 4 instance IDs are returned
}
Showing values of attributes
In addition to suggesting a primitive attribute (such as image_id in example below) user will also be presented with value below the description of the field in completion
Primitive Types

Complex Types (e.g. object)

Hover
Block header
Given a data source or a resource block, user can hover over the header (first line of the block)
data "aws_ami" "ubuntu" {
#^^^^^^^^^^^^^^^^^^^^^^^^
# Hovering over THIS HEADER would display e.g.
# {
# most_recent = true
# image_id = "ami-123456789"
# ...
# }
most_recent = true
filter {
name = "name"
values = ["ubuntu/images/hvm-ssd/ubuntu-focal-20.04-amd64-server-*"]
}
filter {
name = "virtualization-type"
values = ["hvm"]
}
owners = ["099720109477"] # Canonical
}
which will display all known data based on schema, in-config values and state.
Reference
Given a reference address, user can hover over it to display the in-config value
resource "aws_instance" "web" {
ami = data.aws_ami.ubuntu.id
#^^^^^^^^^^^^^^^^^^^^^^
# Hovering over THIS REFERENCE would display e.g. `ami-123456789`
instance_type = "t3.micro"
}
Proposal
Note: It is unclear whether it's avoidable but fully interpolating an expression with all references would likely require understanding dependencies between expressions and therefore blocks of code, which effectively means re-implementing Terraform's DAG in some form or shape.
See also:
- https://github.com/hashicorp/terraform-ls/issues/338
- https://github.com/hashicorp/terraform-ls/issues/495
- https://github.com/hashicorp/terraform-ls/issues/496
Hover
There is an issue tracking support for additional hover request in LSP which would be most likely suitable for this kind of situation - as opposed to obtaining all the schema-related data + state + config data in a single request. This would also allow us to provide more flexible "progressively enhanced" UX where we can show schema-based data quickly and enhance append more content, or replace it once we obtain more data.
See more at https://github.com/microsoft/language-server-protocol/issues/772
We can consider implementing such an extension to the protocol (first internally, then proposing it upstream), and/or just extend the existing textDocument/hover workflow where hcl-lang would return a lang.Address for the given position - e.g. aws_instance.example as an extra field in lang.HoverData. This would then allow the server to use it to obtain more relevant data e.g. via terraform console or terraform state show.
Completion
TODO
Blocking Questions
- How do we obtain values from the state?
- We could use
terraform state show [address](if machine-readable JSON output was added) - We could use
echo [address] | terraform console(if machine-readable JSON output was added)
- We could use
- How do we obtain values from the config?
- How do we present differences between config and state values / how do we merge it?
- How do we deal with excessively large amount of data? e.g.
github_ip_ranges