ansibleでvalidate optionを使うとエラーになる現象の対策

tasksでhttpd.conf をcopyする際にvalidateにapachectl configtestを実行するよう設定すると、、、

- name: copy httpd.conf template
  action: template src=/template/apache/conf/httpd.conf.j2 dest=/etc/httpd/conf/httpd.conf backup=yes validate='/usr/sbin/apachectl configtest'
  notify:
  - restart apache
# ansible-playbook hoge.yaml
TASK: [copy httpd.conf template] ********************************************** 
failed: [hoge] => {"failed": true, "item": "", "parsed": false}
invalid output was: Traceback (most recent call last):
  File "/root/.ansible/tmp/ansible-1381199762.87-223339696345573/copy", line 1104, in ?  main()
  File "/root/.ansible/tmp/ansible-1381199762.87-223339696345573/copy", line 151, in main
  (rc,out,err) = module.run_command(validate % src)
  TypeError: not all arguments converted during string formatting

FATAL: all hosts have already failed -- aborting

python初心者すぎてウッと絶望しかけたけど何かエラーは見たことある!

>>> print "%s, %s" % ("hoge", "fuga")
hoge, fuga
>>> print "%s, %s" % ("hoge")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: not enough arguments for format string

型と変数の数が一致してないときのエラーですね。

たぶんこの例を見る感じだとvalidate に"%s" が必須でdestの引数のファイル名前が与えられるのだろう。

# Copy a new "sudoers file into place, after passing validation with visudo
- action: template src=/mine/sudoers dest=/etc/sudoers validate='visudo -cf %s'

ただ、apachectl configtest のようにファイル名を引数に取らないコマンドの場合はapachtctl configtest httpd.conf などと余計な引数をつけると怒られる。なのでコマンドに影響を与えない無意味な環境変数に%sを使って、強引に解決するバッドノウハウを編み出した結果が以下の内容。

- name: copy httpd.conf template
  action: template src=/template/apache/conf/httpd.conf.j2 dest=/etc/httpd/conf/httpd.conf backup=no validate='DUMMY=%s apachectl configtest'
  notify:
  - restart apache