loading...

Configuration of ansible-lint

koh_sh profile image koh-sh ・5 min read

ansible-lint is a tool to check Ansible Playbook.

GitHub logo ansible / ansible-lint

Best practices checker for Ansible

PyPI version Ansible-lint rules explanation Ansible Code of Conduct Ansible mailing lists GitHub Actions CI/CD Language grade: Python pre-commit

Ansible-lint

ansible-lint checks playbooks for practices and behaviour 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

Installing

Installing on Windows is not supported because we use symlinks inside Python packages.

Using Pip

pip install ansible-lint

From Source

Note: pip 19.0+ is required for installation. Please consult with the PyPA User Guide to learn more about managing Pip versions.

pip install git+https://github.com/ansible/ansible-lint.git

Usage

Command Line Options

The following is the output from ansible-lint --help, providing an overview of the basic command line options:

usage: ansible-lint [-h] [-L] [-q] [-p] [--parseable-severity] [-r RULESDIR]
                    [-R] [--show-relpath] [-t TAGS] [-T] [-v] [-x SKIP_LIST]
                    [--nocolor] [--force-color] [--exclude EXCLUDE_PATHS]
                    [-c CONFIG_FILE] [--version]
                    [playbook [playbook ...]]
positional arguments:
  playbook              One or more files or paths. When missing it will
                        enable auto-detection mode.

optional arguments:
  -h, --help

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))

https://github.com/ansible/ansible-lint/blob/5170c04201e71400421b27255280902c211f8548/lib/ansiblelint/__init__.py#L281

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.

Discussion

pic
Editor guide