Ansibleのcheck_modeオプションでcheckモードを制御する

2016.11.01

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

渡辺です。

Ansible2.2からcheck_modeオプションが追加されます。 ひじょーに欲しかった機能なので紹介します。

Ansibleのcheckモード

ansible-playbookコマンド実行時、--checkオプションを追加した場合、AnsibleはいわゆるDryRunになります。 この時、モジュールでは、サーバの状態をチェックして変更の必要性を確認しますが、変更を行うことはありません。 checkモードは、Playbookを変更する前や、変更を適用する前に利用されます。

commandモジュールはcheckモードでは実行されない

commandモジュールはcheckモードでは実行をスキップします。 これは、commandモジュールがサーバの状態を変更するとみなしているからです。 実際にはcommandモジュールで実行するコマンド次第なのですが、Ansibleの設計ポリシーとしては変更する可能性があるものは変更する、とみなしているのです。

- command: test -f /path_to/file
  register: _test_file

したがって、ファイルの存在チェックなどサーバの状態をチェックするコマンドであっても必ずchangedとなり、checkモードでは必ず実行されないということになります。 とはいえ、ファイルの存在チェックであれば、statモジュールを利用すれば解決します。

- stat: 
    path: /path_to/file
  register: _stat_file

commandモジュールの結果は他のモジュールの実行判定に利用する

commandモジュールがなんらかのチェックを行うコマンドを実行しており、かつそれが標準モジュールで代替できない場合、checkモードでは後続のモジュール実行時にエラーが発生することになります。 これは、commandモジュールが実行されないため、registerで変数が登録されなからです。 あちらを立てればこちらが立たず・・・困ったところです。

- command: test -f /path_to/file
  register: _test_file
- some_module: hogehohe
  when: _test_file.rc = 1  # _test_fileがないとエラー

checkモードで実行を強制するcheck_mode

ここで登場するのがcheck_modeです。 check_modeにはyesまたはnoを指定します。

check_modeyesにした場合、--checkオプションをつけなくてもモジュールは常にcheckモードで実行されます。 check_modenoにした場合、--checkオプションをつけた場合でも、モジュールは常に通常モードで実行されます。

つまり、check_mode: noとすれば、commandモジュールを強制実行させることができるわけです。 結果、後続のモジュール実行犯定時に変数がなくてエラーとなることを回避できることになります。

- command: test -f /path_to/file
  check_mode: no
  changed_when: false
  register: _test_file
- some_module: hogehohe
  when: _test_file.rc = 1

なお、check_mode: yesの方は、グループ変数やコンディションを入れることで特定の条件下でcheckモードかどうかを制御する・・・ような使い方ですかね。 今の所、使いどころはいまいち解りません。

まとめ

check_mode: noはAWS関連のタスクを実行する時、非常に重宝します。 例えば、ec2_vpc_subnet_factsモジュールはサブネットの情報を収集しますが、checkモードでは実行されません。 AWS CLIを実行する場合にはcommandモジュールを利用するので同様です。 ですが、check_modeを利用すれば、checkモードでも実行出来るので、冪等性を保ったPlaybookを書きやすくなります。

    - name: Facts subnet
      ec2_vpc_subnet_facts:
        profile: "{{ profile }}"
        region: "{{ region }}"
      check_mode: no
      register: _subnet_facts