ansible-lint is a tool to check Ansible Playbook.
ansible / ansible-lint
ansible-lint checks playbooks for practices and behavior that could potentially be improved and can fix some of the most common ones for you
Ansible-lint
ansible-lint
checks playbooks for practices and behavior that could
potentially be improved. As a community-backed project ansible-lint supports
only the last two major versions of Ansible.
Visit the Ansible Lint docs site
Using ansible-lint as a GitHub Action
This action allows you to run ansible-lint
on your codebase without having to
install it yourself.
# .github/workflows/ansible-lint.yml
name: ansible-lint
on:
pull_request:
branches: ["main", "stable", "release/v*"]
jobs:
build:
name: Ansible Lint # Naming the build is important to use it as a status check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run ansible-lint
uses: ansible/ansible-lint@main
# optional (see below):
with:
args: ""
setup_python: "true"
working_directory: ""
requirements_file: ""
All the arguments are optional and most users should not need them:
-
args
: Arguments to be passed to ansible-lint…
It helps you to find syntax problems like extra spaces or lines, or point out where doesn't follow Ansible best practice.
[koh@kohs-MBP] ~/work/linttest
% ansible-lint site.yml
[201] Trailing whitespace
site.yml:6
msg: hello
[403] Package installs should not use latest
site.yml:8
Task/Handler: install httpd
[koh@kohs-MBP] ~/work/linttest
%
Below is the list of default rules.
https://docs.ansible.com/ansible-lint/rules/default_rules.html
But each playbook or teams might have their own rules that oppose to Ansible best practice.
Here is how to configure ansible-lint.
*Version of ansible-lint is 4.1.0
.
Config with command line options
Rules are configurable with options of ansible-lint command.
[koh@kohs-MBP] ~/work/linttest
% ansible-lint --help
Usage: ansible-lint [options] playbook.yml [playbook2 ...]
Options:
--version show program's version number and exit
-h, --help show this help message and exit
-L list all the rules
-q quieter, although not silent output
-p parseable output in the format of pep8
--parseable-severity parseable output including severity of rule
-r RULESDIR specify one or more rules directories using one or
more -r arguments. Any -r flags override the default
rules in
/Users/koh/.pyenv/versions/3.7.3/lib/python3.7/site-
packages/ansiblelint/rules, unless -R is also used.
-R Use default rules in
/Users/koh/.pyenv/versions/3.7.3/lib/python3.7/site-
packages/ansiblelint/rules in addition to any extra
rules directories specified with -r. There is no need
to specify this if no -r flags are used
-t TAGS only check rules whose id/tags match these values
-T list all the tags
-v Increase verbosity level
-x SKIP_LIST only check rules whose id/tags do not match these
values
--nocolor disable colored output
--force-color Try force colored output (relying on ansible's code)
--exclude=EXCLUDE_PATHS
path to directories or files to skip. This option is
repeatable.
-c C Specify configuration file to use. Defaults to
".ansible-lint"
[koh@kohs-MBP] ~/work/linttest
%
Basically, you can configure everything with command line options but it is better to use a configuration file to share with your team, or to implement into CI.
Next is how to configure with a file.
Configuration file
It should be placed at ./.ansible-lint
by default, or a file which specified with the option -c
.
This is an example from the official doc.
exclude_paths:
- ./my/excluded/directory/
- ./my/other/excluded/directory/
- ./last/excluded/directory/
parseable: true
quiet: true
rulesdir:
- ./rule/directory/
skip_list:
- skip_this_tag
- and_this_one_too
- skip_this_id
- '401'
tags:
- run_this_tag
use_default_rules: true
verbosity: 1
https://docs.ansible.com/ansible-lint/configuring/configuring.html#configuration-file
exclude_paths (--exclude)
Specify paths or files to exclude from lint.
parseable (-p)
Change the format of the output.
Each error will be converted to one line.
# parseable: false
[koh@kohs-MBP] ~/work/linttest
% ansible-lint site.yml
[201] Trailing whitespace
/Users/koh/work/linttest/roles/201/tasks/main.yml:4
msg: hello
[202] Octal file permissions must contain leading zero or be a string
/Users/koh/work/linttest/roles/202/tasks/main.yml:2
Task/Handler: error 202
[203] Most files should not contain tabs
/Users/koh/work/linttest/roles/203/tasks/main.yml:4
msg: " tab"
[koh@kohs-MBP] ~/work/linttest
%
# parseable: true
[koh@kohs-MBP] ~/work/linttest
% ansible-lint site.yml
/Users/koh/work/linttest/roles/201/tasks/main.yml:4: [E201] Trailing whitespace
/Users/koh/work/linttest/roles/202/tasks/main.yml:2: [E202] Octal file permissions must contain leading zero or be a string
/Users/koh/work/linttest/roles/203/tasks/main.yml:4: [E203] Most files should not contain tabs
[koh@kohs-MBP] ~/work/linttest
%
quiet (-q)
Reduce output.
Not completely 0 but a bit reduced.
# quiet: true
[koh@kohs-MBP] ~/work/linttest
% ansible-lint site.yml
[201] /Users/koh/work/linttest/roles/201/tasks/main.yml:4
[202] /Users/koh/work/linttest/roles/202/tasks/main.yml:2
[203] /Users/koh/work/linttest/roles/203/tasks/main.yml:4
[koh@kohs-MBP] ~/work/linttest
%
rulesdir (-r)
Specify files or directories in which you put original rule files.
skip_list (-x)
Specify tags or error IDs that should be skipped.
You can check about tags with -T
option.
[koh@kohs-MBP] ~/work/linttest
% ansible-lint -T
ANSIBLE0002 ['[201]']
ANSIBLE0004 ['[401]']
ANSIBLE0005 ['[402]']
ANSIBLE0006 ['[303]']
ANSIBLE0007 ['[302]']
ANSIBLE0008 ['[103]']
ANSIBLE0009 ['[202]']
ANSIBLE0010 ['[403]']
ANSIBLE0011 ['[502]']
ANSIBLE0012 ['[301]']
ANSIBLE0013 ['[305]']
ANSIBLE0014 ['[304]']
ANSIBLE0015 ['[104]']
ANSIBLE0016 ['[503]']
ANSIBLE0017 ['[501]']
ANSIBLE0018 ['[101]']
ANSIBLE0019 ['[102]']
behaviour ['[503]']
bug ['[304]']
command-shell ['[305]', '[302]', '[304]', '[306]', '[301]', '[303]']
deprecated ['[105]', '[104]', '[103]', '[101]', '[102]']
formatting ['[104]', '[203]', '[201]', '[204]', '[206]', '[205]', '[202]']
idempotency ['[301]']
idiom ['[601]', '[602]']
metadata ['[701]', '[704]', '[703]', '[702]']
module ['[404]', '[401]', '[403]', '[402]']
oddity ['[501]']
readability ['[502]']
repeatability ['[401]', '[403]', '[402]']
resources ['[302]', '[303]']
safety ['[305]']
task ['[502]', '[503]', '[504]', '[501]']
[koh@kohs-MBP] ~/work/linttest
%
tags (-t)
Opposite of skip_list, specify tags that you want to check.
use_default_rules (-R)
If True, default rules are applied.
If you want to check only your original rules, set it to False.
verbosity (-v)
Specify the verbosity of the output.
It only takes 2 kinds of values which are 0 or greater than 0.
for file in files:
if self.verbosity > 0:
print("Examining %s of type %s" % (file['path'], file['type']))
matches.extend(self.rules.run(file, tags=set(self.tags),
skip_list=self.skip_list))
Configure inside Playbook
By adding a comment, you can skip checks by lines.
Below is an example of the Playbook.
[koh@kohs-MBP] ~/work/linttest
% cat site.yml
---
- hosts: all
tasks:
- name: install latest httpd
yum:
name: httpd
state: latest
- name: install mysql
yum:
name: mysql
state: installed
[koh@kohs-MBP] ~/work/linttest
%
This playbook throws 403 error.
[koh@kohs-MBP] ~/work/linttest
% ansible-lint site.yml
[403] Package installs should not use latest
site.yml:4
Task/Handler: install latest httpd
[koh@kohs-MBP] ~/work/linttest
%
If you really want to keep your httpd updated but not other packages, you can do like below. (you still should not do that though.)
[koh@kohs-MBP] ~/work/linttest
% cat site.yml
---
- hosts: all
tasks:
- name: install latest httpd
yum:
name: httpd
state: latest # noqa 403
- name: install mysql
yum:
name: mysql
state: installed
[koh@kohs-MBP] ~/work/linttest
%
By adding # noqa ID
, the line will be skipped from checks.
[koh@kohs-MBP] ~/work/linttest
% ansible-lint site.yml
[koh@kohs-MBP] ~/work/linttest
%
Original rules
You can create your own rules.
There are some explanations on README and also I recommend you to have a look at scripts of the default rules.
https://github.com/ansible/ansible-lint#creating-custom-rules
https://github.com/ansible/ansible-lint/tree/master/lib/ansiblelint/rules
Here is my example of how to create my own rule.
[koh@kohs-MBP] ~/work/linttest
% cat origrules/True4BooleanRule.py
from ansiblelint import AnsibleLintRule
class True4BooleanRule(AnsibleLintRule):
id = '99'
shortdesc = 'Use "True" for boolean'
description = 'We should "True" for boolean not "yes" or "true".'
tags = ['formatting']
def match(self, file, line):
return ': yes' in line or ': true' in line
[koh@kohs-MBP] ~/work/linttest
%
Playbook can take yes
, true
to set True
for boolean.
With this rule, it throws errors if yes
or true
are used.
*This is a really cheap script only for this explanation please use it with your own risk.
In .ansible-lint
[koh@kohs-MBP] ~/work/linttest
% cat .ansible-lint
rulesdir:
- ./origrules/
[koh@kohs-MBP] ~/work/linttest
%
With this site.yml, it throws 2 errors as intended.
[koh@kohs-MBP] ~/work/linttest
% cat site.yml
-
hosts: all
tasks:
- name: this should be error
service:
name: httpd
state: started
enabled: yes
- name: this should be error too
service:
name: mysqld
state: started
enabled: true
- name: this is ok
service:
name: haproxy
state: started
enabled: True
[koh@kohs-MBP] ~/work/linttest
% ansible-lint site.yml
[99] Use "True" for boolean
site.yml:8
enabled: yes
[99] Use "True" for boolean
site.yml:14
enabled: true
[koh@kohs-MBP] ~/work/linttest
%
Conclusion
Creating own rules is much easier than I expected.
So it is good to try one.
Top comments (0)