Thanks Driven Life

日々是感謝

terraform plan の実行結果で、属性値が変更になる行に色付けする sed

TL;DR

readonly escape_ansi=$(printf '\033')

sed -e '/".*" => ".*"$/!b' \
    -e '/^.*: *"\(.*\)" => "\1"$/!s/.*/'"$escape_ansi"'[31m&'"$escape_ansi"'[m/'

f:id:gongoZ:20160702110516p:plain

経緯

毎晩暑い日が続く日本、AWS の各種リソース管理を Terraform で行っている皆様におかれましては、 日々の業務において terraform plan をよくお使いになられていることと存じます*1

そんな中、例えばこのような実行結果が表示されたとします:

..
.. (message)
..

+ aws_security_group.app
    ingress.#:                   "" => "1"
    ingress.0.cidr_blocks.#:     "" => "1"
    ingress.0.cidr_blocks.0:     "" => "192.0.2.0/24"
    ingress.0.from_port:         "" => "80"
    ingress.0.protocol:          "" => "tcp"
    ingress.0.to_port:           "" => "80"

-/+ aws_security_group.db
    ingress.#:                   "2" => "2"
    ingress.0.cidr_blocks.#:     "1" => "1"
    ingress.0.cidr_blocks.0:     "198.51.100.0/24" => "198.51.100.0/24"
    ingress.0.from_port:         "3306" => "3306"
    ingress.0.protocol:          "6" => "tcp"
    ingress.0.to_port:           "3306" => "3306"
    ingress.1.cidr_blocks.#:     "" => "1"
    ingress.1.cidr_blocks.0:     "" => "203.0.113.0/24"
    ingress.1.from_port:         "" => "5432"
    ingress.1.protocol:          "" => "tcp"
    ingress.1.to_port:           "" => "5432"

-/+ aws_security_group.mail
    ingress.#:                   "2" => "1"
    ingress.0.cidr_blocks.#:     "1" => "1"
    ingress.0.cidr_blocks.0:     "198.51.100.0/24" => "198.51.100.0/24"
    ingress.0.from_port:         "587" => "587"
    ingress.0.protocol:          "6" => "tcp"
    ingress.0.to_port:           "587" => "587"
    ingress.1.cidr_blocks.#:     "1" => ""
    ingress.1.cidr_blocks.0:     "198.51.100.0/24" => ""
    ingress.1.from_port:         "995" => ""
    ingress.1.protocol:          "6" => ""
    ingress.1.to_port:           "995" => ""

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

(実行結果はてきとうです)

各セキュリティーグループのルール数が2、3個なのでまだまだ見えますが、例えばルール数が20個とかになるとかなりの行数が目に入ります。その中で どの行(属性)が変更なのかぱっと見、わかりづらい と思うわけです。思いました。

まあそんなわけで、属性値に変更のある場所がわかりやすく見えればいいな、ということで、いくつか方法はあると思いますが、今回は sed でやってみました。

sed

readonly escape_ansi=$(printf '\033')

sed -e '/".*" => ".*"$/!b' \
    -e '/^.*: *"\(.*\)" => "\1"$/!s/.*/'"$escape_ansi"'[31m&'"$escape_ansi"'[m/'
  1. "xx" => "yy" という文字列(xxとyyは任意)を 含まない 行はスキップして次に進む
  2. "xx" => "xx" という条件に一致しない(つまり左と右の "" 内の値が 同じではない )場合 に、赤で色付けする

こんな感じでできました。パターンは単純なんですが terraform plan の実行結果に対してだけ使うのであれば充分かなと思います。

ついでにこいつをスクリプトに落とすと、雰囲気こんな感じ

#!/bin/sh

readonly escape_ansi=$(printf '\033')
readonly program_name=$0

if [ -p /dev/stdin ] ; then
    cat -
else
    if [ ! $# -ge 1 ] ; then
        echo "$0: [ERROR] You must specify file."
        exit 1;
    fi

    if [ ! -f "$1" ] ; then
        echo "$0: [ERROR] \"$1\" No such file."
        exit 1;
    fi

    cat "$1"
fi | sed -e '/".*" => ".*"$/!b' \
         -e '/^.*: *"\(.*\)" => "\1"$/!s/.*/'"$escape_ansi"'[31m&'"$escape_ansi"'[m/'

てきとうに tpdiff とか名前で保存しておいて

$ terraform plan | tpdiff

こんな感じで、冒頭の画像のように表示されます。多分。

ひとまず

あたりでは動いているようです。

まとめ

sed 難しい

おまけ

当初、sed の色付けする部分を

-e $'/^.*: *"\\(.*\\)" => "\\1"$/!s/.*/\e[31m&\e[m/'

みたいな感じでやってたんですが、 POSIX 準拠してるかってチェックしてくれる shellcheck を使うと

fi | sed -e '/".*" => ".*"$/!b'
         -e $'/^.*: *"\\(.*\\)" => "\\1"$/!s/.*/\e[31m&\e[m/'
            ^-- SC2039: In POSIX sh, $'..' is undefined.

ってな感じで怒られたので、printf 使うようにしました。

*1:手元実行なんかせず、Atlasにお任せしてる人が多いのかもしれない