terraformに対応していないクラウドリソースを local-exec を用いてterraform化してみます。 今回はBigQueryのユーザー定義関数(UDF)でやってみます。

実装

さて早速。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
variable project{}

resource "null_resource" "bigquery-udf" { <- #1
  triggers = {
    query = "CREATE OR REPLACE FUNCTION my_dataset.TEST_FUNCTION(x INT64) AS (x + 1);" <- #2
  }
  provisioner "local-exec" { <- #3
    interpreter = ["bq", "query", "--use_legacy_sql=false", "--project_id=${var.project}"] <- #4
    command     = self.triggers.query
    on_failure  = fail <- #5
  }
  provisioner "local-exec" {
    when        = destroy <- #6
    interpreter = ["bq", "query", "--use_legacy_sql=false", "--project_id=${var.project}"]
    command     = "DROP FUNCTION IF EXISTS ${element(regex("FUNCTION\\s(.+?)[\\s\\(]", file("${path.module}/udf/${each.value}")), 0)}" <- #7
    on_failure  = fail
  }
}

解説

#1

執筆時点では google provderはBigQueryのUDFに対応していないため、 null_resource として定義します。 https://www.terraform.io/docs/provisioners/null_resource.html

#2

リソースの本体です。この部分が変更されるとresource updateとして扱われます。 https://registry.terraform.io/providers/hashicorp/null/latest/docs/resources/resource#argument-reference

#3

リソースのcreate時の挙動をlocal-exec provisionerとして定義します。 https://www.terraform.io/docs/provisioners/local-exec.html

#4

実際に実行するコマンドを定義します。 今回の例では command にSQL自身を、interpreter にはSQLを実行するための bq コマンドを記述します。 https://www.terraform.io/docs/provisioners/local-exec.html#argument-reference

#5

コマンドの失敗時の挙動 (terraformコマンド自体を失敗させるかどうか) を設定します。 https://www.terraform.io/docs/provisioners/index.html#failure-behavior

#6

when = destroyを宣言するとリソース削除時に実行するコマンドを定義できます。 https://www.terraform.io/docs/provisioners/index.html#destroy-time-provisioners

#7

terraformとは関係ありませんが、リソース削除時はDDLから関数名を正規表現で抽出してDROPするようにしてみました。


複数のUDFを管理する場合はprovisionerの定義が冗長になるので、queryをvariableに定義してfor_each を使う実装になるかと思います。 CI/CDパイプライン等のterraformコマンドの実行環境にbqコマンドを用意しなければならないデメリットがあるため、リソースをterraform管理にするメリットがそのコストを上回ると判断される場合には有用かと思います。