DEV Community

Cover image for Developing Terraform Custom Provider
Saravanan G
Saravanan G

Posted on • Updated on

Developing Terraform Custom Provider

Table of Content

Introduction

We assume that the readers of this article has prior understanding and working knowledge in Terraform and has created resource provisioning TF files for various Cloud providers. But still....

Bit of intro into Terraform

  • Terraform is a Cloud agnostic Infra as code technology and used to create immutable infrastructure.
  • Terraform is used to create, manage, and update infrastructure resources such as physical machines, VMs, network switches, containers, and more. Almost any infrastructure type can be represented as a resource in Terraform.
  • Deliver infrastructure as code with Terraform using declarative tf configuration files
  • Plan and predict changes: Terraform provides an elegant user experience for operators to safely and predictably make changes to infrastructure
  • Create reproducible infrastructure: Terraform makes it easy to re-use configurations for similar infrastructure, helping you avoid mistakes and save time.

Terraform Provider

A provider is responsible for understanding API interactions and exposing resources. Most providers configure a specific infrastructure platform (either cloud or self-hosted). Providers can also offer local utilities for tasks like generating random numbers for unique resource names.

Terraform Custom Provider

According to Terraform documentation,

There are a few possible reasons for authoring a custom Terraform provider, such as:

  • An internal private cloud whose functionality is either proprietary or would not benefit the open source community.

  • A "work in progress" provider being tested locally before contributing back.

  • Extensions of an existing provider

Refer the Hashicorp Documentation on writing custom providers

What is required to develop Custom Provider

  1. Just small enough Go development knowledge
  2. Resource creation supported by API calls from the respective provider

Install and Configure Terraform

  • Refer here for installing terraform
  • Windows
    • Download and extract the terraform executable
    • Add terraform executable path to ENV PATH variable
  • In Linux flavours, Copy the terraform executable in /usr/bin path to execute it from any path.

How to develop provider code with Go

Step 1 Setting up Go develop environment

Refer my Dev community article

Read my article on getting started with Go Hello World

Step 2 Custom Provider Source Code Details

Please check out the provider source files from GitHub Repo Here

  • Required source files for custom provider are,
    • main.go
    • provider.go
    • resource_server.go
The code layout looks like this:
.
├── main.go
├── provider.go
├── resource_server.go
Enter fullscreen mode Exit fullscreen mode
  • Go entry point function is main.go.
// main.go
package main

import (
        "github.com/hashicorp/terraform-plugin-sdk/plugin"
        "github.com/hashicorp/terraform-plugin-sdk/terraform"
)

func main() {
        plugin.Serve(&plugin.ServeOpts{
                ProviderFunc: func() terraform.ResourceProvider {
                        return Provider()
                },
        })
}
Enter fullscreen mode Exit fullscreen mode
  • provider.go will have the resource server function calls.
// provider.go
package main

import (
        "github.com/hashicorp/terraform-plugin-sdk/helper/schema"
)

func Provider() *schema.Provider {
        return &schema.Provider{
                ResourcesMap: map[string]*schema.Resource{
                     "customprovider_server": resourceServer(),
                },
        }
}
Enter fullscreen mode Exit fullscreen mode
  • All the resource creation has to be coded in resource_server.go. This file will have the resource function declaration and definition like create, delete etc, it also gets the input params required to create resources.
// resource_server.go
package main

import (
        "github.com/hashicorp/terraform-plugin-sdk/helper/schema"
)

func resourceServer() *schema.Resource {
        return &schema.Resource{
                Create: resourceServerCreate,
                Read:   resourceServerRead,
                Update: resourceServerUpdate,
                Delete: resourceServerDelete,

                Schema: map[string]*schema.Schema{
                        "num_sys": &schema.Schema{
                                Type:     schema.TypeString,
                                Required: true,
                        },
                },
        }
}

func resourceServerCreate(d *schema.ResourceData, m interface{}) error {
        num_sys := d.Get("num_sys").(string)

        d.SetId(num_sys)

/* 
API call to be added for respective provider. In case of developing provider for on-prem cloud or public cloud, that is not supported by terraform, add the API call to corresponding Resource creation API 
*/
        return resourceServerRead(d, m)
}

func resourceServerRead(d *schema.ResourceData, m interface{}) error {
        return nil
}

func resourceServerUpdate(d *schema.ResourceData, m interface{}) error {
        return resourceServerRead(d, m)
}

func resourceServerDelete(d *schema.ResourceData, m interface{}) error {
        return nil
}
Enter fullscreen mode Exit fullscreen mode
  • Details regarding the custom provider code in resource_server.go:
    • Our code repo example implemented with mock resource creation for the provider called 'customprovider'.
    • In real-time case, it has to be changed for the provider name of respective cloud or on-premises server.
    • Most of providers have API calls to be consumed for resource operation like create/update/delete etc.. So We need to define the logic of resource operations like create and delete using the custom provider api calls, to apply the terraform template.
    • Please add the API call implementation in the /* commented out */ section in resource_server.go

Step 3 Build go code and create tf provider executable

cd tf_custom_provider/
go mod init
go mod tidy
go build -o terraform-provider-customprovider
Enter fullscreen mode Exit fullscreen mode

Please note,

Third-party plugins (both providers and provisioners) can be manually installed into the user plugins directory
Located at %APPDATA%\terraform.d\plugins on Windows and ~/.terraform.d/plugins on other systems.

Copy the custom provider executable created in the step above to Terraform plugin directory
Enter fullscreen mode Exit fullscreen mode
  • After adding the logic for resource operations in resource_server.go, our custom provider is ready to get tested

Step 4 Create terraform file

Test the provider by creating main.tf, by providing the resource inputs. In our sample just the number of server count added as an input parameter for demo purpose.
Create or Edit main.tf file with code to create custom provider resource

resource "customprovider_server" "my-server-name" {
    num_sys = "2"
}
Enter fullscreen mode Exit fullscreen mode

Step 5 Testing Provider Create and Destroy resource

  • The custom provider executable should be placed inside the "~/.terraform.d/plugins" (in Linux server) path to enable the access to the custom provider functionality
  • Execute the following Terraform commands to verify the custom provider functionalities we have added,
terraform init
terraform plan
terraform apply
terraform destroy
Enter fullscreen mode Exit fullscreen mode

Bibliography and Reference

Terraform Docs
Custom Provider Lab Tutorial
Custom Provider Easy Tutorial

Discussion (0)