Building Custom HCL Providers with the Terraform Go SDK
It's 2019, and "Infrastructure as Code" (IaC) isn't just a buzzword anymore—it's the baseline. Terraform has won the tool war, but what happens when you need to manage a proprietary API or a niche service that doesn't have an official provider?
You build your own. Using the Terraform Plugin SDK, you can map Go functions to HCL resources and data sources.
The Anatomy of a Provider
A Terraform provider is a standalone binary that communicates with Terraform Core via RPC. The SDK handles all the heavy lifting of state management and diffing. Your job is to define the schema and implement the CRUD (Create, Read, Update, Delete) operations.
Defining a Resource
Here’s a look at how we define a simple "item" resource in a custom provider:
package myprovider
import (
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
)
func resourceItem() *schema.Resource {
return &schema.Resource{
Create: resourceItemCreate,
Read: resourceItemRead,
Update: resourceItemUpdate,
Delete: resourceItemDelete,
Schema: map[string]*schema.Schema{
"name": {
Type: schema.TypeString,
Required: true,
},
"description": {
Type: schema.TypeString,
Optional: true,
},
},
}
}
func resourceItemCreate(d *schema.ResourceData, m interface{}) error {
name := d.Get("name").(string)
// Call your API here to create the resource
d.SetId("unique-id-from-api")
return resourceItemRead(d, m)
}
The Diffing Engine
The real magic is in how Terraform calculates the "plan". If you change the description in your .tf file, Terraform calls your Update function. If you change a field marked as ForceNew: true, Terraform knows it has to destroy and recreate the resource.
Why Go?
HashiCorp chose Go for a reason: static binaries, excellent concurrency, and a robust standard library for networking. In 2019, if you're doing DevOps, you're doing Go.
Stop manually clicking buttons in consoles. If it has an API, it should have a Terraform provider.