Ansibleのlineinfileモジュールでタブ文字（"\t"）を挿入する際

lineinfileのクォート処理で、バグらしきものを見つけたので、メモ。
~~あとで GitHub に issue 登録しておこうかしら。~~ 登録した（[#174](https://github.com/ansible/ansible-modules-core/issues/174)）。


2014/10/15追記
どうも " '...' " によるクォート処理は、他の箇所でも怪しい。
" '...' " で変な動作になったら、' "..." '（ダブル／シングルを逆にする）を試すと、うまく動くことがあるみたい。


# 環境

**Ansible 1.7.2で発生。1.7.1 では発生しないようだ。**

今回は、"pip install ansible"して、1.7.2 を使ったら発生。びっくりした。
"yum install ansible"で 1.7.1 に戻したら治まった。

OSはCentOS7。


# 問題

ある条件が揃うと、lineinfileの挿入行で "\t" を展開できない。

例えば、こんなテキストファイルがあったとして（インデントは"\t"）

```text
# a sample text

        Insert after this line: single-quoted-nomix '...'
        the next line

        Insert after this line: double-quoted-nomix "..."
        the next line

        Insert after this line: single-quoted-mix '"..."'
        the next line

        Insert after this line: double-quoted-mix "'...'"
        the next line

        Insert after this line: single-quoted-jinja2-mix '{{xx}} "..."'
        the next line

        Insert after this line: double-quoted-jinja2-mix "{{xx}} '...'"
        the next line
```

以下のAnsible playbookは期待通りに動作しない。**ケース４がダメ**。"\t"が効かない。

```yaml
--- # file: lineinfile.yml

- hosts: all

  gather_facts: False

  vars:
    original_file: ./test.txt.org
    target_file: ./test.txt
    fresh_start: yes

  tasks:
    - name: copy the data file
      copy: src={{ original_file }} dest={{ target_file }}
        force={{ fresh_start }}

    - name: case1 insert the line '...'
      lineinfile: dest={{ target_file }} state=present
        insertafter='\t.*single-quoted-nomix'
        line='\ta line with tab 1'
        regexp='a line with tab 1'

    - name: case2 insert the line "..."
      lineinfile: dest={{ target_file }} state=present
        insertafter="\t.*double-quoted-nomix"
        line="\ta line with tab 2"
        regexp="a line with tab 2"

    - name: case3 insert the line with '"..."'
      lineinfile: dest={{ target_file }} state=present
        insertafter='\t.*single-quoted-mix'
        line='\ta line with "tab" 3'
        regexp='a line with "tab" 3'

    - name: case4 insert the line "'...'"
      lineinfile: dest={{ target_file }} state=present
        insertafter="\t.*double-quoted-mix"
        line="\ta line with 'tab' 4"
        regexp="a line with 'tab' 4"

    - name: case5 insert the line with '"..."' with jinja2
      lineinfile: dest={{ target_file }} state=present
        insertafter='\t.*single-quoted-jinja2-mix'
        line='{{ "\t" }}a line with "tab" 5'
        regexp='a line with "tab" 5'

    - name: case6 insert the line "'...'" with jinja2
      lineinfile: dest={{ target_file }} state=present
        insertafter="\t.*double-quoted-jinja2-mix"
        line="{{ '\t' }}a line with 'tab' 6"
        regexp="a line with 'tab' 6"
```

## 結果

case4だけ、"\t" が文字列として挿入されてしまった。

```text
# a sample text

        Insert after this line: single-quoted-nomix '...'
        a line with tab 1
        the next line

        Insert after this line: double-quoted-nomix "..."
        a line with tab 2
        the next line

        Insert after this line: single-quoted-mix '"..."'
        a line with "tab" 3
        the next line

        Insert after this line: double-quoted-mix "'...'"
\ta line with 'tab' 4
        the next line

        Insert after this line: single-quoted-jinja2-mix '{{xx}} "..."'
        a line with "tab" 5
        the next line

        Insert after this line: double-quoted-jinja2-mix "{{xx}} '...'"
        a line with 'tab' 6
        the next line
```

# 回避方法

以下のようにすれば問題ない様子。

 1. Ansible 1.7.2は使わない
 2. クォートを混ぜない（解にならないかも）
 3. 外側のクォートをシングルクォートにして、そのなかで "\t" を使う
 4. Jinja2 を駆使する

こんなところで、なんでバグったんだろうな～。