16
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

OpenTofu の Lua/Go ですぐに自作関数を定義できる機能を試す

Last updated at Posted at 2025-03-24

はじめに

ちょうど一年前の2024年4月に OpenTofu から、HCL中の式で簡単にGoやLuaで自作したカスタム関数を呼び出せる機能およびプロバイダがリリースされていたので、本記事でそれを試していきたいと思います。

元々 OpenTofu / Terraform 双方でカスタム関数自体の機能は提供されていますが、ちょっとした関数を定義するだけでも自作プロバイダを用意する必要があり面倒です。

Provider-defined functions are supported in Terraform 1.8 and later.
https://developer.hashicorp.com/terraform/plugin/framework/v1.13.x/functions/concepts

As of OpenTofu 1.7.0, providers may define their own functions to be available during execution.
https://opentofu.org/docs/language/functions/#provider-defined-functions

今回紹介する機能はそのままTerraformコード中にカスタム関数のコードを書けばいいだけなので、とても簡単に使うことができます。

実際に試してみる

(この記事のソースコードは https://gitlab.com/ksaitou/2025-03-15_opentofu-immediate-func にあります)

環境準備

.opentofu-version ファイルを用意した上で、 tenv でOpenTofuをインストールして試します。

.opentofu-version
1.9.0
# OpenTofu のインストール
$ tenv tofu install

今回試用するものをプロバイダとして定義します。残念ながら去年(2024-04)の発表以降開発はアクティブではないようです。

main.tf
terraform {
    required_providers {
        lua = {
            source = "opentofu/lua"
            version = "0.0.2"
        }
        go = {
            source = "opentofu/go"
            version = "0.0.3"
        }
    }
}
# プロジェクトの初期化
$ tofu init

Lua (opentofu/lua)

まずLua関数の実行から行っていきます。

lua.tf
locals {
    lua_add = <<EOT
function add( input )
    return input.foo + input.bar
end

return add
EOT
}

output "example" {
    value = provider::lua::exec(local.lua_add, {"foo": 100, "bar": 200})
}

Luaのソースコードからは関数を返せばそれを lua::exec で呼べるようです。

上記を実行すると、きちんと計算結果が表示されます。

$ tofu plan
Changes to Outputs:
  + example = 300

Go (opentofu/go)

つづいて、Go関数の実行も試してみます。

lib.go
package lib

type FooBar struct {
	Former int `tf:"foo"`
	Latter int `tf:"bar"`
}

func Add(foobar FooBar) int {
	return foobar.Former + foobar.Latter
}
go.tf
provider "go" {
    go = file("./lib.go")
}

output "test" {
    value = provider::go::add({"foo": 300, "bar": 400})
}

package lib 上で定義したエクスポートされた関数(大文字から始まる関数)をその関数名を用いて呼び出し可能なようです。

上記を実行すると、きちんと計算結果が表示されます。

$ tofu plan
Changes to Outputs:
  + test    = 700

なぜGoのソースコードをいきなり実行できるのか?

opentofu/go では ./lib.go として外部のGoファイルをスクリプト言語のように指定していますが、本来Go言語はビルドしないと動かないはずです。どうなっているのでしょう?

プロバイダのソースコードを見てみましょう。

https://github.com/opentofu/terraform-provider-go/blob/main/main.go

package main

import (
// ...
	"github.com/traefik/yaegi/interp"
	"github.com/traefik/yaegi/stdlib"
)
// ...
						&tfprotov6.SchemaAttribute{
							Name:     "go",
							Type:     tftypes.String,
							Required: true,
						},
// ...
				codeVal := cfg["go"]
				var code string
				err = codeVal.As(&code)

// ...
				interpreter := interp.New(interp.Options{})
				if err := interpreter.Use(stdlib.Symbols); err != nil {
// ...
				_, err = interpreter.Eval(code)
// ...
				exports := interpreter.Symbols("lib")
				libExports := exports["lib"]

ざっと読む限り、go プロパティに指定したコードをGoのインタプリタ実装である yaegi に渡しているようです。

つまり、ここで書いているGoはビルドされて動く通常のGoではありません。通常のGoプロバイダのように何でも自由に実装できると考えないほうがよさそうです。そういう用途であれば真っ当にGoでプロバイダを実装することになるでしょう。

プロバイダの実装については、以下の私のエントリも参考にしてください。

この機能(プロバイダ)は Terraform でも使えるのか?

これらのプロバイダがTerraformでも同じように使えるのか試してみます。

プロバイダがTerraformレジストリ側には存在していないので、プロバイダの参照について registry.opentofu.org/source の先頭につけてあげれば参照可能です。

main.tf
terraform {
    required_providers {
        lua = {
            source = "registry.opentofu.org/opentofu/lua"
            version = "0.0.2"
        }
        go = {
            source = "registry.opentofu.org/opentofu/go"
            version = "0.0.3"
        }
    }
}

Terraformもインストールしましょう。

.terraform-version
1.11.2
# Terraform のインストール
$ tenv terraform install

これで参照自体はできるのですが、以下のようにそれぞれ実行可能かどうかは異なってしまいました。

  • opentofu/lua: OpenTofu上と変わらず実行可能
  • opentofu/go: There is no function named "provider::go::add". と言われエラーで終了
    • そもそもプロバイダが任意の関数名を定義できるのがOpenTofuだけの機能の模様……

OpenTofuもTerraformと同じプロトコル(tfprotov6)を話すのですが、動的な関数部分についてはOpenTofu側のみの拡張のようです。

両方で実行したい場合はLuaに限定したほうがよさそうです。

まとめ

OpenTofuで使えるインスタントな自作関数定義機能を使ってみました。

リポジトリを見る限り、去年の発表時点から開発が止まってしまっているので実際の利用はためらうところですが、今後に期待です。

16
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
16
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?