injecuetとは: injecuet: CUEに環境変数を注入する便利CLIツールを書いた - Sexually Knowing
これまでCUEに埋め込むデータソースとして環境変数だけだったのですが、新たにTerraform stateを参照する機能を追加しました。
こういうCUEがあって:
@inject(tfstate,stateURL=./terraform/ok/terraform.tfstate) name: string @inject(tfstate,name=output.user.name) age: int @inject(tfstate,name=output.user.age)
terraform/ok/terraform.tfstate
がこういうかんじだとして:
{ "version": 4, "terraform_version": "1.1.6", "serial": 2, "lineage": "3124ddff-8837-9bb1-a0d6-fe4fd14969aa", "outputs": { "user": { "value": { "age": 17, "name": "aereal" }, "type": [ "object", { "age": "number", "name": "string" } ] } }, "resources": [] }
injecuet ./tfstate.cue
を実行するとこんな風に解決されます:
{ @inject(tfstate,stateURL=./terraform/ok/terraform.tfstate) name: "aereal" @inject(tfstate,name=output.user.name) age: 17 @inject(tfstate,name=output.user.age) }
attributeの形式を変更
before:
@injectenv(USER)
after:
@inject(env,name=USER)
Terraform state対応を入れるにあたり、データソースを識別できるようより拡張性のあるフォーマットに変えました。
古い形式も現在サポートしていますが、そのうち消えるかもしれません。
実装の話を簡単にすると、元々は (*Attribute) Contents() string という関数でattributeの中身を得て、それを strings.Split
していました。
Contents()
は @some_attr(ここだよ)
の ここだよ
を返します。
が、よくよく *Attribute
のメソッドを見て Arg(int)
などが生えていることに気がつきます。
Arg reports the contents of the ith comma-separated argument of a.
という説明の通り、attributeの括弧の中身をカンマ区切りのリストとみなす実装です。
このようにライブラリのサポートがより受けやすい形式にしようということで変えました。
tfstate-lookup最高
Terraform stateから値を取る処理はtfstate-lookupにおんぶにだっこです。とても助かっています。
fujiwara/tfstate-lookup: Lookup resource attributes in tfstate.
CUEとJSONにおける数値の扱い
ちょっとハックが必要だったのが数値の扱いです。具体的にはfloatとintで、ちょっと込み入ったややdirtyな実装になっています。
具体的にはここ: github.com
CUEはintとfloatという区別があるのですが、JSONはnumberというGoやCUEでいうintとfloatをまとめた型しかありません。 これは元になったECMAScriptの仕様に由来するものですね。
で、Goのencoding/jsonのunmarshalはデフォルトでJSONのnumberをfloat64に変換します。
Goのfloat64をCUEがintを求める式に埋めようとすると型の不一致でエラーになりますが、Terraform stateに数値が含まれているとCUEに埋められないのも不条理です。
なので以下の条件をすべて満たす際にint64へキャストするようにしています。
- CUEの式がintを受け入れる
- CUEの式が floatは受け入れない
- Terraform stateから得た値 (interface{}) がfloat32かfloat64である
理想的にはTerraform stateから得た値の小数部が0であることまで見るとよいのでしょうが、だいぶ大変なのでここらへんで諦めています。
良い実装方法があればPull Requestしてもらえると嬉しいです。