BFT名古屋 TECH BLOG

日々の業務で得た知識を所属するエンジニアたちがアウトプットしていきます。

【Ansible】Ansibleでテキストファイルを編集するふたつの方法

 こんにちは!
 BFT名古屋支店の佐野です。

 以前から続く記事の流れに乗り、今回も実際にAnsibleを使用する例および方法についてお送りしていきます。
 今回お送りするのは、yum.confファイルなどのような設定ファイル内のテキストをAnsibleのモジュールによって編集する方法です。

 その他、こういった設定ファイルの管理を行なう場合のちょっとした話についてもお送りします。


はじめに:Ansibleでテキストファイルを“管理”する方法

 最初から元も子もない話をしてしまうと、筆者としては「テキストファイルを編集する」ということに関して、Ansibleは「どちらかというと苦手である」という認識を持っています。

 Ansibleを有効に活用するできるのは多数のクライアントを同時に管理する場合であるという都合上、テキストファイルを編集するということに関しても、一度に多くのクライアントを相手にして共通した内容にする処理を行なうという形になることが多いと思われます。
 その場合において筆者が経験した多くのケースでは、各クライアントに存在する同名のテキストファイルに対して編集による内容変更・追加ではなく、変更済のテキストファイルをクライアントに上書きコピーを行なうという手法を使用しました。
 クライアントが持つ設定内容がすべて同一のものであり、その内容を変更・追加してクライアントに再適用するのであれば、変更後の設定ファイルをクライアントに向けて配り直す方がAnsibleの場合は確実であり、簡便であると言えます。

 なぜそう言えるのかというと、Ansibleにてテキストファイルを編集する場合はテキスト内容を正規表現で指定し、その部分を基準として挿入や置換を行なう仕組みとなっているためです。
 管理対象のクライアントが持つ管理対象のテキストファイルすべてに共通する記述があれば、この方法で管理を行なうことができます。
 しかし、すべてのクライアントが同じ内容の管理対象テキストファイルを使っているのであれば前述の通り設定変更後のファイルを配布した方がよく、そうでない場合は管理対象テキストファイルすべてに正規表現で指定できる共通の部分があり、かつその共通の部分が編集したい部分の付近になければいけません。
 (一応、テキスト挿入の場合は正規表現にて指定した内容が存在しなかった場合、EOFに挿入されます)

 複数の異なる構造のテキストファイルの内容を編集する場合、この点を加味してAnsibleを使用するか、直接編集を行なうかの検討を行なう必要が出てくるかと思います。
 もちろんPlaybookを詳細に書き込むことで、細やかに処理を行なうことも可能かと思いますが、そのPlaybookを作るのが早いかAnsibleを使わず直接編集するのが早いかは、見極めることが必要です。

 以上を踏まえたうえで、テキストファイルの編集を行なうためのモジュールとなる以下ふたつについて、それぞれの使い方と違いについて解説をいたします。
 (ちなみに「変更済のテキストファイルをクライアントに上書きコピーを行なう」手法を取る場合はcopyモジュールを使用します。copyモジュールを使用するケース、使い方の解説については別記事にてお送りしたいと思います)

使用モジュール 概要
lineinfile テキストファイルの内容を行単位で追加します
blockinfile テキストファイルにマーカーラインで囲まれたテキストブロックを挿入・更新、または削除します

テキストファイルに文章を挿入するPlaybook(lineinfileモジュールの場合)

 例として、yumコマンドの動作を決定する設定ファイルである/etc/yum.confに対してAnsibleでテキストの挿入を行ないます。
 今回の場合は既存に設定されたプロキシーの直下に、新たなプロキシーの設定を書き込みます。
 lineinfileモジュールでそれを行なう場合、Playbookの作成例は以下の通りになります。

- hosts: all

  tasks:
  - name: set yum proxy
    lineinfile:
      dest: /etc/yum.conf
      insertafter: "^proxy=.*$"
      line={{ item }}
    with_items:
      - 'proxy_password=hogehoge'
      - 'proxy_username=hogehoge.san'
      - 'proxy=proxy=http://example.com:8080/'

 以上Playbookを実行した結果については、以下のようになります。

proxy=proxy=http://example.com:8080/
proxy_username=hogehoge.san
proxy_password=hogehoge

 lineinfileはテキストを行単位で編集するものであり、基本的に1回の処理で1行の文字列を編集(今回の場合は挿入)します。
 挿入する場所を正規表現によって指定することが可能であり、今回は"^proxy=.*$"、つまり意図的には「コメントアウトされたproxy」の直下に挿入されることになっています。
 またwith_itemsを利用することで複数行の編集も行なうことが可能ですが、処理的には「特定の行の直下に文字列を挿入する」を繰り返していることになるため、文章が後から挿入した順となってしまうのがやや使いにくい点と言えます。
 この特徴を意識してPlaybookを記述すればlineinfileにて複数行を挿入することは可能ではありますが、いちいち逆順に記述するのは面倒かつ後から見た場合に分かりにくいかと思いますので、複数行挿入を行なう場合は基本的に後述するblockinfileモジュールを使用します。


テキストファイルに文章を挿入するPlaybook(blockinfileモジュールの場合)

 今度はblockinfileモジュールを使用し、lineinfileの例と同じく/etc/yum.confに対して既存プロキシー下に新たなプロキシー設定の挿入を行ないます。
 この場合のPlaybookの作成例は以下の通りになります。

- hosts: all

  tasks:
  - name: set yum proxy
    blockinfile:
      path: /etc/yum.conf
      insertafter: "^proxy=.*$"
      block: |
        proxy=http://example.com:8080/
        proxy_username=hogehoge.san
        proxy_password=hogehoge

 以上Playbookを実行した結果については、以下のようになります。

# BEGIN ANSIBLE MANAGED BLOCK
proxy=proxy=http://example.com:8080/
proxy_username=hogehoge.san
proxy_password=hogehoge
# END ANSIBLE MANAGED BLOCK

 blockinfileは主に複数行にわたるテキストブロックを挿入・更新・削除するためのモジュールです。
 ブロックでひとくくりとなったテキストをそのままテキストファイルの中に挿入できるため、lineinfileのように順序の入れ替わりを意識する必要はありません。
 ただしblockinfileで挿入したテキストはマーカーラインという目印に挟まれることになります。
 マーカーラインは上記実行結果の「# BEGIN ANSIBLE MANAGED BLOCK」および「# END ANSIBLE MANAGED BLOCK」の部分です。
 これについてはPlaybook内で内容を編集することはできますが、マーカーラインを記述しないようにしたり、削除することはできません。
 blockinfileで編集した場所が分かりやすく、またblockinfileでこのマーカーライン内のテキストを更新できるといったメリットがありますが、見栄えとしてはどうしても悪くなってしまうのが欠点となります。


さいごに:lineinfileモジュールとblockinfileモジュールの違いと共通の欠点

 以上がAnsibleによってクライアントのテキストファイルを編集するモジュール、lineinfileとblockinfileの解説となります。  両者の違いはまとめると、以下のようになります。

  • lineinfile

    • 1行ずつ追加や変更や削除する。
    • 複数行を挿入する場合、新しく挿入したものが上になる。
  • blockinfile

    • 複数行のテキストの塊を追加・更新・削除する。
    • 再度追加すると一度追加した内容を更新する。

 このような形で、基本的に
 「1行の文字列を追加する場合や、どうしてもマーカーラインを追加したくない場合はlineinfile」
 「複数行の文字列を追加する場合はblockinfile」
 という使い分けをすれば問題ないかと思います。

 ただし両者の注意点としてどちらもテキストファイル内に指定した正規表現に該当する記述が2か所以上あった場合、その中で一番上の行が文字列を挿入する基準の行となってしまうことがあります。
 これを意識せずに使用してしまうと、思わぬところに文字列が挿入されたり、意図しないところの文字列が変更されてしまうということになりますので、編集先のテキストファイルの全容を把握し、指定する正規表現内容を検討することが重要となります。

 Ansibleによって多数の設定ファイルを一度に変更できるこれらのモジュールは便利ですが、こういった危険性を含んでいるものであるということを理解した上で、トラブルなく利用していただければと思います。
 もし「大丈夫かな?」と思った際は、またこの記事を見返して特徴等を思い返していただければ幸いです。
 以上、お読みいただきありがとうございました。