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

Allow loading of on-disk provider schemas

Open tylerFowler opened this issue 2 years ago • 4 comments

Current Version

0.25.2

Use-cases

I have a use case where I have a number of org-private providers and would like to be able to distribute schemas for them alongside a base terraform-ls build in order to provide autocomplete support for these internal providers.

Attempted Solutions

A custom fork that embeds a set of schemas that are built out-of-band would not be doable for my usecase given organizational constraints.

Proposal

A simple solution might be to provide a flag to provider schemas on-disk that would augment or override the existing VFS schema store loading process in internal/schemas. This would allow us to distribute the schemas separately from the terraform-ls binary and avoid a long-lived fork.

For example:

$ terraform-ls serve -provider-schemas ./schemas.json -provider-versions ./versions.json

Admittedly having to provide two files is somewhat clunky, ideally the two can be combined into a single file and disassembled in code but I understand if there's opposition to that.

If there is interest in this solution or something like it, I would be interested in contributing such a feature since we need it sooner rather than later.

tylerFowler avatar Mar 07 '22 23:03 tylerFowler

Hi @tylerFowler Thanks for sharing the use case.

For what it's worth we do already support providers which are not embedded into LS, although it comes with some caveats. Ironically, the embedding of provider schemas initially came as a "fallback" to the original method but probably ended up as the primary method of getting schemas for reasons I'll describe below. 😅

The language server will attempt to run terraform providers schema -json in any directory/module which was initialized (i.e. has .terraform as a result of terraform init) and use it the same way as the embedded schemas, in fact it will prefer locally obtained schemas over the embedded ones. This is also meant to address the fact that embedded schemas reflect only the latest versions of providers at the time of LS release, which may not match the version of provider any user uses, resulting in minor inaccuracies in metadata used in completion/hover/etc..

The major caveats of obtaining schema via CLI are

  • (compatible version of) Terraform has to be already installed
  • the module has to be initialized already, LS won't attempt to do it by itself
  • terraform providers schema -json will fail if the on-disk configuration is "too invalid" (such as missing } or {) and we don't have an effective way of retrying this command
  • both init and terraform providers schema -json require access to the state, meaning that if it's stored in a remote backend (as per best practices) this requires auth

The challenge with schemas in separate files isn't as much the clunkiness (although I agree it is clunky) but more that there is 1 schema per provider version, so the interface is more like a filesystem hierarchy or HTTP endpoint, rather than a single file.

HTTP endpoint is basically how we plan to integrate with registry.terraform.io API as part of https://github.com/hashicorp/terraform-ls/issues/193 and I expect that the same or comparable API functionality would also be eventually added to TFC API such that we can source schemas even for providers hosted in private registries. The remaining question for private registry is discovery and auth of course, but we have some groundwork available in the cloud block and/or terraform login, so we could probably even make it work more or less out of the box, as long as there is ~/.terraform.d/credentials.tfrc.json.

On a related note - How do you distribute these internal providers? Would the private registry in TFC help in this situation, if we integrated with a hypothetical future API there?


There is also alternative/additional idea described in https://github.com/hashicorp/terraform-ls/issues/355 which involves obtaining the schemas via gRPC, but that has some other challenges as the provider still has to be installed somehow somewhere (and kept up to date).

radeksimko avatar Mar 08 '22 09:03 radeksimko

Hello, thanks for the reply!

As it happens, the caveats you listed to TF CLI based schema discovery do apply to my usecase pretty directly. We don't actually distribute our internal providers to users at all, all actual Terraform operations happen in a controlled cloud setting so developers writing Terraform code never really interact with the tool itself and so do not download providers at all. Hence the need for us to be able to distribute schemas separately.

That said, we are also looking into implementing a private registry using the TF protocol, so I'd be very interested in the ability to source schemas from one. Is there a timeline for that feature?

tylerFowler avatar Mar 11 '22 22:03 tylerFowler

That said, we are also looking into implementing a private registry using the TF protocol, so I'd be very interested in the ability to source schemas from one. Is there a timeline for that feature?

There is currently no timeline. I can say is that providers in the public registry are generally higher on our priority list but there's a possibility we may end up supporting private registry at least partially as a side effect of solving this for public providers since some parts of the private and public Registry codebase are AFAIK shared at it may end up being just a matter of swapping hostnames. I cannot predict nor guarantee that at this point though.

It is relatively unlikely we'll introduce support for loading schema directly from the filesystem - due to the workflow challenges we both described here. If we do introduce some support though it would be more along the lines of loading schemas from a directory with a particular structure, assuming the most pragmatic use case would be schemas available via NFS mount-point (e.g. \\shared-tf-providers), similar to how terraform providers mirror works internally.

radeksimko avatar Mar 14 '22 16:03 radeksimko

That's fair, after investigating further it appears that if I were to implement a custom private registry, then the terraform init process would work correctly and be sufficient to allow terraform-ls to provide autocompletion and other features, correct me if I'm missing something there.

I wasn't aware of the providers mirror subcommand, that's very interesting and might open up new options for my usecase - thanks for sharing that. And of course if terraform-ls would be able to take advantage of something like that directly, it would spare me having to direct users to create nontrivial .terraformrc setups. Either through some sort of on-host filesystem, or via a remote structure like the Provider Mirror Network Protocol (preferred).

tylerFowler avatar Mar 18 '22 22:03 tylerFowler