Johnman.md

プログラミングのことや個人的なことを書きます。たぶん。

outputsだけを追加してtarraform planするとtfnotifyがパースエラーになる

Terraform を触っていて若干面倒になった部分があったのでメモ。

現状としては、「outputsだけを追加してterraform planするとtfnotifyがパースエラーで落ちる」というものです。

tfnotifyとは

tfnotifyはメルカリが開発しているTerraformの実行結果を通知してくれるCLIです。

GitHubやSlackなどに結果を投げられます。

github.com

tfnotifyのexit code判定

tfnotifyは下記の正規表現によってterraform planが成功したかどうかを判定しています。

リソースが変更されれば Plan: \d にマッチして、なにも追加されていなければ No changes. にマッチするというわけですね。

// NewPlanParser is PlanParser initialized with its Regexp
func NewPlanParser() *PlanParser {
    return &PlanParser{
        Pass: regexp.MustCompile(`(?m)^(Plan: \d|No changes.)`), // ここ
        Fail: regexp.MustCompile(`(?m)^(Error: )`),
        // "0 to destroy" should be treated as "no destroy"
        HasDestroy:   regexp.MustCompile(`(?m)([1-9][0-9]* to destroy.)`),
        HasNoChanges: regexp.MustCompile(`(?m)^(No changes. Infrastructure is up-to-date.)`),
    }
}

https://github.com/mercari/tfnotify/blob/master/terraform/parser.go#L61-L70

また、exit codeは下記のswitch文で判定しています。

PassとFailの正規表現両方にマッチしなかったものはパースエラーとして処理されます。

var exitCode int
switch {
case p.Pass.MatchString(body):
    exitCode = ExitPass
case p.Fail.MatchString(body):
    exitCode = ExitFail
default:
    return ParseResult{
        Result:   "",
        ExitCode: ExitFail,
        Error:    fmt.Errorf("cannot parse plan result"),
    }
}

https://github.com/mercari/tfnotify/blob/master/terraform/parser.go#L101-L113

outputsだけを追加したときの出力

しかし、リソースを変更せずにoutputsだけを追加した場合、下記のような出力になります。

pagerduty_schedule.secondary: Refreshing state...
pagerduty_schedule.primary: Refreshing state...
pagerduty_team_membership.team[0]: Refreshing state...
pagerduty_team_membership.team[1]: Refreshing state...
pagerduty_escalation_policy.team: Refreshing state...
pagerduty_service.team: Refreshing state...
pagerduty_service_integration.datadog: Refreshing state...

------------------------------------------------------------------------

Changes to Outputs:
  + my_another_project_name = "my-another-project"

------------------------------------------------------------------------

outputsの変更のみが出力されていますね。

リソースの変更がないため Plan: は出力されません。さらに、まったく変更がない(outputsを変更している)ため、No changes. も出力されません。

その結果、tfnotifyの正規表現にマッチせず、パースエラーとしてterraform planは成功するけれどtfnotifyで失敗するということになります。

対応策

今回のoutputsはremote stateから読み込んで外部で使いたいものだったので、outputsとそれを使うリソース定義を同時に行うということができませんでした。

また、terraform planとtfnotifyをCIで実行していたので無理やりマージするのは抵抗があり、雑ですがサービスに影響しない変更を加え、無理やりPlanが結果に出るようにしました。

基本的にはoutputsはリソースの定義と一緒に追加してしまうのがいいかもしれません。

まとめ

下記のことが原因で、outputsだけを追加してterraform planするとtfnotifyがパースエラーになってしまうということが起きました。 1. tfnotifyは正規表現でパースしている 2. outputsだけを追加したterraform planの出力は正規表現にマッチしない 3. パースエラーとして処理される

対応としては、極力outputsはリソースの変更と一緒に追加したほうがよさそうです。

また、issueを投げてみました。時間があるときにPRを投げられるといいなと思います。 github.com