Ansibleのshellモジュールとインデント
確認version
- Ansible 2.7.0
- Python 3.6.5
Ansibleのshellモジュールに記載した実行コマンドは、スペースとタブが取り除かれて実行される。そのためPythonのようなインデントが意味を持つプログラムを実行することができない。
- name: exec python program
shell: |
python -c '
import sys
for i in range(1, 20):
if i % 3 == 0 and i % 5 == 0:
print(i)
sys.exit()
'
register: result
- name: print result
debug: msg="{{ result }}"
このroleを実行すると以下のようなエラーが出力されてしまう。"cmd"
の部分で実行されるスクリプトを確認するとインデントが消えていることがわかる。また"stderr_lines"
にはIndentationError: expected an indented block
と出力されている。
TASK [test : exec python program] ********************************************************************************************************************************************
fatal: [server01]: FAILED! => {"changed": true, "cmd": "python -c '\nimport sys\nfor i in range(1, 20):\nif i % 3 == 0 and i % 5 == 0:\nprint(i)\nsys.exit()\n'", "delta": "0:00:00.040754", "end": "2018-10-26 20:39:53.171771", "failed": true, "rc": 1, "start": "2018-10-26 20:39:53.131017", "stderr": " File \"<string>\", line 4\n if i % 3 == 0 and i % 5 == 0:\n ^\nIndentationError: expected an indented block", "stderr_lines": [" File \"<string>\", line 4", " if i % 3 == 0 and i % 5 == 0:", " ^", "IndentationError: expected an indented block"], "stdout": "", "stdout_lines": []}
インデントを残したままshellモジュールに渡す方法
インデントを残したままshellモジュールに渡すには、ロール内でset_fact
を使って変数にプログラムをセットし、その変数をshellモジュールに渡す。
args.executable
にpythonを切り出せるし、さらにpython -c '...'
というようにシングルクォーテーションでプログラム本体をくくる必要がないので、プログラム内でシングルクォーテーションをエスケープを気にせず使用することができる。
- name: create python program
set_fact:
script_content: |
import sys
for i in range(1, 20):
if i % 3 == 0 and i % 5 == 0:
print(i)
sys.exit()
- name: exec python program
shell: "{{ script_content }}"
args:
executable: python
register: result
- name: print result
debug: msg="{{ result.stdout }}"
これを実行すると以下のように正しく実行できた。
TASK [test : print result] ***************************************************************************************************************************************************
ok: [server01] => {
"msg": "15"
}
参考
Shell module does not respect indentation with multiline command