hashicorp / terraform

Terraform enables you to safely and predictably create, change, and improve infrastructure. It is a source-available tool that codifies APIs into declarative configuration files that can be shared amongst team members, treated as code, edited, reviewed, and versioned.
https://www.terraform.io/
Other
42.11k stars 9.47k forks source link

Function documentation needs TF code examples #28135

Open cognitiaclaeves opened 3 years ago

cognitiaclaeves commented 3 years ago

Current Terraform Version

This is related to the documentations for functions, as I've observed them, since they've been out.

Proposal

It takes to much time when switching contexts after not looking at TF for a while to readjust again. One of the most jarring aspects of working with TF is that moment where I need to remember how I can run functions interactively in a TF session so that I can interpolate how to use functions in code. This could be greatly reduced if there were two kinds of examples for each function: the one that presently exists that shows how to do it interactively, and another that shows what it looks like in code. Functions are used pretty frequently, so it's like I'm unable to write any TF until after I'm able to remember how to run the functions interactively.

Example

Today I need to figure out how to template a file that we're writing through a file provisioner. So, I go to file provisioner and see how I might be able to use a template with it. Then I pull up template and find that I should use a function for TF 12+. So I pull up the function and get a lot of examples of how to use it -- not in the way that it needs to be written for IAC. Now I have to burn cycles to figure out how to make the translation. Then I'm good, so long as I continue to write TF frequently enough that I don't forget how it works again. Then, I inevitably do, and the cycle starts over again. This has happened about 10 times now, since I started working with TF 12.

apparentlymart commented 3 years ago

Hi @cognitiaclaeves! Thanks for sharing this feedback.

I'd like to talk a little more about what would've helped you in this case. It sounds like you were in a situation where you needed to combine two Terraform features together -- in this case, the file provisioner's arguments along with the templatefile function -- and you're saying that it would've helped to see an example of them both together, perhaps something like this?

  provisioner "local-exec" {
    content = templatefile("${path.module}/example.tmpl", {
      ip_address = self.private_ip
    })
    # ...
  }

As I'm sure you can imagine, a challenge with this sort of example is that there are an essentially-infinite number of combinations of features like this which are orthogonal to one another. As a compromise, we've often tried to think about what might be common combinations that many users would encounter -- and often we learn this by observing what questions are asked repeatedly by lots of people -- and so that leads to us writing sections like Flattening nested structures for for_each in the flatten function docs, or the variable validation example in can.

As I think about questions I've seen about templatefile (in the community forum and similar), I think the most common situation has been in using templatefile to prepare dynamic cloud-init scripts/configurations to assign into arguments like aws_instance user_data, and the corresponding features in other cloud compute platforms. Questions about provisioners are less common, but of course that's likely because we've documented that provisioners are a last resort and suggested folks use user_data-like features instead where possible, and so I expect folks with a use-case like yours are more commonly ending up dealing with cloud-init than with the file provisioner.

With that said then, do you think that an example like the following would've given you a good enough starting point which you could then adapt to a working configuration for the file provisioner?

variable "environment" {
  type = string
}

resource "aws_instance" "example" {
  user_data = templatefile("${path.module}/example.tmpl", {
    environment = var.environment
  }

  # ...
}

Although not directly an example of the file provisioner, I'm hoping that it shows enough of the grammar that you'd be able to see how to adapt it to assign to the content argument of the file provisioner too, because it's just the argument name that would be different then.

We do also have the challenge that Terraform Core is provider-agnostic and so it's difficult to write an example that will resonate with folks using different cloud platforms than the one we happen to arbitrarily choose for the example, but I think in this case we have the advantage that we can link to and from the existing documentation section Passing data into virtual machines and other compute resources to hopefully give readers enough information to see how to adapt the example to the equivalent mechanism for the platform they are targeting.