てくなべ (tekunabe)

ansible / network automation / 学習メモ

[Ansible] 「つまずき Ansible 【Part20】VSCodeでいい感じにansible-lintしたい」ふりかえり

はじめに

2020/10/24 に、YouTube Live で「つまずき Ansible 【Part20】VSCodeでいい感じにansible-lintしたい」という配信をしました。

実際に作業しながら(ときには)エラーと戦って進めるシリーズです。

tekunabe.connpass.com

今回は、今回は、Playook の書きっぷりをチェックするツールである ansible-lint を Visual Studio Code からいい感じに呼び出す方法をました。

最終イメージ(ansible-lintとyamllint同時実行)

やったことをふりかえります。

  • 環境
    • ansible 2.9.14
    • ansible-lint 4.3.5

2023/08/02 追記

現在では VS CodeAnsible 拡張 の標準で類似のことができるため、本記事のような設定は不要です。

動画

www.youtube.com


■ やったこと

ansible-lint のインストール

ansible-lint は、Playbook の書き方がルールに沿っているかチェックするツールです。

https://ansible-lint.readthedocs.io/en/latest/index.html

デフォルトのルールとして、たとえば、行の末尾に余計なスペースがないか、タスクに name がついているかなどがあります。 デフォルトのルールは以下のページに記載されています。

index - Ansible Lint Documentation

インストールは pip でできます。

pip install ansible-lint

ansible-lint をコマンドで手動実行

まずは、以下のような Playbook を対象にします。(おそらく配信時と微妙にことなります)

- hosts: all
  gather_facts: no
  
  vars:
    msg: greeting

  tasks:
    - debug:
        msg: "{{msg}}"

    - name: Create a directory if it does not exist
      file:
        path: /etc/some_directory
        state: directory
        mode: 755

    - name: Send summary mail
      local_action:
        module: debug
        msg: hello

ansible-lint ファイル名 でチェックします。

(a2914) [root@centos7 stumble2]# ansible-lint test01.yml 
[201] Trailing whitespace
test01.yml:3
  

[206] Variables should have spaces before and after: {{ var_name }}
test01.yml:9
        msg: "{{msg}}"

[202] Octal file permissions must contain leading zero or be a string
test01.yml:11
Task/Handler: Create a directory if it does not exist

[504] Do not use 'local_action', use 'delegate_to: localhost'
test01.yml:18
      local_action:

...(略)...

いくつかのメッセージが表示されました。

VS Code のタスクに登録

コマンドで実行するのは少々面倒に思い、VS Code の「タスク」に登録することにします。

さらに、lint結果を problem matcher で解析して、VS Code の問題として認識させるようにします。

問題として認識することで、エディター画面で問題箇所を示してくれたり、「問題」を一覧表示してくれたりします。

.vscode/tasks.json に、以下のように定義します。

  • .vscode/tasks.json
{
  // See https://go.microsoft.com/fwlink/?LinkId=733558
  // for the documentation about the tasks.json format
  "version": "2.0.0",
  "tasks": [
    {
      "label": "ansible-lint current file",
      "type": "shell",
      "command": "/root/envs/a2914/bin/ansible-lint",  // 環境に応じて変える
      "args": [
        "${file}",
        "-p"
      ],
      "detail": "現在開いているファイルを ansible-lint する",
      "presentation": {
        "reveal": "never",
      },
      "problemMatcher": {
        "owner": "ansible-lint",
        "fileLocation": "autoDetect",
        "pattern":[
            {
                // sample
                // 01_show.yml:10: [E201] Trailing whitespace
                "regexp": "^(.+):(\\d+): (.+)$",
                "file": 1,
                "line": 2,
                "message": 3,
            }
          ],
      },
    }
  ]
}

これで、タスク ansible-lint current file を実行すると、今開いているファイルにたいして ansible-lint ファイル名 -p を実行し、問題を表示してくれます。

-p を付けたのは、problem matcher の正規表現で拾いやすくするためです。

タスクの定義方法の詳細は、VS Code の公式ドキュメントを参照してください。

エディタで対象の Playbook を開いている状態で、コマンドパレット(mac: Command + Shift + P / win: Ctrl + Shift + P )から、「タスク: タスクの実行」を選択します。

コマンドパレットからタスクの実行を選択

タスクの一覧の中から、先程 tasks.json に定義した ansible-lint current file を選択します。

タスク ansible-lint current file を選択

すると、開いていた Playbook に対して ansible-lint が実行され、問題の箇所に波線が引かれたり、問題の一覧が表示されたります。

ansible-lint 結果がエディタ内や問題一覧に表示される

ファイル保存時に自動 ansible-lint

ここまでで、タスク経由で ansible-lint を実行して問題として扱えるようになりました。

しかしまだ、都度タスクを実行するが手間と感じため、ファイル保存時に ansible-lint ができるようにしようと考えました。 (本当はリアルタイムにやりたい)。

ファイル保存をトリガーにしてタスクを実行する機能は標準にはないようなので、「Trigger Task on Save」という拡張を利用しました。

インストールした上で、.vscode/settings.jsontasks.jsonではなく)に、以下の設定を追加します。

  • .vscode/settings.json
{
    // 既存設定は省略

    "triggerTaskOnSave.on": true,
    "triggerTaskOnSave.tasks": {
        "ansible-lint current file": [
            "*.yml",
            "*.yaml"
        ]
    }
}

これで、*.yml*.yaml のファイルを保存するときに、さきほどのタスク ansible-lint current file を実行するようになります。

さらに yamllint も同時に自動実行

ansible-lint と似た linter に yamllint があります。(pip install yamllint でインストール)

ansible-lintyamllint のルールをカバーしているわけではないので、両者を組み合わせて利用されているかたも多いのではないでしょうか。

同じような設定することで、yamllint も同時に自動実行できるようになります。

両方実行する、tasks.jsonsettings.json はそれぞれ以下の通りです。

  • .vscode/tasks.json
{
  // See https://go.microsoft.com/fwlink/?LinkId=733558
  // for the documentation about the tasks.json format
  "version": "2.0.0",
  "tasks": [
    // {
    //   "label": "echo",
    //   "type": "shell",
    //   "command": "echo Hello"
    // },
    {
      "label": "ansible-lint current file",
      "type": "shell",
      "command": "/root/envs/a2914/bin/ansible-lint",
      "args": [
        "${file}",
        "-p"
      ],
      "detail": "現在開いているファイルを ansible-lint する",
      "presentation": {
        "reveal": "never",
      },
      "problemMatcher": {
        "owner": "ansible-lint",
        "fileLocation": "autoDetect",
        "pattern":[
            {
                // sample
                // 01_show.yml:10: [E201] Trailing whitespace
                "regexp": "^(.+):(\\d+): (.+)$",
                "file": 1,
                "line": 2,
                "message": 3,
            }
          ],
      },
    },
    {
      "label": "yamllint current file",
      "type": "shell",
      "command": "/root/envs/a2914/bin/yamllint",
      "args": [
        "-f",
        "parsable",
        "${file}",
      ],
      "detail": "現在開いているファイルを yamllint する",
      "presentation": {
        "reveal": "never",
      },
      // "isBackground": true,
      "problemMatcher": {
        "owner": "yamlllint",
        "fileLocation": "autoDetect",
        "pattern":[
            {
                // sample
                /// /home/sakana/01_show.yml:8:1: [error] too many blank lines (8 > 0) (empty-lines)
                "regexp": "^(.+):(\\d+):(\\d+): \\[(.+?)\\] (.+)$",
                "file": 1,
                "line": 2,
                "column": 3,
                "severity": 4,
                "message": 5,
            }
          ],
      },
    },
  ]
}
  • .vscode/settings.json
{
    // 既存設定は省略

    "triggerTaskOnSave.on": true,
    "triggerTaskOnSave.tasks": {
        "ansible-lint current file": [
            "*.yml",
            "*.yaml"
        ],
        "yamllint current file": [
            "*.yml",
            "*.yaml"
        ],
    }
}

これで、ファイル保存時に ansible-lintyamllint が実行されます。

ansible-lintとyamllint同時実行

ansible-lint では引っかからなかった、 真偽値は falsetrue で指定してね、というメッセージが表示されるようになったことが分かります。


さらに(妄想レベル)

さらに、ansible-playook コマンドの --syntax-check オプションの結果も扱えるようにできたらいいなと思っています。

また、ファイル保存時ではなく、もっと早くリアルタイムに「問題」として検出できる方法があれば知りたいです。


Part21 にむけて

以下のネタを検討中です。気が向いたものをやります。

  • Ansible 2.10 関連ほかにも
  • connection: local ななにか
  • Ansible Toewr / AWX をコマンドがら操作する
  • ansible.cfg
  • Jinja2、フィルター
  • Windows
  • ESXi で VM作成
  • parsee_cli モジュール(Part15 の続き)