Ansibleのプレイブックを実行していると、プレイブックを適用することなくおおむね動作するか確認したくなります。 Ansibleのcheckモードがそれですが、Ansibleのモジュールによってはcheckモードに対応していないものがあります。 今回はそのメモ。
checkモードとは
Ansibleのcheckモードは、プレイブックを実行することなく検証できます。
利用方法は、ansible-playbook
コマンドに--check
オプションをつけるだけです。
$ ansible-playbook foo.yml --check
checkモードの理想と現実
checkモードは理想と現実にギャップがあるため利用するには注意しなくてはいけません。
- 理想: モジュールによる副作用を対象マシンに及ぼすことなく動作確認できる
- 現実: モジュールによってはcheckモードでも容赦なく実行される
またcheckモードでスキップされるタスクにて変数を登録している場合、後続でその変数を参照しているものは明示的にスキップする必要があります。 あるいはcheckモードでも必ず実行させることで制御するのもいいでしょう。
この3点に気をつければ割と便利に使えます。
モジュールがcheckモードに対応しているかしていないか判別する
Ansibleには多くのモジュールがありますが、そのすべてがcheckモードに対応しているわけではありません。 幸いモジュールがcheckモードに対応しているかどうかは、モジュールのウェブページに記載されています。
確認方法
Attributes表のcheck_mode
を確認します。1
例
ansible.builtin.fileは、Attributesにcheck_mode: full
の表記があるのでcheckモードに対応しています。
ansible.builtin.get_urlは、Attributesにcheck_mode: partial
の表記があるのでcheckモードに一部対応しています。
checkモードでスキップされる変数定義を使う後続ステップはスキップする
変数tem_dir
を定義するステップを用意したとしましょう。次のステップでtemp_dir
を参照している場合、checkモードで実行するとtemp_dir
は定義されていないためエラーになります。
- name: "go - Create temporary directory for download" ansible.builtin.tempfile: state: directory prefix: golang_install register: temp_dir - name: "go - Download Go tarball" ansible.builtin.get_url: url: "https://go.dev/dl/go{{ go.version }}.linux-amd64.tar.gz" dest: "{{ temp_dir.path }}/go.tar.gz" mode: "0644" register: download_result until: download_result is not failed retries: 3 delay: 2
TASK [tools : go - Download Go tarball] **************************************** fatal: [localhost]: FAILED! => {"msg": "The task includes an option with an undefined variable.. 'dict object' has no attribute 'path'\n\nThe error appears to be in '/home/runner/work/local-provisioner/local-provisioner/envs/include_role/ubuntu/install_go.yaml': line 15, column 3, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n\n- name: \"go - Download Go tarball\"\n ^ here\n"}
モジュールがcheckモードに対応していてもしていなくても変数を参照してエラーになります。
checkモードの時だけ実行しないようにするには、when: ansible_check_mode
使ってcheckモード時だけスキップします。
- name: "go - Download Go tarball" ansible.builtin.get_url: url: "https://go.dev/dl/go{{ go.version }}.linux-amd64.tar.gz" dest: "{{ temp_dir.path }}/go.tar.gz" mode: "0644" register: download_result until: download_result is not failed retries: 3 delay: 2 when: not ansible_check_mode # <- checkモードのときはスキップする
checkモードでタスクを強制的に実行する
私はansible.builtin.shell
やansible.builtin.command
で取得した結果から変数を作ることがあります。
副作用のない処理なので、checkモードでも実行したいのですがこれらはcheckモードではスキップされてしまいます。
- name: "Get os" ansible.builtin.shell: set -o pipefail && uname | tr '[:upper:]' '[:lower:]' args: executable: /bin/bash register: os_value changed_when: false
checkモードでも強制実行されるようにしたいときは、check_mode: false
を指定します。
- name: "Get os" ansible.builtin.shell: set -o pipefail && uname | tr '[:upper:]' '[:lower:]' args: executable: /bin/bash register: os_value changed_when: false check_mode: false
まとめ
Ansibleはいろいろなことができるだけに、checkモードをモジュールがいい感じにやってくれるのではなくユーザーがいい感じにいじる必要があります。 柔軟だからこそのジレンマを感じるところですが、checkモードをうまく使うことでAnsibleのプレイブックをより便利に使えるようになります。
参考
- 同じ表からdiffモードに対応しているかも確認できます。↩