LoginSignup
4
4

More than 3 years have passed since last update.

Ansibleのdebugモジュールを使ってログを出力する方法がshellモジュールを使ったかどうかで違ったのでまとめる

Last updated at Posted at 2019-09-07

Ansibleのdebugモジュールを使う際、shellモジュールを使っているかどうかで出力方法がやや異なります。

では、どのように違うのか?

その違いを忘れないように下記のような表を作りました。

モジュール別のdebug方法一覧表

標準出力のdebug エラー出力のdebug
shellモジュール "{{ $RESULT.stdout }}" "{{ $RESULT.stderr }}"
shellモジュール以外(fileなど) "{{ $RESULT }}" "{{ $RESULT }}"

上の表を作るにあたり、えいやっで作ったyamlはこちらです。

検証するために作ったsample.yml

---
- hosts: 
    - dev
  become: yes
  vars:
    ##成功、stdoutのみ"dir_test "と出力あり。
    #target: /usr/etc/
   ##成功、stdout/stderrともに出力なし。
    #target: /usr/etc/dir_test 
    ##失敗、stderのみ"No such file or directory"と出力あり。
    target: /usr/ett  

  tasks:
    #- name: Check if target dir exists or not
    - stat:
        path: "{{ target }}"
      register: result_stat
      failed_when: false 
      ##moduleの実行結果を確認する場合は"{{ $REGISTER }}"
    - name: debug 
      debug:
        msg: "{{ result_stat }}"
    - shell: ls "{{ target }}"
      register: result_shell
      failed_when: false
      changed_when: false
    #shellモジュールで直接コマンドを叩いた実行結果を確認する場合は"{{ $REGISTER.stdout or $REGISTER.stderr }}"
    - name: debug result_shell.stdout
      debug:
        msg: "{{ result_shell.stdout }}"
    - name: debug result_shell.stderr
      debug:
        msg: "{{ result_shell.stderr }}"

上の表を作るにあたり、ドキュメントを読み漁っていくなかでshellモジュールの箇所とそのソースコードが参考になったので、
併せて紹介させてください。

debug方法を理解するためにshellモジュールのドキュメントとソースコードを少し読んで分かったこと

  • 内部的にsubprocessモジュールを使い、 run_commandメソッドとしてコマンドを叩いていた
  • 返却値はrc(リターンコード), stdout(標準出力), stderr(エラー出力)の3つ

つまり、debugモジュールでログを吐き出す方法がshellモジュールを使っているかどうかで違うというのは、subprocess.Popen()を使っているかどうかと読み替えてもいいかもしれません。

run_command(args, check_rc=False, close_fds=True, executable=None, data=None, binary_data=False, path_prefix=None, cwd=None, use_unsafe_shell=False, prompt_regex=None, environ_update=None, umask=None, encoding='utf-8', errors='surrogate_or_strict', expand_user_and_vars=True, pass_fds=None, before_communicate_callback=None)
Execute a command, returns rc, stdout, and stderr.

Parameters: args – is the command to run * If args is a list, the command will be run with shell=False. * If args is a string and use_unsafe_shell=False it will split args to a list and run with shell=False * If args is a string and use_unsafe_shell=True it runs with shell=True.
Kw check_rc: Whether to call fail_json in case of non zero RC. Default False
Kw close_fds: See documentation for subprocess.Popen(). Default True
Kw executable: See documentation for subprocess.Popen(). Default None

出所:Ansible Reference: Module Utilities

cf. subprocessモジュールでコマンドを叩いているところ
ansible/basic.py at devel · ansible/ansible

subprocessモジュールの返却値はstdin(標準入力), stdout, stderrの3つですが、run_commandメソッドではstdinではなく、rcが返却されています。
ついでにrc, リターンコードについてかるーく調べたので、備忘録も兼ねて本記事に続けて書いていきます。

Ansibleにおけるリターンコード

Ansibleにおけるリターンコード と書いたのですが、そもそもリターンコードについて造詣が深いわけではないので、下記のシェルスクリプトに関する記事からリターンコードの説明箇所を引用します。

正常終了時は exit 0 で、異常終了時には exit 1 で終了するようにするのが慣例

出所:終了ステータス | UNIX & Linux コマンド・シェルスクリプト リファレンス

そんなリターンコードですが、Ansibleにおけるリターンコードは一般的なそれとはやや異なるようです。
公式docsにリターンコード(rc)について興味深い記述が合ったので共有します。

Ansible normally has defaults that make sure to check the return codes of commands and modules and it fails fast – forcing an error to be dealt with unless you decide otherwise.

Sometimes a command that returns different than 0 isn’t an error. Sometimes a command might not always need to report that it ‘changed’ the remote system. This section describes how to change the default behavior of Ansible for certain tasks so output and error handling behavior is as desired.

@gkzvoice 超意訳
(Ansibleの)利用者が通常コマンド及びモジュールのリターンコードを確認するようにし、また特に断らない限り、強制的にエラーを処理するために、早くfailedと出力するようにしている。

0以外のリターンコードが返却されたコマンドはエラーと判定しないケースがある。リモート機器(Ansibleにとってのターゲット機器)が'changed'と通知する必要が必ずしもない。本セクションでは、Ansibleの通常のふるまい(一般的なリターンコードと同様0は正常終了、1は異常終了と判定するロジック)をどのように変更して、Ansibleに求められているタスクの実行結果の出力とエラー判定方法を(Ansibleの利用者が)おこなっていけばよいか、(サンプルコードも交えて)取り上げていく。

キッチリ正常判定を行う場合と条件が複数行にまたがる場合にスマートに書く場合のサンプルコードを引用して本記事を終えたいと思います。

キッチリ正常判定を行う場合

failed_when: result.rc == 0 or "No such" not in result.stdout

条件が複数行にまたがる場合にスマートに書く場合


- name: example of many failed_when conditions with OR
  shell: "./myBinary"
  register: ret
  failed_when: >                                        #":"の後に">"を書けば改行できるようですね。
    ("No such file or directory" in ret.stdout) or
    (ret.stderr != '') or
    (ret.rc == 10)

出所: Error Handling In Playbooks — Ansible Documentation

P.S. Twitterもやってるのでフォローしていただけると泣いて喜びます!
@gkzvoice

4
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
4