vscode-terraform icon indicating copy to clipboard operation
vscode-terraform copied to clipboard

Show data from config and state

Open radeksimko opened this issue 4 years ago • 0 comments

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

image2 image3

Complex Types (e.g. object)

image1

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)
  • 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

radeksimko avatar Aug 10 '21 13:08 radeksimko