■ はじめに
Ansible には、テキストファイルを行単位で編集する lineinfile
モジュール があります。httpd.conf
などの設定ファイルの設定項目を書き換えるといった用途に利用できます。
この記事では、 lineinfile
モジュールの公式ドキュメントに記載されている使用例をベースにして、使い方を説明します。
なお、公式ドキュメントの使用例は、Playbook 単位ではなくtask 単位で記載されています。この記事では Playbook 単位で例示します。
動作確認環境
- Ansible 2.3.0, 2.7.8
- CentOS 7.6 (Ansible 側、管理対象ホスト側とも)
目次
- ■ はじめに
- ■ 単純に行置換する
- ■ 行を削除する
- ■ マッチしなかった場合に挿入したい箇所を指定して挿入する
- ■ 正しく編集が行われるかを事前に検証する
- ■ 応用編: チェックモードであらかじめ編集前後の diff を確認する
- ■ まとめ
■ 単純に行置換する
Playbook
/etc/selinux/config
内の '^SELINUX='
にマッチする行を SELINUX=enforcing
に置換する Playbook です。
- hosts: linux gather_facts: no become: yes tasks: - lineinfile: path: /etc/selinux/config regexp: '^SELINUX=' line: 'SELINUX=enforcing'
path
オプション- 対象のファイル名のパス名を指定します。(必須)
regexp
オプション- 編集対象とする行を示す正規表現を指定します。
- マッチする行が複数ある場合、最後にマッチした行が対象になります。
- マッチしなかった場合は EOF が対象(デフォルトの
backrefs: no
の場合 )
line
オプション- 挿入/置換する行を指定します。
state
オプションがpresent
(デフォルト) の場合のみ有効です。
本タスクで指定していないその他のオプション例
owner
、group
オプション- 所有者情報を指定できます。
mode
オプション- パーミッションを指定でできます。(例
mode: 0644
)
- パーミッションを指定でできます。(例
create
オプションpath
で指定したファイルが存在しなかった場合にファイル作成するかどうか(デフォルトno
)
backup
オプション- 編集前のファイルをバックアップとして別途保存するかどうか(デフォルト
no
)
- 編集前のファイルをバックアップとして別途保存するかどうか(デフォルト
実行ログ
ここでは、SELINUX=disabled
の状態で Playbook を実行します。
$ cat /etc/selinux/config | grep "^SELINUX=" SELINUX=disabled $ ansible-playbook -i inventory lineinfile_simple.yml PLAY [linux] *************************************************************** TASK [lineinfile] ********************************************************** changed: [linux1] PLAY RECAP ***************************************************************** linux1 : ok=1 changed=1 unreachable=0 failed=0 $ cat /etc/selinux/config | grep "^SELINUX=" SELINUX=enforcing
無事に SELINUX=enforcing
に置換されました。
なお、この後もう一度同じ Playbook を実行した場合は、すでに SELINUX=enforcing
になっていることを検出して、とくに何もしません。そのため、対象ファイルの更新日時も変わりません。
■ 行を削除する
Playbook
/etc/sudoers
内の '^%wheel'
にマッチする行を削除する Playbook です。
- hosts: linux gather_facts: no become: yes tasks: - lineinfile: path: /etc/sudoers state: absent regexp: '^%wheel'
state
オプション- マッチした行を削除したい場合は
state: absent
を指定します。
- マッチした行を削除したい場合は
実行ログ
ここでは、'^%wheel'
にマッチする行がある状態で Playbook を実行します。
$ sudo cat /etc/sudoers | grep "^%wheel" %wheel ALL=(ALL) ALL $ ansible-playbook -i inventory lineinfile_absent.yml PLAY [linux] *************************************************************** TASK [lineinfile] ********************************************************** changed: [linux1] PLAY RECAP ***************************************************************** linux1 : ok=1 changed=1 unreachable=0 failed=0 $ sudo cat /etc/sudoers | grep "^%wheel" $ # 表示なし
無事に '^%wheel'
にマッチする行が削除されました。
■ マッチしなかった場合に挿入したい箇所を指定して挿入する
Playbook
./test.txt
内に 、'^Listen '
にマッチする行があれば line
の内容に置換し、マッチする行がなければ insertafter
で指定する '^#Listen '
にマッチする行の次の行に Listen 8080
を挿入する Playbook です。
設定ファイル内にコメントアウトされた設定があるときに、その次の行に有効な設定値を挿入したい場合などに利用できます。
- hosts: linux gather_facts: no become: yes tasks: - lineinfile: path: ./test.txt regexp: '^Listen ' insertafter: '^#Listen ' line: 'Listen 8080'
insertafter
オプション
本タスクで指定していないその他のオプション例
firstmatch
オプション(Ansible 2.5から利用可能)insertafter
やinsertbefore
オプションの正規表現で複数の行がマッチした場合、最初にマッチした行を基準とするかどうかを指定します。(デフォルトno
)
実行ログ
ここでは、#Listen 80
がある状態で Playbook を実行します。
$ cat ./test.txt abc abc #Listen 80 abc abc $ ansible-playbook -i inventory lineinfile_after.yml PLAY [linux] ******************************************************************* TASK [lineinfile] ************************************************************** changed: [linux1] PLAY RECAP ********************************************************************* linux1 : ok=1 changed=1 unreachable=0 failed=0 $ cat ./test.txt abc abc #Listen 80 Listen 8080 abc abc
無事に '^#Listen '
にマッチする次の行に Listen 8080
が挿入されました。
なお、もし ./test.txt
が
abc abc Listen 80 abc abc
のように regexp
オプションで指定した '^Listen '
にマッチする行がある場合は、単純に置換されて以下のようになります。
abc abc Listen 8080 abc abc
■ 正しく編集が行われるかを事前に検証する
Playbook
/etc/sudoers
の内容を編集して保存する前に、/usr/sbin/visudo -cf
コマンドでファイルのフォーマットを確認する Playbook です。
- hosts: linux gather_facts: no become: yes tasks: - lineinfile: path: /etc/sudoers state: present regexp: '^%ADMIN ALL=' line: '%ADMIN ALL=(ALL) NOPASSWD: ALL' validate: '/usr/sbin/visudo -cf %s'
validate
オプション- 編集後のファイルの内容が正しいか検証するためのコマンドを指定します。対象を
%s
で指定します。
- 編集後のファイルの内容が正しいか検証するためのコマンドを指定します。対象を
実行ログ
ここでは、SELINUX=disabled
の状態で Playbook を実行します。
$ sudo cat /etc/sudoers | grep '^%ADMIN ALL=' $ $ ansible-playbook -i inventory lineinfile_validate.yml PLAY [linux] **************************************************************** TASK [lineinfile] *********************************************************** changed: [linux1] PLAY RECAP ****************************************************************** linux1 : ok=1 changed=1 unreachable=0 failed=0 $ sudo cat /etc/sudoers | grep '^%ADMIN ALL=' %ADMIN ALL=(ALL) NOPASSWD: ALL
無事に /etc/sudoers
の内容が編集されました。
なお、もし line: '%ADMIN ALL=(ALL) XXXXXXXx: ALL'
のように無効なフォーマットを指定して Playbook を実行した場合は、以下のようなエラーメッセージが表示されて異常終了します。
TASK [lineinfile] ************************************************************************************* fatal: [linux1]: FAILED! => {"changed": false, "msg": "failed to validate: rc:1 error:>>> /tmp/tmpWQcMFk: syntax error near line 121 <<<\n"}
■ 応用編: チェックモードであらかじめ編集前後の diff を確認する
ansible-playbook
コマンドの --check
、--diff
オプションを一緒に利用すると、実際はファイルの内容を編集せずに、あらかじめ編集前後の diff を確認できます。
以下の Playbook で実行例を確認します。
- hosts: linux gather_facts: no become: yes tasks: - lineinfile: path: ./test.txt regexp: '^Listen ' insertafter: '^#Listen ' line: 'Listen 8080'
$ cat test.txt # 対象ファイルの事前確認 abc abc #Listen 80 abc abc $ ansible-playbook -i inventory lineinfile_after.yml --diff --check PLAY [linux] ********************************************************** TASK [lineinfile] ****************************************************** --- before: ./test.txt (content) +++ after: ./test.txt (content) @@ -1,5 +1,6 @@ abc abc #Listen 80 +Listen 8080 abc abc changed: [linux1] PLAY RECAP ********************************************************* linux1 : ok=1 changed=1 unreachable=0 failed=0 $ cat test.txt # ファイルの内容は変更されていない abc abc #Listen 80 abc abc
■ まとめ
公式ドキュメントの使用例をベースにして、lineinfile
モジュール の使い方を説明しました。
他に「こんなことできるかな?」と気になる事がありましたら、公式ドキュメントで詳細をご確認ください。
また、lineinfile モジュールは Files modules
に分類されています。Files modules
には、他にも、指定した正規表現にマッチするすべての文字列を置換する replace
や、行ではなくブロック単位で編集する blockinfile
などのモジュールがあります。詳細は Files modules
の一覧からご確認ください。