state:absentとpath:/directoryの挙動
Ansible Version: 2.3
Ansibleのfileモジュールのstateでabsentを指定すると、pathがディレクトリの場合、そのディレクトリの下にファイルがあったとしても削除されてしまう。
If absent, directories will be recursively deleted
参照: https://docs.ansible.com/ansible/latest/modules/file_module.html
つまり、シェルコマンドでいうとディレクトリの中が空の場合に削除してくれるrmdir
ではなくrm -rf
を実行しているのと同じであり、安易に使用するとデータを失いかねない。
障害ケース
例えばMySQLやMongoDBなどのインストールとセットアップのために以下のようなtaskを作成する。
## 1. yum installする
- name: install
yum:
name: "{{ item }}"
state: installed
enablerepo: "mysql57-community"
with_items:
- mysql-community-server
- mysql-community-devel
## /var/lib/mysqlが自動で作成される
## 2. データ領域を外部ディスクに作成するため、/var/lib/mysqlのディレクトリを消す
- stat:
path: /var/lib/mysql
register: mysql_dir
- file:
path: /var/lib/mysql
state: absent
when:
- mysql_dir.stat.isdir is defined
- mysql_dir.stat.isdir
## 3. 外部ディスクへ/var/lib/mysqlからsymlinkをはる
- file:
src: /DISK01/mysql
dest: /var/lib/mysql
state: link
## 4. MySQLを起動する
- service:
name: mysqld
state: started
enabled: yes
## /var/lib/mysqlにデータが作成される
このplaybookであれば何度実行してもmysql_dir.stat.isdir
の条件により初回以外はsymlinkになっている/var/lib/mysqlは削除されない。しかし、運用していく中で、外部ディスクを外して/var/lib/mysqlに直接データを置くような作業を手動で実行してしまった場合など、/var/lib/mysqlがsymlinkからディレクトリに戻ってしまったときにAnsibleを再実行するとMySQLのデータ丸ごと削除してしまう。
手動で構成変更しているのが悪いと言えば悪いのだが、playbookにバグを作りこんでしまう可能性もあるだろうし、重要なデータがある箇所でrm -rf
になりかねないstate: absent
を使わない方がいいだろう。
ワークアラウンド
shellモジュールを使ってディレクトリの中が空であれば(念のために再帰的に)削除するようにする。再帰的に削除する方法は空のディレクトリを再帰的に消すを参考にfindの-empty -delete
を使う。特に再帰的に削除しなくてよければrmdir /var/lib/mysql
でも全く問題ない。
## 2. データ領域を外部ディスクに作成するため、/var/lib/mysqlのディレクトリを消す
- stat:
path: /var/lib/mysql
register: mysql_dir
- shell: |
find /var/lib/mysql -type d -empty -delete
when:
- mysql_dir.stat.isdir is defined
- mysql_dir.stat.isdir