(This talk was written in a caffeine fueled haze over the last few days.
All aboard the low standards limbo!)
(Or one of it's various forks)
"Infrastructure automation to provision and manage resources in any cloud or data center."
The simulation
We live in
The simulation
We live in
Our AI overlords
This concept broadly known as Infrastructure As Code
Terraform has a 63.6% percent market share
(Excluding other forks of terraform like open tofu)
[Firefly state of IAC 2024]
Why bother?
¯\_(ツ)_/¯
Super Important Business
Critical Server™
Super Important Business
Critical Server™
"Restructuring"
Super Important Business
Critical Server™
Super Important Business
Critical Server™
Years Pass...
Super Important Business
Critical Server™
Years Pass...
Super Important Business
Critical Server™
Years Pass...
Super Important Business
Critical Server™
Years Pass...
Super Important Business
Critical Sever™
[DO NOT TOUCH]
Super Important Business
Critical Sever™
[DO NOT TOUCH]
You
S̵̯͊u̸̠͑p̴̩̓ȇ̴̗r̴͓̈́ ̴̡͐Ḯ̴̮m̷̦̃p̵̩̆o̵̢̾r̵̳͑t̸̨̂á̶̮n̴̤͘t̷̩̏ ̵͕́B̸̰͋ų̵̏s̷̝̓i̴̦̽n̸̬̈ē̴̟s̸̮̒s̴̻̊
̷̤̊C̴̜͝r̷͍̐ĭ̸͈t̵̹͒i̵͎̓ç̸̓ã̴͙ḷ̸͆ ̵̮̊S̷̯͊e̴̠̍v̸̡̒e̶̞͒r̶̲̕™̷̠̓
̸̹͋
̴̡̎[̶̨́D̴̠̈́O̸̭͑ ̵̠̃N̴͈̂Ȍ̵̺T̸͖̓ ̵̮͘T̶̢̅O̷̤͂U̵͓̍C̴̭̍H̴͖͂]̷͔̌
You
S̵̯͊u̸̠͑p̴̩̓ȇ̴̗r̴͓̈́ ̴̡͐Ḯ̴̮m̷̦̃p̵̩̆o̵̢̾r̵̳͑t̸̨̂á̶̮n̴̤͘t̷̩̏ ̵͕́B̸̰͋ų̵̏s̷̝̓i̴̦̽n̸̬̈ē̴̟s̸̮̒s̴̻̊
̷̤̊C̴̜͝r̷͍̐ĭ̸͈t̵̹͒i̵͎̓ç̸̓ã̴͙ḷ̸͆ ̵̮̊S̷̯͊e̴̠̍v̸̡̒e̶̞͒r̶̲̕™̷̠̓
̸̹͋
̴̡̎[̶̨́D̴̠̈́O̸̭͑ ̵̠̃N̴͈̂Ȍ̵̺T̸͖̓ ̵̮͘T̶̢̅O̷̤͂U̵͓̍C̴̭̍H̴͖͂]̷͔̌
You
S̵̯͊u̸̠͑p̴̩̓ȇ̴̗r̴͓̈́ ̴̡͐Ḯ̴̮m̷̦̃p̵̩̆o̵̢̾r̵̳͑t̸̨̂á̶̮n̴̤͘t̷̩̏ ̵͕́B̸̰͋ų̵̏s̷̝̓i̴̦̽n̸̬̈ē̴̟s̸̮̒s̴̻̊
̷̤̊C̴̜͝r̷͍̐ĭ̸͈t̵̹͒i̵͎̓ç̸̓ã̴͙ḷ̸͆ ̵̮̊S̷̯͊e̴̠̍v̸̡̒e̶̞͒r̶̲̕™̷̠̓
̸̹͋
̴̡̎[̶̨́D̴̠̈́O̸̭͑ ̵̠̃N̴͈̂Ȍ̵̺T̸͖̓ ̵̮͘T̶̢̅O̷̤͂U̵͓̍C̴̭̍H̴͖͂]̷͔̌
You
New Super Duper
Critical Server
Destroy
Recreate
You
New Super Duper
Critical Server
Write 📖
Plan📝
Apply 🚀
Write 📖
Hashicorp Configuration Language 🎉
resource "some_resource" "some_block" {
some_config_block {
bla = "bla"
bla2 = 1337
bla3 = false
}
something = "something"
}
Hashicorp Configuration Language 🎉
resource "some_resource" "some_block" {
some_config_block {
bla = "bla"
bla2 = 1337
bla3 = false
}
something = "something"
}
resource "aws_instance" "some_server" {
instance_type = "t2.micro"
[...]
}
resource "aws_instance" "some_server" {
instance_type = "t2.micro"
[...]
}
resource "aws_instance" "some_server2" {
instance_type = "t2.micro"
[...]
}
resource "aws_ami" "some_ami" {
prefix = "someing/*"
}
resource "aws_instance" "some_server" {
ami = aws_ami.some_ami
instance_type = "t2.micro"
[...]
}
resource "aws_instance" "some_server2" {
ami = aws_ami.some_ami
instance_type = "t2.micro"
[...]
}
AMI
Write 📖
Plan📝
Apply 🚀
Plan 📖
Plan 📖
Terraform State
(What Terraform thinks you currently have)
Code Changes
(What you are declaring the next state of the system should be)
Compute
Difference
Plan 📖
terraform plan -out "tfplan"
aws.region: Reading...
aws.region: Read complete after 0s [id=us-east-1]
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:
- resource "region" "us-east-1" {
- # The literal entire AWS Region
- }
Plan: 0 to add, 0 to change, 1 to destroy.
───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
Saved the plan to: tfplan
To perform exactly these actions, run the following command to apply:
terraform apply "tfplan"
Write 📖
Plan📝
Apply 🚀
Apply 🚀
Apply 🚀
$ terraform apply
Enter a value: yes
Creating... module.crowdsrike_channel_file[291]
Apply complete! Resources: 1 added, 0 changed, 0 destroyed.
Outputs:
update-status = "¯\_(ツ)_/¯"
Terraform Providers
[STUFF]
Provider
Terraform Providers
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
}
Terraform Providers
Terraform Providers
Custom Terra
form providers
Custom Terra
form providers
Custom Terra
form providers
Custom Terra
form providers
gRPC
Custom Provider
[Golang]
Custom Terra
form providers
gRPC
Custom Provider
Custom Provider
[Golang]
Custom Terra
form providers
gRPC
Custom Provider
Custom Provider
[Golang]
Custom Terra
form providers
gRPC
Custom Provider
Custom Terra
form providers
gRPC
Custom Provider
[Some other
Language]
(You monster)
Custom Terra
form providers
gRPC
Custom Provider
[Some other
Language]
(You monster)
Custom Terra
form providers
gRPC
Custom Provider
[Some other
Language]
(You monster)
Custom Terra
form providers
gRPC
Custom Provider
[Some other
Language]
(You monster)
Custom Terra
form providers
"There has been a lot of interest in writing providers using languages other than Go, and people frequently ask for information on how to go about doing that. The Terraform team's policy at this time is that while it is technically possible to write providers in languages other than Go, our tooling, documentation, and ecosystem will all assume your provider is being written in and distributed as Go code for the time being."
https://developer.hashicorp.com/terraform/plugin/best-practices/provider-code
Custom Terra
form providers
"If you are not using Go Lang Good Luck Have Fun, You are on your own"
Custom Terra
form providers
Custom Terra
form providers
Custom Terra
form providers
package main
import "fmt"
func main() {
fmt.Println("Yam Orroight.")
}
Custom Terra
form providers
package main
import "fmt"
func main() {
var number int = 0
yam := "yam"
fmt.Println(yam, "Orroight.")
}
Custom Terra
form providers
package main
import "fmt"
type MyStruct struct {
name string
number int
}
func NewMyStruct(name string, number int) *MyStruct {
return &MyStruct{
name: name,
number: number,
}
}
func main() {
myStruct := NewMyStruct("Jeff", 25)
fmt.Println(myStruct)
}
Custom Terra
form providers
package main
import "fmt"
type MyStruct struct {
name string
number int
}
func NewMyStruct(name string, number int) *MyStruct {
return &MyStruct{
name: name,
number: number,
}
}
// Value receiver method - doesn't modify the struct
func (m *MyStruct) GetInfo() string {
return fmt.Sprintf("Name: %s, Number: %d", m.name, m.number)
}
func main() {
myStruct := NewMyStruct("Jeff", 25)
// Using value receiver method
fmt.Println(myStruct.GetInfo()) // Name: Jeff, Number: 25
}
Custom Terra
form providers
Custom Terra
form providers
(https://gobyexample.com/)
Custom Terra
form providers
Custom Terra
form providers
Custom Terra
form providers
Custom Terra
form providers
"Providers are Terraform plugins that define resources and data sources for practitioners to use. Providers are wrapped by a provider server for interacting with Terraform."
- https://developer.hashicorp.com/terraform/plugin/framework/providers
Custom Terra
form providers
Resource
Resource
Resource
Function
Data
Source
Custom Terra
form providers
Resource
Resource
Resource
Function
Data
Source
Custom Terra
form providers
Custom Terra
form providers
Custom Terra
form providers
terraform {
required_providers {
some_provider = {
source = "some/provider"
version = "0.0.1"
}
}
}
provider "some_provider" {
api_key = "foobar"
}
Custom Terra
form providers
type Provider interface {
// The name of the provider
Metadata(context.Context, MetadataRequest, *MetadataResponse)
// Schema configuration for the terraform provider
Schema(context.Context, SchemaRequest, *SchemaResponse)
// Called once for every time the provider is called to do a thing.
// e.g Create resources / Read the state of an app ECT..
Configure(context.Context, ConfigureRequest, *ConfigureResponse)
// A list of the "data sources" supported by the provider
DataSources(context.Context) []func() datasource.DataSource
// A list of the "resources" supported by the provider
Resources(context.Context) []func() resource.Resource
}
Custom Terra
form providers
type Provider interface {
// The name of the provider
Metadata(context.Context, MetadataRequest, *MetadataResponse)
// Schema configuration for the terraform provider
Schema(context.Context, SchemaRequest, *SchemaResponse)
// Called once for every time the provider is called to do a thing.
// e.g Create resources / Read the state of an app ECT..
Configure(context.Context, ConfigureRequest, *ConfigureResponse)
// A list of the "data sources" supported by the provider
DataSources(context.Context) []func() datasource.DataSource
// A list of the "resources" supported by the provider
Resources(context.Context) []func() resource.Resource
}
Custom Terra
form providers
type Provider interface {
// The name of the provider
Metadata(context.Context, MetadataRequest, *MetadataResponse)
// Schema configuration for the terraform provider
Schema(context.Context, SchemaRequest, *SchemaResponse)
// Called once for every time the provider is called to do a thing.
// e.g Create resources / Read the state of an app ECT..
Configure(context.Context, ConfigureRequest, *ConfigureResponse)
// A list of the "data sources" supported by the provider
DataSources(context.Context) []func() datasource.DataSource
// A list of the "resources" supported by the provider
Resources(context.Context) []func() resource.Resource
}
Custom Terra
form providers
type Provider interface {
// The name of the provider
Metadata(context.Context, MetadataRequest, *MetadataResponse)
// Schema configuration for the terraform provider
Schema(context.Context, SchemaRequest, *SchemaResponse)
// Called once for every time the provider is called to do a thing.
// e.g Create resources / Read the state of an app ECT..
Configure(context.Context, ConfigureRequest, *ConfigureResponse)
// A list of the "data sources" supported by the provider
DataSources(context.Context) []func() datasource.DataSource
// A list of the "resources" supported by the provider
Resources(context.Context) []func() resource.Resource
}
Custom Terra
form providers
Custom Terra
form providers
resource "some_type" "some_id" {
name = "something"
attr = "value"
list_vals = [
1,
2,
3
]
}
Custom Terra
form providers
"Resources are an abstraction that allow Terraform to manage infrastructure objects, such as a compute instance, an access policy, or disk. Providers act as a translation layer between Terraform and an API, offering one or more resources for practitioners to define in a configuration."
- https://developer.hashicorp.com/terraform/plugin/framework
Custom Terra
form providers
A thing that you can:
Custom Terra
form providers
type Resource interface {
// Called when thing needs creating
Create(context.Context, CreateRequest, *CreateResponse)
// Called when thing needs reading
Read(context.Context, ReadRequest, *ReadResponse)
// Called when thing needs updating
Update(context.Context, UpdateRequest, *UpdateResponse)
// Called when thing needs deleting
Delete(context.Context, DeleteRequest, *DeleteResponse)
[...]
}
Custom Terra
form providers
type Resource interface {
// Called when thing needs creating
Create(context.Context, CreateRequest, *CreateResponse)
// Called when thing needs reading
Read(context.Context, ReadRequest, *ReadResponse)
// Called when thing needs updating
Update(context.Context, UpdateRequest, *UpdateResponse)
// Called when thing needs deleting
Delete(context.Context, DeleteRequest, *DeleteResponse)
// Called to get properites the resource block should have
// and it's behaviours
Schema(context.Context, SchemaRequest, *SchemaResponse)
// The name of the thing!
Metadata(context.Context, MetadataRequest, *MetadataResponse)
// More functionality is available in extra methods
[...]
}
Custom Terra
form providers
type Resource interface {
// Called when thing needs creating
Create(context.Context, CreateRequest, *CreateResponse)
// Called when thing needs reading
Read(context.Context, ReadRequest, *ReadResponse)
// Called when thing needs updating
Update(context.Context, UpdateRequest, *UpdateResponse)
// Called when thing needs deleting
Delete(context.Context, DeleteRequest, *DeleteResponse)
// Called to get properites the resource block should have
// and it's behaviours
Schema(context.Context, SchemaRequest, *SchemaResponse)
// The name of the thing!
Metadata(context.Context, MetadataRequest, *MetadataResponse)
// More functionality is available in extra methods
[...]
}
Custom Terra
form providers
Custom Terra
form providers
data "data_type" "name" {
attr = "value"
}
// Use data elsewhere in tf file
Custom Terra
form providers
"Data sources are an abstraction that allow Terraform to reference external data. Unlike managed resources, Terraform does not manage the lifecycle of the resource or data. Data sources are intended to have no side-effects."
- https://developer.hashicorp.com/terraform/plugin/framework/data-sources
Custom Terra
form providers
Custom Terra
form providers
type DataSource interface {
// Name of the datasource block
Metadata(context.Context, MetadataRequest, *MetadataResponse)
// The structure of the data source
Schema(context.Context, SchemaRequest, *SchemaResponse)
// Run when the data source needs refetching
Read(context.Context, ReadRequest, *ReadResponse)
}
Custom Terra
form providers
type DataSource interface {
Metadata([...])
Schema([...])
Read([...])
}
type Resource interface {
Create([...])
Read([...])
Update([...])
Delete([...])
Schema([...])
Metadata([...])
[...]
}
Custom Terra
form providers
type DataSource interface {
Metadata([...])
Schema([...])
Read([...])
}
type Resource interface {
Create([...])
Read([...])
Update([...])
Delete([...])
Schema([...])
Metadata([...])
[...]
}
Data sources act in a similar capacity to a "Read-Only" resource
Custom Terra
form providers
"Functions are an abstraction that allow providers to expose computational logic beyond Terraform's built-in functions and simplify practitioner configurations"
- https://developer.hashicorp.com/terraform/plugin/framework/functions
Function.
It's a function
Custom Terra
form providers
locals {
two = provider::provider_name::add(1, 1)
}
Custom Terra
form providers
type Function interface {
// The name of the function
Metadata(context.Context, MetadataRequest, *MetadataResponse)
// Defines the arguments it accept's and it's return values
Definition(context.Context, DefinitionRequest, *DefinitionResponse)
// The code to execute when the function it run
Run(context.Context, RunRequest, *RunResponse)
}
Custom Terra
form providers
Schemas
Custom Terra
form providers
func (d *LightDataSource) Schema(
_ context.Context,
req datasource.SchemaRequest,
resp *datasource.SchemaResponse
) {
resp.Schema = schema.Schema{
Attributes: map[string]schema.Attribute{
"id": schema.StringAttribute{
Computed: true,
},
"value": schema.StringAttribute{
Required: true,
},
"some_other_value": schema.BoolAttribute{
Optional: true
},
},
}
}
Custom Terra
form providers
func (d *LightDataSource) Schema(
_ context.Context,
req datasource.SchemaRequest,
resp *datasource.SchemaResponse
) {
resp.Schema = schema.Schema{
Attributes: map[string]schema.Attribute{
"id": schema.StringAttribute{
Computed: true,
},
"value": schema.StringAttribute{
Required: true,
},
"some_other_value": schema.BoolAttribute{
Optional: true
},
},
}
}
datasource "some_name" "some_value" {
value = "huh"
some_other_value = "yay"
}
Custom Terra
form providers
Custom Terra
form providers
Custom Terra
form providers
Custom Terra
form providers
Custom Terra
form providers
https://developer.hashicorp.com/terraform/plugin/framework
Custom Terra
form providers
Provider Testing
Advanced Use Cases for Resources (Import)
Provider Documentation Generation
Much much more!
Provider Registry Publishing
What we have covered in this talk
Custom Terra
form providers
Wikimedia [CC0, CC-SA4]
@_Iroshi (Gophers CC0)
Custom Terra
form providers
Custom Terra
form providers
You can find my socials on
https//ryan.gd