Ansibleで冪等性を保つためにはfailed_whenとかstatを使うと便利
構成管理ツールとしてAnsibleを使って開発環境を作っているんだけど(本番でも使えるようにとかはまだできてない)、特定のコマンドの実行結果によって次の処理をスキップするかどうかみたいなのを制御したい場面がある。
例えばcentos6.xでnginxの設定を行いたいとすると、以下のようになる。
- name: get nginx rpm get_url: url="http://nginx.org/packages/centos/6/noarch/RPMS/nginx-release-centos-6-0.el6.ngx.noarch.rpm" dest="/var/tmp/nginx-release-centos-6-0.el6.ngx.noarch.rpm" - name: add nginx rpm yum: name=/var/tmp/nginx-release-centos-6-0.el6.ngx.noarch.rpm state=present - name: install nginx yum: name=nginx state=present - name: register service service: name=nginx enabled=yes - name: add conf file copy: src=../files/extra.conf dest=/etc/nginx/conf.d - name: move default conf shell: mv /etc/nginx/conf.d/default.conf /etc/nginx/conf.d/default.conf.backup
確かにこれでもnginxのインストールと必要な設定は行えるが、このままでは冪等性が担保されない。Ansibleのコアモジュールの多くは冪等性をチェックしているが、shellモジュールなどの冪等性は担保されない。対象のサーバに対してこのスクリプトを実行した場合、2回目移行もdefault.confをmvしようとしてエラーになるだろう。
幸いAnsibleにはregisterという出力を変数に格納できる仕組みがあるので、それを利用するとよい。
- name: is nginx already installed shell: which nginx register: which_nginx # (中略) - name: move default conf shell: mv /etc/nginx/conf.d/default.conf /etc/nginx/conf.d/default.conf.backup
しかし、これではエラーとなってしまう。Ansibleは終了ステータスが0以外のものを原則エラーとして解釈するからだ。which nginxでnginxが存在しなかった場合、no nginx foundのようなものがエラー出力に出てしまうから、ハンドリングする必要がある。
結果、以下のように書くのがよい。
- name: is nginx already installed shell: which nginx register: which_nginx failed_when: which_nginx not in [0, 1] # (中略) - name: move default conf shell: mv /etc/nginx/conf.d/default.conf /etc/nginx/conf.d/default.conf.backup when: which_nginx.rc == 1
failed_whenは値に記述した結果のBooleanでタスクの成功可否を判定する。failed_whenを使うことで終了ステータスの正常・エラーに関わらずタスク自体は通過させ、以後はそこで宣言した変数のステータスや出力内容を見ながらタスクを実行するかスキップするか決めるようにするとよいと思う。
余談だが、特定ファイルの存在確認をするためには以下のようなやり方がある
- name: check default conf stat: path=/etc/nginx/conf.d/default.conf register: is_exists - name: move default conf shell: mv /etc/nginx/conf.d/default.conf /etc/nginx/conf.d/default.conf.backup when: is_exists.stat.md5 is defined