はじめに
2020/10/24 に、YouTube Live で「つまずき Ansible 【Part20】VSCodeでいい感じにansible-lintしたい」という配信をしました。
実際に作業しながら(ときには)エラーと戦って進めるシリーズです。
今回は、今回は、Playook の書きっぷりをチェックするツールである ansible-lint を Visual Studio Code からいい感じに呼び出す方法をました。
やったことをふりかえります。
- 環境
- ansible 2.9.14
- ansible-lint 4.3.5
2023/08/02 追記
現在では VS Code の Ansible 拡張 の標準で類似のことができるため、本記事のような設定は不要です。
動画
■ やったこと
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
を選択します。
すると、開いていた Playbook に対して ansible-lint
が実行され、問題の箇所に波線が引かれたり、問題の一覧が表示されたります。
ファイル保存時に自動 ansible-lint
ここまでで、タスク経由で ansible-lint
を実行して問題として扱えるようになりました。
しかしまだ、都度タスクを実行するが手間と感じため、ファイル保存時に ansible-lint
ができるようにしようと考えました。
(本当はリアルタイムにやりたい)。
ファイル保存をトリガーにしてタスクを実行する機能は標準にはないようなので、「Trigger Task on Save」という拡張を利用しました。
インストールした上で、.vscode/settings.json
(tasks.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-lint
は yamllint
のルールをカバーしているわけではないので、両者を組み合わせて利用されているかたも多いのではないでしょうか。
同じような設定することで、yamllint
も同時に自動実行できるようになります。
両方実行する、tasks.json
、settings.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-lint
と yamllint
が実行されます。
ansible-lint
では引っかからなかった、 真偽値は false
か true
で指定してね、というメッセージが表示されるようになったことが分かります。
さらに(妄想レベル)
さらに、ansible-playook
コマンドの --syntax-check
オプションの結果も扱えるようにできたらいいなと思っています。
また、ファイル保存時ではなく、もっと早くリアルタイムに「問題」として検出できる方法があれば知りたいです。
Part21 にむけて
以下のネタを検討中です。気が向いたものをやります。