koh’s blog

Sys Admin who loves automation

Ansibleでcommandを使わないためのモジュール

Playbookを書いているとたまに

  • 特定のパッケージがインストールされていたらなにかする
  • 特定のユーザが存在したらなにかする

みたいな処理をしたいときがあります。
実際にインストールしたりユーザ作成せずに現状の確認だけをしたいケースです。

そういったときに command, shellモジュールを使用することで実現できます。

  tasks:
    - name: check if httpd is installed
      shell: rpm -qa | grep httpd
      register: httpd_installed
      ignore_errors: True
      check_mode: False
      changed_when: False

    - name: print
      debug:
        msg: "httpd is installed"
      when: httpd_installed.rc == 0

ただし上記のやり方は色々めんどくさいこともあります。

  • changed_whenignore_errors等のパラメータの設定が必要
  • ansible実行時やansible-lintでwarningが出力されがち

そこでcommandモジュールの代わりになりうるモジュールをいくつか紹介します。

検証環境

ansible: v2.9.9
targetOS: CentOS7.7 and Ubuntu 18.04

stat

stat – Retrieve file or file system status — Ansible Documentation

statモジュールはファイルの状態を確認できます。
ファイルの有無のみでなく種類(ファイル/ディレクトリ/リンクなど)やowner等の情報も取得できます。

  tasks:
    - name: check if /etc/hosts exists
      stat:
        path: /etc/hosts
      register: etchosts

    - name: print
      debug:
        msg: "/etc/hosts exists"
      when: etchosts.stat.exists

    - name: print
      debug:
        msg: "/etc/hosts is directory"
      when: etchosts.stat.isdir # this should be False

package_facts

package_facts – package information as facts — Ansible Documentation

package_factsはパッケージがインストールされているかの確認ができます。
取得したパッケージ一覧はansible_facts.packages に格納されます。

  tasks:
    - name: check packages
      package_facts:
        manager: auto

    - name: print
      debug:
        msg: "Version of NetworkManager is {{ ansible_facts.packages['NetworkManager'][0]['version'] }}"
      when: "'NetworkManager' in ansible_facts.packages"

getent

getent – A wrapper to the unix getent utility — Ansible Documentation

getentモジュールはgetentコマンドのラッパーでpasswdやgroup等のデータを取得できます。
取得した情報はgetent_***に格納されます(***は指定したdatabase名)
※取得できる情報は対象のOSによって異なります。

  tasks:
    - name: check users
      getent:
        database: passwd

    - name: print
      debug:
        msg: "app1 user exists"
      when: "'app1' in getent_passwd"

service_facts

service_facts – Return service state information as fact data — Ansible Documentation

service_factsモジュールは各serviceの情報を取得します。
取得した情報はansible_facts.servicesに格納されます。

  tasks:
    - name: check services
      service_facts:

    - name: print
      debug:
        msg: "firewalld is {{ ansible_facts.services['firewalld.service']['status'] }}"
      when: "'firewalld.service' in ansible_facts.services"

まとめ

たまたまtwitterpackage_factsを知って他にも似たようなモジュールが無いか調べたら色々ありました。
モジュールをなるべく使うことでOSの差分を吸収してくれたりコード量も減るのでよりPlaybookらしいPlaybookになる気がします。