Terraform is an open source resource orchestration tool based on Golang, which allows users to manage and configure any infrastructure, the infrastructure of public and private cloud services, and external services.
Overview
Terraform is logically split into two main parts:
- Terraform Core: This is the Terraform binary that communicates with plugins to manage infrastructure resources. It provides a common interface that allows you to leverage many different cloud providers, databases, services, and in-house solutions.
- Terraform Plugins: These are executable binaries written in Go that communicate with Terraform Core over an RPC interface. Each plugin exposes an implementation for a specific service, such as the AWS provider or the cloud-init provider. Terraform currently supports one type of Plugin called providers.
Get Started
Clone these template repositories on GitHub: terraform-provider-scaffolding (SDKv2)
Steps:
- clone the terraform-provider-scaffolding (SDKv2).
- explore development environment, modify
GNUmakefile
. - define the provider、data_source、resource schema.
- write code for cos bucket CRUD (
internal/provider
dir) and acceptance tests. - test the provider.
- generate the provider documentation.
Requirements
- Terraform >= 0.13.x
- Go >= 1.15
Building The Provider
To compile the provider, run go install
. This will build the provider and put the provider binary in the $GOPATH/bin
directory.
Generate the Provider Documentation
To generate or update documentation, run go generate
.
Acceptance tests
In order to run the full suite of Acceptance tests, run make testacc
.
Note: Acceptance tests create real resources, and often cost money to run.
Directory Structure
Take cos bucket
as an example, modify the directory structure as follows.
terraform-provider-cos |
The structure is mainly divided into five parts:
main.go
, plugin entry.provider.go
, attributes used to describe plugins, such as: configured key, supported resource list, callback - configuration.data_source_*.go
, read calls, mainly query interfaces.resource_*.go
, write calls, including resource addition, deletion, modification and query interfaces.service_*.go
, public methods divided by resource categories.
Explore your development environment
TEST?=$$(go list ./... | grep -v 'vendor') |
Define provider schema
func New(version string) func() *schema.Provider { |
Define bucket data resource schema
resource_cos_bucket.go
func resourceCosBucket() *schema.Resource { |
data_source_cos_bucket.go
func dataSourceCosBucket() *schema.Resource { |
Implement Complex Read
func dataSourceCosBucketRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { |
Implement Create
func resourceCosBucketCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { |
Implement Update
func resourceCosBucketUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { |
Implement Delete
func resourceCosBucketDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { |
Implement Cos Bucket Service
import ( |
Test the provider
make install
[blazehu@MacBook ~]$ make install
go build -o terraform-provider-cos_v0.1
mkdir -p ~/.terraform.d/plugins/blazehu.com/edu/cos/0.1/darwin_amd64
mv terraform-provider-cos_v0.1 ~/.terraform.d/plugins/blazehu.com/edu/cos/0.1/darwin_amd64- write
demo.tf
terraform {
required_providers {
cos = {
source = "blazehu.com/edu/cos"
version = "0.1"
}
}
}
provider "cos" {
region = "ap-shanghai"
}
resource "cos_bucket_resource" "demo" {
name = "terraform-1251762279"
acl = "private"
# acl = "public-read-write"
}
data "cos_bucket_data_source" "test" {
name = cos_bucket_resource.demo.id
} - run
terraform init
Initializing the backend...
Initializing provider plugins...
- Finding blazehu.com/edu/cos versions matching "0.1.0"...
- Installing blazehu.com/edu/cos v0.1.0...
- Installed blazehu.com/edu/cos v0.1.0 (unauthenticated)
Terraform has created a lock file .terraform.lock.hcl to record the provider
selections it made above. Include this file in your version control repository
so that Terraform can guarantee to make the same selections by default when
you run "terraform init" in the future.
Terraform has been successfully initialized! - run
terraform apply -auto-approve
, create a cos bucketTerraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
+ create
<= read (data resources)
Terraform will perform the following actions:
# data.cos_bucket_data_source.test will be read during apply
# (config refers to values not yet known)
<= data "cos_bucket_data_source" "test" {
+ id = (known after apply)
+ name = (known after apply)
+ owner = (known after apply)
}
# cos_bucket_resource.demo will be created
+ resource "cos_bucket_resource" "demo" {
+ acl = "public-read-write"
+ id = (known after apply)
+ name = "terraform-1251762279"
+ update_at = (known after apply)
}
Plan: 1 to add, 0 to change, 0 to destroy.
cos_bucket_resource.demo: Creating...
cos_bucket_resource.demo: Creation complete after 1s [id=terraform-1251762279]
data.cos_bucket_data_source.test: Reading...
data.cos_bucket_data_source.test: Read complete after 0s [id=terraform-1251762279]
Apply complete! Resources: 1 added, 0 changed, 0 destroyed. - change acl to
public-read-write
, runterraform apply -auto-approve
cos_bucket_resource.demo: Refreshing state... [id=terraform-1251762279]
Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
~ update in-place
<= read (data resources)
Terraform will perform the following actions:
# data.cos_bucket_data_source.test will be read during apply
# (config refers to values not yet known)
<= data "cos_bucket_data_source" "test" {
~ id = "terraform-1251762279" -> (known after apply)
name = "terraform-1251762279"
~ owner = "qcs::cam::uin/794369159:uin/794369159" -> (known after apply)
}
# cos_bucket_resource.demo will be updated in-place
~ resource "cos_bucket_resource" "demo" {
~ acl = "public-read-write" -> "private"
id = "terraform-1251762279"
name = "terraform-1251762279"
# (1 unchanged attribute hidden)
}
Plan: 0 to add, 1 to change, 0 to destroy.
cos_bucket_resource.demo: Modifying... [id=terraform-1251762279]
cos_bucket_resource.demo: Modifications complete after 1s [id=terraform-1251762279]
data.cos_bucket_data_source.test: Reading... [id=terraform-1251762279]
data.cos_bucket_data_source.test: Read complete after 0s [id=terraform-1251762279]
Apply complete! Resources: 0 added, 1 changed, 0 destroyed. - verify if no changes, run
terraform apply -auto-approve
cos_bucket_resource.demo: Refreshing state... [id=terraform-1251762279]
No changes. Your infrastructure matches the configuration.
Terraform has compared your real infrastructure against your configuration and found no differences, so no changes are needed.
Apply complete! Resources: 0 added, 0 changed, 0 destroyed. - destroy the resources, run
terraform destroy -auto-approve
cos_bucket_resource.demo: Refreshing state... [id=terraform-1251762279]
Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
- destroy
Terraform will perform the following actions:
# cos_bucket_resource.demo will be destroyed
- resource "cos_bucket_resource" "demo" {
- acl = "private" -> null
- id = "terraform-1251762279" -> null
- name = "terraform-1251762279" -> null
- update_at = "2022-01-29T11:28:31+08:00" -> null
}
Plan: 0 to add, 0 to change, 1 to destroy.
cos_bucket_resource.demo: Destroying... [id=terraform-1251762279]
cos_bucket_resource.demo: Destruction complete after 1s
Destroy complete! Resources: 1 destroyed.Tip: You can also retrieve detailed Terraform and provider logs by setting the environment variable TF_LOG. Please include a detailed logs with any bug reports so the author can identify and address the bug. To learn more about log levels and how to interpret a crash log, refer to the Debugging Terraform Documentation.