【Ansible】ansible-lintとyamllintでplaybookの品質を安定させたい

#### はじめに
<バージョン>
ansible 2.9.7

playbookを作ったら、動くことが大前提ですが人によって書き方が違うと見づらいですよね。
ansible-lintとyamllintというツールを実行することで、playbookの書き方が一定のルールに
沿っていなかったら指摘してくれます。（使用するにはインストールが必要）
以下のplaybookのどこに問題点があるのでしょうか？

```yaml:lint_test.yml
- name: lint TEST
  hosts: localhost
  gather_facts: no
  vars:
    boolean_true: true
    boolean_false: false
  tasks:
    - name: 'loop test'
      debug:
        msg: "{{ item.name }} : {{ item.file }}"
      with_list:
        - { name: "loop1", file: "file1" }
        - { name: "loop2", file: "file2" }
 
    # debug test   
    - name: 'debug'
      debug:
        msg: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"

    - name: 'check true'
      debug:
        msg: "result is true"
      when:
        - boolean_true == true

    - name: 'check false'
      debug:
        msg: "result is false"
      when:
        - boolean_false == false
```

### 動作確認
lintをする前にまずplaybookが動くことが大前提なので確認しましょう。
syntax-checkと動作確認をして問題ないことが確認出来ました。
動作するのであればこれで問題ないように感じますが、ansible-lintとyamllintを実行するとどうなるか確認しましょう。

```text
[ec2-user@ip-<ip-addr>]$ ansible-playbook lint_test.yml --syntax-check

playbook: lint_test.yml
[ec2-user@ip-<ip-addr>]$ ansible-playbook lint_test.yml

PLAY [lint TEST] **************************************************************************************************************

TASK [loop test] **************************************************************************************************************
ok: [localhost] => (item={u'name': u'loop1', u'file': u'file1'}) => {
    "msg": "loop1 : file1"
}
ok: [localhost] => (item={u'name': u'loop2', u'file': u'file2'}) => {
    "msg": "loop2 : file2"
}

TASK [debug] *****************************************************************************************************************
ok: [localhost] => {
    "msg": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
}

TASK [check true] ************************************************************************************************************
ok: [localhost] => {
    "msg": "result is true"
}

TASK [check false] ************************************************************************************************************
ok: [localhost] => {
    "msg": "result is false"
}

PLAY RECAP *******************************************************************************************************************
localhost                  : ok=4    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
```

### ansible-lintをかけてみた
実行すると、yml名の右に何行目に問題があるか教えてくれます。一つずつエラーメッセージを確認していきましょう。
（1）14行目：Trailing whitespace
　ここは1個目のタスクの下にある空行です。空行に見えますが実はスペースが入っています。
（2）24行目： Don't compare to literal True/False
　条件が真の場合、flag == trueという書き方ではなく以下の様に直す必要があります。
<修正前>
- boolean_true == true
<修正後>
- boolean_true
（3）30行目： Don't compare to literal True/False
条件が偽の場合、flag == falseという書き方ではなく以下の様に直す必要があります。
<修正前>
- boolean_false == false
<修正後>
- not boolean_false

```text:出力
[ec2-user@ip-<ip-addr>]$ ansible-lint lint_test.yml
[201] Trailing whitespace
lint_test.yml:14


[601] Don't compare to literal True/False
lint_test.yml:24
        - boolean_true == true

[601] Don't compare to literal True/False
lint_test.yml:30
        - boolean_false == false
```

### yamllintをかけてみた
yamllintだと何行目の何文字目に誤りがあるかを細かく教えてくれます。1:1ということは、1行目の1文字目に誤りがあるということです。
エラーの意味は、[yamllint documentation](https://yamllint.readthedocs.io/en/stable/rules.html)を見ればわかりますが、ここでも一つずつエラーメッセージを確認していきましょう。
（1）[ 1:1 ] warning  missing document start "---"  (document-start)
　yamlの書き出しはハイフン(-)を3つ書く必要があります。
（2）[3:17] truthy value should be one of false, true  (truthy)
　yes/no ではなく、true/falseで書きましょう。
（3）[12:12][12:41][13:12][13:41] too many spaces inside braces  (braces)
　余計なスペースがある時のメッセージです。辞書型では{ }の始まりと終わりの前後にスペースは不要です。
<修正前>
- { name: "loop1", file: "file1" }
<修正後>
- {name: "loop1", file: "file1"}
（4）[14:1] trailing spaces  (trailing-spaces)
　ansible-lintでも指摘された項目です。空行に見えますが実はスペースが入っています。
（5）[18:81] line too long (83 > 80 characters)  (line-length)
　「aaaa…」と長い行になっていますが、一行に81文字以上書いてはいけません。
（6）[30:33] no new line character at the end of file  (new-line-at-end-of-file)
　最終行は「 - boolean_false == false」ですが、この行の最後に改行を入れる必要があります。

```text:出力
[ec2-user@ip-<ip-addr>]$ yamllint lint_test.yml
lint_test.yml
lint_test.yml
  1:1       warning  missing document start "---"  (document-start)
  3:17      warning  truthy value should be one of [false, true]  (truthy)
  12:12     error    too many spaces inside braces  (braces)
  12:41     error    too many spaces inside braces  (braces)
  13:12     error    too many spaces inside braces  (braces)
  13:41     error    too many spaces inside braces  (braces)
  14:1      error    trailing spaces  (trailing-spaces)
  18:81     error    line too long (83 > 80 characters)  (line-length)
  30:33     error    no new line character at the end of file  (new-line-at-end-of-file)
```

### 修正後playbook
以下が修正後のplaybookです。

```yaml:lint_test_modify.yml
---
- name: lint TEST
  hosts: localhost
  gather_facts: false
  vars:
    boolean_true: true
    boolean_false: false
  tasks:
    - name: 'loop test'
      debug:
        msg: "{{ item.name }} : {{ item.file }}"
      with_list:
        - {name: "loop1", file: "file1"}
        - {name: "loop2", file: "file2"}

    # debug test
    - name: 'debug'
      debug:
        msg: "aaaaa"

    - name: 'check true'
      debug:
        msg: "result is true"
      when:
        - boolean_true

    - name: 'check false'
      debug:
        msg: "result is false"
      when:
        - not boolean_false

```

### まとめ
「ansible-lintとyamllintのどちらかだけを使えばいいのではないか？」と思うかもしれませんが、
2つのlintで指摘項目が異なるので併用する方がplaybookの品質が安定します。

### 参考資料
[yamllint documentation](https://yamllint.readthedocs.io/en/stable/rules.html)