Ansible で日本語ロケールなサーバでも su したい

## su に失敗するケース

sudo の設定が無くても su で管理を始められるのが Ansible の利点の 1つだと思っている。
が、ログイン先のサーバによっては su できないものが見つかる。

```console:一般ユーザはOK
$ ansible -vvv -k -a id test01
SSH password:
<test01> ESTABLISH CONNECTION FOR USER: hoge on PORT 22 TO test01
<test01> REMOTE_MODULE command id
<test01> EXEC /bin/sh -c 'mkdir -p $HOME/.ansible/tmp/ansible-tmp-1413805795.69-176729273645081 && chmod a+rx $HOME/.ansible/tmp/ansible-tmp-1413805795.69-176729273645081 && echo $HOME/.ansible/tmp/ansible-tmp-1413805795.69-176729273645081'
<test01> PUT /tmp/tmphT3M68 TO /home/hoge/.ansible/tmp/ansible-tmp-1413805795.69-176729273645081/command
<test01> EXEC /bin/sh -c 'LANG=C LC_CTYPE=C /usr/bin/python /home/hoge/.ansible/tmp/ansible-tmp-1413805795.69-176729273645081/command; rm -rf /home/hoge/.ansible/tmp/ansible-tmp-1413805795.69-176729273645081/ >/dev/null 2>&1'
test01 | success | rc=0 >>
uid=500(hoge) gid=500(hoge) groups=500(hoge)
}
```

```console:rootユーザにsuするとハングアップ
$ ansible -vvv -k --ask-su-pass -S -a id test01
SSH password:
su password:
<test01> ESTABLISH CONNECTION FOR USER: hoge on PORT 22 TO test01
<test01> REMOTE_MODULE command id
<test01> EXEC /bin/sh -c 'mkdir -p $HOME/.ansible/tmp/ansible-tmp-1413805925.95-157880462545113 && chmod a+rx $HOME/.ansible/tmp/ansible-tmp-1413805925.95-157880462545113 && echo $HOME/.ansible/tmp/ansible-tmp-1413805925.95-157880462545113'
<test01> PUT /tmp/tmpjkkti2 TO /home/hoge/.ansible/tmp/ansible-tmp-1413805925.95-157880462545113/command
<test01> EXEC /bin/sh -c 'su root -c "/bin/sh -c '"'"'echo SUDO-SUCCESS-xmanncgpffykbigatwdldkkdgmmbhtce; LANG=C LC_CTYPE=C /usr/bin/python /home/hoge/.ansible/tmp/ansible-tmp-1413805925.95-157880462545113/command; rm -rf /home/hoge/.ansible/tmp/ansible-tmp-1413805925.95-157880462545113/ >/dev/null 2>&1'"'"'"'
```

## 解決策

UTF-8 に関しては 1.8 で直るようだ。
https://github.com/ansible/ansible/issues/8681
とりあえず開発版を突っ込むと解決する。

```console:RPMパッケージにしてインストール
$ git clone git://github.com/ansible/ansible.git
$ cd ./ansible
$ git submodule update --init --recursive
$ make rpm
$ su
# rpm -Uvh rpm-build/ansible-*.noarch.rpm
```

最新でもまたハマるやつがいるなーと思って調べたら今度は EUC-JP だったので、以下のようにして暫定解決。
いつかまた別の文字コードで同じようなことをすることになるかもしれない。

```diff:/usr/lib/python2.6/site-packages/ansible/utils/su_prompts.py
--- su_prompts.py.org   2014-10-20 20:15:09.000000000 +0900
+++ su_prompts.py       2014-10-20 20:59:43.249570364 +0900
@@ -23,6 +23,7 @@
     'Password',
     '??',
     'パスワード',
+    '\xa5\xd1\xa5\xb9\xa5\xef\xa1\xbc\xa5\xc9',
     'Adgangskode',
     'Contrasena',
     'Contrasenya',
```

```console:成功するパターン
$ ansible -vvv -k --ask-su-pass -S -a id test01
SSH password:
su password:
<test01> ESTABLISH CONNECTION FOR USER: hoge on PORT 22 TO test01
<test01> REMOTE_MODULE command id
<test01> EXEC /bin/sh -c 'mkdir -p $HOME/.ansible/tmp/ansible-tmp-1413806497.99-216453360801100 && chmod a+rx $HOME/.ansible/tmp/ansible-tmp-1413806497.99-216453360801100 && echo $HOME/.ansible/tmp/ansible-tmp-1413806497.99-216453360801100'
<test01> PUT /tmp/tmpjHv_x2 TO /home/hoge/.ansible/tmp/ansible-tmp-1413806497.99-216453360801100/command
<test01> EXEC /bin/sh -c 'su root -c "/bin/sh -c '"'"'echo SUDO-SUCCESS-xtytjbmmmvotdxchaexagwjhciuxdiaq; LANG=C LC_CTYPE=C /usr/bin/python /home/hoge/.ansible/tmp/ansible-tmp-1413806497.99-216453360801100/command; rm -rf /home/hoge/.ansible/tmp/ansible-tmp-1413806497.99-216453360801100/ >/dev/null 2>&1'"'"'"'
test01 | success | rc=0 >>
uid=0(root) gid=0(root) groups=0(root)
```

## ロケール以外のハマりポイント

ロケールに関係なく、su するユーザのホームディレクトリが存在しない場合は余計な文字列が出ているためにハマった。

```none:pdb
(Pdb) s
> /usr/lib/python2.6/site-packages/ansible/runner/connection_plugins/paramiko_ssh.py(243)exec_command()
-> (self.runner.su_pass and utils.su_prompts.check_su_prompt(sudo_output)):
(Pdb) list
238
239                         while True:
240
241                             if success_key in sudo_output or \
242                                 (self.runner.sudo_pass and sudo_output.endswith(prompt)) or \
243  ->                             (self.runner.su_pass and utils.su_prompts.check_su_prompt(sudo_output)):
244                                 break
245                             chunk = chan.recv(bufsize)
246
247                             if not chunk:
248                                 if 'unknown user' in sudo_output:
(Pdb) print repr(sudo_output)
'Could not chdir to home directory /home/hoge: No such file or directory\r\nPassword: '
```

これも正規表現を追加するなどして check_su_prompt の結果が True になるようにすれば回避できるが、微妙なのでおとなしくホームディレクトリを作成した。