kakakakakku blog

Weekly Tech Blog: Keep on Learning!

Terraform Plugin Framework を使ったカスタムプロバイダの実装に入門できる Terraform チュートリアル「Custom Framework Providers」

Terraform チュートリアル「Custom Framework Providers」を試した❗️

Terraform から RESTful API を操作するカスタムプロバイダを実装しながら Terraform Plugin Framework の仕組みを学べて非常に良かった👌チュートリアルは計11種類から構成されていて一歩一歩進められる.3時間ぐらいあれば十分終わると思うけど,僕自身は朝活として毎日1,2個をコツコツと進めていた🕐

  • Implement a provider with the Terraform Plugin Framework
  • Configure provider client
  • Implement data source
  • Implement logging
  • Implement resource create and read
  • Implement resource update
  • Implement resource delete
  • Implement resource import
  • Implement automated testing
  • Implement documentation generation
  • Release and publish to the Terraform registry

developer.hashicorp.com

現在 Terraform でカスタムプロバイダを実装するためには Terraform Plugin Framework を使う選択肢と Terraform Plugin SDKv2 を使う選択肢がある.ドキュメントには今後新しく実装する場合は Terraform Plugin Framework 推奨と書いてある📝

developer.hashicorp.com

Hashicups API ☕

チュートリアルでは Hashicups という架空のコーヒーショップアプリケーションの RESTful API を Terraform から操作できるようにする☕ API リソースとしてはコーヒーを表現する /coffees と注文を表現する /orders があって,他にも JWT を使った認証の仕組みもある💡実装や Docker Compose ファイルは GitHub の hashicorp-demoapp/product-api-go リポジトリにある.

github.com

試しに Hashicups API を Docker Compose で起動して,API 操作を簡単に紹介する❗️

POST /signup

$ curl -X POST -s localhost:19090/signup -d '{"username":"education", "password":"test123"}'

POST /signin

$ HASHICUPS_TOKEN=$(curl -X POST -s localhost:19090/signin -d '{"username":"education", "password":"test123"}' | jq -r .token)

GET /coffees

$ curl -s http://localhost:19090/coffees | jq .
[
  {
    "id": 1,
    "name": "HCP Aeropress",
    "teaser": "Automation in a cup",
    "collection": "Foundations",
    "origin": "Summer 2020",
    "color": "#444",
    "description": "",
    "price": 200,
    "image": "/hashicorp.png",
    "ingredients": [
      {
        "ingredient_id": 6
      }
    ]
  },
  {
    "id": 2,
    "name": "Packer Spiced Latte",
    "teaser": "Packed with goodness to spice up your images",
    "collection": "Origins",
    "origin": "Summer 2013",
    "color": "#1FA7EE",
    "description": "",
    "price": 350,
    "image": "/packer.png",
    "ingredients": [
      {
        "ingredient_id": 1
      },
      {
        "ingredient_id": 2
      },
      {
        "ingredient_id": 4
      }
    ]
  },
  
  (中略)
  
    {
    "id": 9,
    "name": "Waypointiato",
    "teaser": "Deploy with a little foam",
    "collection": "Discoveries",
    "origin": "Fall 2020",
    "color": "#14C6CB",
    "description": "",
    "price": 250,
    "image": "/waypoint.png",
    "ingredients": [
      {
        "ingredient_id": 1
      },
      {
        "ingredient_id": 2
      }
    ]
  }
]

GET /orders

$ curl -s -H "Authorization: ${HASHICUPS_TOKEN}" http://localhost:19090/orders
[]

Terraform コード main.tf

まずは実装したカスタムプロバイダを使った Terraform コード main.tf を紹介するのが早いと思う.hashicups_order リソースを使って注文できる❗️

terraform {
  required_providers {
    hashicups = {
      source = "hashicorp.com/edu/hashicups"
    }
  }
  required_version = ">= 1.1.0"
}

provider "hashicups" {
  username = "education"
  password = "test123"
  host     = "http://localhost:19090"
}

resource "hashicups_order" "edu" {
  items = [
    {
      coffee   = { id = 3 }
      quantity = 2
    },
    {
      coffee   = { id = 1 }
      quantity = 2
    }
  ]
}

output "edu_order" {
  value = hashicups_order.edu
}

また hashicups_coffees データソースの実装もできる❗️

data "hashicups_coffees" "edu" {}

output "edu_coffees" {
  value = data.hashicups_coffees.edu
}

実際に terraform apply コマンドを実行してみると注文を登録できる☕

$ terraform apply

(中略)

Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: yes

hashicups_order.edu: Creating...
hashicups_order.edu: Creation complete after 0s [id=1]

Apply complete! Resources: 1 added, 0 changed, 0 destroyed.

Outputs:

edu_order = {
  "id" = "1"
  "items" = tolist([
    {
      "coffee" = {
        "description" = ""
        "id" = 3
        "image" = "/vault.png"
        "name" = "Vaulatte"
        "price" = 200
        "teaser" = "Nothing gives you a safe and secure feeling like a Vaulatte"
      }
      "quantity" = 2
    },
    {
      "coffee" = {
        "description" = ""
        "id" = 1
        "image" = "/hashicorp.png"
        "name" = "HCP Aeropress"
        "price" = 200
        "teaser" = "Automation in a cup"
      }
      "quantity" = 2
    },
  ])
  "last_updated" = "Sunday, 29-Oct-23 20:53:38 JST"
}

Hashicups API から直接注文を取得すると期待通りに登録されている👏

$ curl -s -H "Authorization: ${HASHICUPS_TOKEN}" http://localhost:19090/orders | jq .
[
  {
    "id": 1,
    "items": [
      {
        "coffee": {
          "id": 3,
          "name": "Vaulatte",
          "teaser": "Nothing gives you a safe and secure feeling like a Vaulatte",
          "collection": "Foundations",
          "origin": "Spring 2015",
          "color": "#FFD814",
          "description": "",
          "price": 200,
          "image": "/vault.png",
          "ingredients": [
            {
              "ingredient_id": 1
            },
            {
              "ingredient_id": 2
            }
          ]
        },
        "quantity": 2
      },
      {
        "coffee": {
          "id": 1,
          "name": "HCP Aeropress",
          "teaser": "Automation in a cup",
          "collection": "Foundations",
          "origin": "Summer 2020",
          "color": "#444",
          "description": "",
          "price": 200,
          "image": "/hashicorp.png",
          "ingredients": [
            {
              "ingredient_id": 6
            }
          ]
        },
        "quantity": 2
      }
    ]
  }
]

他にも terraform import コマンドを実行できるようにしたり,terraform-plugin-testing を使ってテストコードを実装したり,実際にカスタムプロバイダを実装するときに使うことになるであろうトピックに触れられたところも良かった👏

$ terraform import hashicups_order.edu 2
hashicups_order.edu: Importing from ID "2"...
hashicups_order.edu: Import prepared!
  Prepared hashicups_order for import
hashicups_order.edu: Refreshing state... [id=2]

Import successful!

$ TF_ACC=1 go test -count=1 -v
=== RUN   TestAccCoffeesDataSource
--- PASS: TestAccCoffeesDataSource (1.38s)
PASS
ok      terraform-provider-hashicups/internal/provider  1.599s

$ TF_ACC=1 go test -count=1 -run='TestAccOrderResource' -v
=== RUN   TestAccOrderResource
--- PASS: TestAccOrderResource (2.88s)
PASS
ok      terraform-provider-hashicups/internal/provider  3.226s

github.com

Terraform Plugin Framework

Terraform Plugin Framework では Metadata にリソース名・データソース名を定義して,Schema にリソースの構造体を定義する.さらに Create / Read / Update / Delete にリソースの操作を実装する.Terraform コード main.tf 側のコードと見比べることで「なるほど💡こうやってカスタムプロバイダと Hashicups API が連携してるのか❗️」というイメージを深めることができて,とてもわかりやすい仕組みになっていると思った.

github.com

そして Create / Read / Update / Delete では Hashicups API を直接呼び出すのではなく hashicups-client-go を使って r.client.CreateOrder()r.client.GetOrder() のように実行する.

github.com

まとめ

Terraform Plugin Framework を使ったカスタムプロバイダの実装に入門できる Terraform チュートリアル「Custom Framework Providers」を試した❗️Hashicups という架空のコーヒーショップアプリケーションの RESTful API を Terraform から操作できるようにしながら Terraform Plugin Framework の仕組みを学べて非常に良かった👌

Terraform Registry に公開されてる Terraform Provider Hashicups はこちら〜 \( 'ω')/

github.com