テキストファイルの中の文字列を管理できるansible.builtin.lineinfileモジュール

林如弥氏:私の大いなる力で、lineinfileを責任を持って行使してしまって、やらかしましたという発表です。お願いします。

みなさん、ansible.builtin.lineinfileモジュールを使っていると思います。とても便利ですよね。ドキュメントの一角を切り取ってきたのですが「Manage lines in text files」ということで、テキストファイルの中の文字列を管理できるモジュールで、とても便利です。

私たちのユースケースでいうと、主にアプリや、OSの設定を一部変えることをやっています。

詳細は割愛しますが、こういうことをゴチャゴチャとlineinfileで、ありがたいことに使わせてもらっています。

copyやtemplatesという便利なモジュールもありますが、ファイルを丸ごと置き換えられないようなケースで使うのがlineinfileかなと思っていますし、特定の行を、シュパッと狙い撃って修正できる、これもまたいいところです。

ちょっとうちのつらみなんですけれども、けっこう手作業で作られた不揃いの環境があって(笑)、同じファイルでぜんぜん中身が違うけど、特定のパラメーターだけを変えたり、追加できたりするのがlineinfileで、だからみんな大好きですよね。

そんなlineinfileのやらかしを、2つほど持ってきたので、紹介します。

lineinfileを使って失ってしまった冪等性

1個目、やらかし1ということで「実行するたびに重複が発生する/etc/hosts」というタイトルです。

これはサンプルですが、172.18.9.32みたいなIPに、今ショートネームみたいな、s1 sv1みたいなのがついています。ここに、ちょっと見直しをしてserver1みたいなものを追加したくなったわけです。

ここでやはりlineinfileですよと。regexpで先頭の正規表現かけて、後半はグループ化でbackrefsであとで再利用する。それで、最後の末尾にserver1を足すと。

これ、一見すごくよさそうに見えるんです。1回なら動くんです。

しかし、これは打つたびにserver1がこのように増えていく、増えていく、増えていく。しかも、これってhostsファイルとしては、どうも問題がないらしくて、気づくまでに時間がかかってしまいます。いろいろなケースで再利用したせいで、どんどん増えていったという問題が起きました。

こうして、Ansibleの代名詞と言ってもいいぐらいの冪等性を、lineinfileを使って(笑)失ってしまったというやらかしが1個目です。

1回の実行だけだと1箇所しか文字列は変換されない

そして、やらかし2です。「変換対象が複数回出るなら、replaceモジュールを使いましょう」というやらかし。

もう、この時点でピーンときた方もいると思うのですが、とあるミドルウェアの設定ファイルに、DB01みたいな宛先が書いてあったんです。そのDBをバージョンアップして、その向き先だけアプリでは書くことがあったんです。

「テキストの中の特定文字列を変えるならlineinfileだろう!」と思って、こんな感じのことを書きました。

先ほどとあまり変わらないのですが、regexpでDestの文字列を拾って、変えたい部分だけNewDB01みたいなかたちで書いたんです。すると、こうなりました。

どういう動きをしたかというと、後半のDB01だけNewDB01というかたちになるんです。つまり、1個目に出たDB01は変換されなかったんです。もう1回同じPlaybookをそのまま打つと、きちんと変換されます。

つまり、1回の実行だけだと1箇所しか変換されないんです。これに気づかなかった私が、アプリチームに「どうぞ、もう変えておきましたので」と言って、正常確認をお願いしたのですが、特定のコネクションプールだけ古いほうにつながり、新しいところには1箇所だけつながっている。そういう状況を作ってしまって、混乱を生んでしまいました。当時の同僚のみなさんにお詫びをしたいと思います。

これは、しっかりとドキュメントに書いてあります。Synopsisという、概要とでも訳すんですかね、そこに「See the ansible.builtin.replace module if you want to change multiple, similar lines」。「似たような、複数の場所を変更するなら、きちんとreplaceモジュールを見てね」ときっちりと書いてあるのに、僕はlineinfileを好きすぎて、1回で失敗したというやらかしの話でした(笑)。

lineinfileを使用する時は冪等性を確認する

まとめです。lineinfileは、やはりとても便利ですが、書き方次第では冪等性が失われます(笑)。きちんと複数回実行しても、同じ箇所が同じだけきちんとOKになるか、2回目やったら増えないかというところを確認しましょう。

あとは、複数箇所を同時に1回のplaybookの実行で変えたいのであれば、ここはreplaceモジュールの出番なので、lineinfileはまた別の機会で使ってくださいという話で、私の発表を終わります。ご清聴ありがとうございました。