Terraform
Implement documentation generation
In this tutorial, you will add documentation generation capabilities to a provider that interacts with the API of a fictional coffee-shop application called HashiCups. To do this, you will:
- Add terraform-plugin-docs to the provider.
This enables the provider to automatically generate data source, resource, and function documentation. - Add schema descriptions.
This enhances the documentation to include a description for the provider itself, its data sources and resources, and each of their attributes. - Add configuration examples.
This enhances the documentation to include example Terraform configurations. - Add resource import documentation.
This enhances the resource documentation to include an example of how to import the resources that support it. - Run documentation generation.
This ensures that the documentation generation works as expected.
The terraform-plugin-docs
Go module cmd/tfplugindocs
command enables providers to implement documentation generation. The generation uses schema descriptions and conventionally placed files to produce provider documentation that is compatible with the Terraform Registry.
Prerequisites
To follow this tutorial, you need:
- Go 1.21+ installed and configured.
- Terraform v1.8+ installed locally.
Navigate to your terraform-provider-hashicups
directory.
Your code should match the 10-acceptance-tests
directory
from the example repository.
If you're stuck at any point during this tutorial, refer to the
11-documentation-generation
directory in the example repository to see the code implemented in this
tutorial.
Add schema descriptions
The tfplugindocs
tool will automatically include schema-based descriptions, if
present in a data source, provider, or resource's schema. The schema.Schema
type's Description
field describes the data source, provider, or resource
itself. Each attribute's or block's Description
field describes that
particular attribute or block. These descriptions should be tailored to
practitioner usage and include any caveats or value expectations, such as
special syntax.
Open the internal/provider/provider.go
file.
Add documentation to your provider by replacing the entire Schema
method
with the following, which adds Description
fields to the provider's schema and
each of it's attributes.
internal/provider/provider.go
// Schema defines the provider-level schema for configuration data.
func (p *hashicupsProvider) Schema(_ context.Context, _ provider.SchemaRequest, resp *provider.SchemaResponse) {
resp.Schema = schema.Schema{
Description: "Interact with HashiCups.",
Attributes: map[string]schema.Attribute{
"host": schema.StringAttribute{
Description: "URI for HashiCups API. May also be provided via HASHICUPS_HOST environment variable.",
Optional: true,
},
"username": schema.StringAttribute{
Description: "Username for HashiCups API. May also be provided via HASHICUPS_USERNAME environment variable.",
Optional: true,
},
"password": schema.StringAttribute{
Description: "Password for HashiCups API. May also be provided via HASHICUPS_PASSWORD environment variable.",
Optional: true,
Sensitive: true,
},
},
}
}
Open the internal/provider/coffees_data_source.go
file.
Add documentation to your data source by replacing the entire Schema
method
with the following.
internal/provider/coffees_data_source.go
// Schema defines the schema for the data source.
func (d *coffeesDataSource) Schema(_ context.Context, _ datasource.SchemaRequest, resp *datasource.SchemaResponse) {
resp.Schema = schema.Schema{
Description: "Fetches the list of coffees.",
Attributes: map[string]schema.Attribute{
"id": schema.StringAttribute{
Description: "Placeholder identifier attribute.",
Computed: true,
},
"coffees": schema.ListNestedAttribute{
Description: "List of coffees.",
Computed: true,
NestedObject: schema.NestedAttributeObject{
Attributes: map[string]schema.Attribute{
"id": schema.Int64Attribute{
Description: "Numeric identifier of the coffee.",
Computed: true,
},
"name": schema.StringAttribute{
Description: "Product name of the coffee.",
Computed: true,
},
"teaser": schema.StringAttribute{
Description: "Fun tagline for the coffee.",
Computed: true,
},
"description": schema.StringAttribute{
Description: "Product description of the coffee.",
Computed: true,
},
"price": schema.Float64Attribute{
Description: "Suggested cost of the coffee.",
Computed: true,
},
"image": schema.StringAttribute{
Description: "URI for an image of the coffee.",
Computed: true,
},
"ingredients": schema.ListNestedAttribute{
Description: "List of ingredients in the coffee.",
Computed: true,
NestedObject: schema.NestedAttributeObject{
Attributes: map[string]schema.Attribute{
"id": schema.Int64Attribute{
Description: "Numeric identifier of the coffee ingredient.",
Computed: true,
},
},
},
},
},
},
},
},
}
}
Open the internal/provider/order_resource.go
file.
Add documentation to your resource by replacing the entire Schema
method
with the following.
internal/provider/order_resource.go
// Schema defines the schema for the resource.
func (r *orderResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) {
resp.Schema = schema.Schema{
Description: "Manages an order.",
Attributes: map[string]schema.Attribute{
"id": schema.StringAttribute{
Description: "Numeric identifier of the order.",
Computed: true,
PlanModifiers: []planmodifier.String{
stringplanmodifier.UseStateForUnknown(),
},
},
"last_updated": schema.StringAttribute{
Description: "Timestamp of the last Terraform update of the order.",
Computed: true,
},
"items": schema.ListNestedAttribute{
Description: "List of items in the order.",
Required: true,
NestedObject: schema.NestedAttributeObject{
Attributes: map[string]schema.Attribute{
"quantity": schema.Int64Attribute{
Description: "Count of this item in the order.",
Required: true,
},
"coffee": schema.SingleNestedAttribute{
Description: "Coffee item in the order.",
Required: true,
Attributes: map[string]schema.Attribute{
"id": schema.Int64Attribute{
Description: "Numeric identifier of the coffee.",
Required: true,
},
"name": schema.StringAttribute{
Description: "Product name of the coffee.",
Computed: true,
},
"teaser": schema.StringAttribute{
Description: "Fun tagline for the coffee.",
Computed: true,
},
"description": schema.StringAttribute{
Description: "Product description of the coffee.",
Computed: true,
},
"price": schema.Float64Attribute{
Description: "Suggested cost of the coffee.",
Computed: true,
},
"image": schema.StringAttribute{
Description: "URI for an image of the coffee.",
Computed: true,
},
},
},
},
},
},
},
}
}
Review function documentation
The tfplugindocs
tool will generate documentation for functions based on the
function definition. Open the compute_tax_function.go
file and review the
Definition
method.
compute_tax_function.go
func (f *ComputeTaxFunction) Definition(ctx context.Context, req function.DefinitionRequest, resp *function.DefinitionResponse) {
resp.Definition = function.Definition{
Summary: "Compute tax for coffee",
Description: "Given a price and tax rate, return the total cost including tax.",
Parameters: []function.Parameter{
function.Float64Parameter{
Name: "price",
Description: "Price of coffee item.",
},
function.Float64Parameter{
Name: "rate",
Description: "Tax rate. 0.085 == 8.5%",
},
},
Return: function.Float64Return{},
}
}
Add configuration examples
The tfplugindocs
tool will automatically include Terraform configuration
examples from files with the following naming conventions:
- Provider:
examples/provider/provider.tf
- Resources:
examples/resources/TYPE/resource.tf
- Data Sources:
examples/data-sources/TYPE/data-source.tf
- Functions:
examples/functions/TYPE/function.tf
Replace TYPE
with the name of the resource, data source, or function. For
example: examples/resources/hashicups_order/resource.tf
.
Open the examples/provider/provider.tf
file and replace the existing code with the following.
examples/provider/provider.tf
# Configuration-based authentication
provider "hashicups" {
username = "education"
password = "test123"
host = "http://localhost:19090"
}
Remove the data source example from the scaffolding framework.
$ rm -r examples/data-sources/scaffolding_example
Create a examples/data-sources/hashicups_coffees
directory.
$ mkdir -p examples/data-sources/hashicups_coffees
Create the examples/data-sources/hashicups_coffees/data-source.tf
file with the following.
examples/data-sources/hashicups_coffees/data-source.tf
# List all coffees.
data "hashicups_coffees" "all" {}
Remove the resource example from the scaffolding framework.
$ rm -r examples/resources/scaffolding_example
Create the examples/resources/hashicups_order
directory.
$ mkdir -p examples/resources/hashicups_order
Create the examples/resources/hashicups_order/resource.tf
file with the following.
examples/resources/hashicups_order/resource.tf
# Manage example order.
resource "hashicups_order" "example" {
items = [
{
coffee = {
id = 3
}
quantity = 2
},
]
}
Add resource import documentation
The tfplugindocs
tool automatically will include Terraform import examples for
resources with the file naming convention examples/resources/TYPE/import.sh
.
Create a new examples/resources/hashicups_order/import.sh
file with the following.
examples/resources/hashicups_order/import.sh
# Order can be imported by specifying the numeric identifier.
terraform import hashicups_order.example 123
Add function example
Create a examples/functions/compute_tax
directory.
$ mkdir -p examples/functions/compute_tax
Create the examples/functions/compute_tax/function.tf
file with the following.
examples/functions/compute_tax/function.tf
# Compute total price with tax
output "total_price" {
value = provider::hashicups::compute_tax(5.00, 0.085)
}
Run documentation generation
Open tools/tools.go
and replace the provider name in the documentation generation command.
tools.go
// Generate copyright headers
//go:generate go run github.com/hashicorp/copywrite headers -d .. --config ../.copywrite.hcl
// Format Terraform code for use in documentation.
// If you do not have Terraform installed, you can remove the formatting command, but it is suggested
// to ensure the documentation is formatted properly.
//go:generate terraform fmt -recursive ../examples/
// Generate documentation.
//go:generate go run github.com/hashicorp/terraform-plugin-docs/cmd/tfplugindocs generate --provider-dir .. -provider-name hashicups
Now that you have implemented the documentation generation functionality for your provider, run the cd tools; go generate ./...
command to generate the documentation.
$ cd tools; go generate ./...
rendering website for provider "hashicups" (as "hashicups")
exporting schema from Terraform
compiling provider "hashicups"
using Terraform CLI binary from PATH if available, otherwise downloading latest Terraform CLI binary
running terraform init
getting provider schema
generating missing templates
generating missing resource content
generating new template for "hashicups_order"
generating missing data source content
generating new template for data-source "hashicups_coffees"
generating missing function content
generating new template for function "compute_tax"
generating missing provider content
generating new template for "hashicups"
rendering static website
cleaning rendered website dir
removing directory: "data-sources"
rendering templated website to static markdown
rendering "data-sources/coffees.md.tmpl"
rendering "functions/compute_tax.md.tmpl"
rendering "index.md.tmpl"
rendering "resources/order.md.tmpl"
View the generated files in the docs
directory to verify that the
documentation contains the expected descriptions, examples, and schema
information.
Next steps
Congratulations! You have enhanced the provider with documentation generation capabilities.
If you were stuck during this tutorial, checkout the
11-documentation-generation
directory in the example repository to see the code implemented in this
tutorial.
- To learn more about the Terraform Plugin Framework, refer to the Terraform Plugin Framework documentation.
- For a full capability comparison between the SDKv2 and the Plugin Framework, refer to the Which SDK Should I Use? documentation.
- The example repository contains directories corresponding to each tutorial in this collection.
- Submit any Terraform Plugin Framework bug reports or feature requests to the development team in the Terraform Plugin Framework Github repository.
- Submit any Terraform Plugin Framework questions in the Terraform Plugin Framework Discuss forum.