ansible-lint

Best practices checker for Ansible

Github星跟踪图

.. image:: https://img.shields.io/pypi/v/ansible-lint.svg
:target: https://pypi.org/project/ansible-lint
:alt: PyPI version

.. image:: https://img.shields.io/badge/Ansible--lint-rules%20table-blue.svg
:target: https://docs.ansible.com/ansible-lint/rules/default_rules.html
:alt: Ansible-lint rules explanation

.. image:: https://img.shields.io/badge/Code%20of%20Conduct-Ansible-silver.svg
:target: https://docs.ansible.com/ansible/latest/community/code_of_conduct.html
:alt: Ansible Code of Conduct

.. image:: https://img.shields.io/badge/Mailing%20lists-Ansible-orange.svg
:target: https://docs.ansible.com/ansible/latest/community/communication.html#mailing-list-information
:alt: Ansible mailing lists

.. image:: https://img.shields.io/travis/com/ansible/ansible-lint/master.svg?label=Linux%20builds%20%40%20Travis%20CI
:target: https://travis-ci.com/ansible/ansible-lint
:alt: Travis CI build status

.. image:: https://github.com/ansible/ansible-lint/workflows/%F0%9F%91%B7/badge.svg
:target: https://github.com/ansible/ansible-lint/actions?query=workflow%3A%F0%9F%91%B7
:alt: ? GitHub Actions CI/CD build status — tests

.. image:: https://github.com/ansible/ansible-lint/workflows/%F0%9F%9A%A8/badge.svg
:target: https://github.com/ansible/ansible-lint/actions?query=workflow%3A%F0%9F%9A%A8
:alt: ? GitHub Actions CI/CD build status — linters

.. image:: https://img.shields.io/lgtm/grade/python/g/ansible/ansible-lint.svg?logo=lgtm&logoWidth=18
:target: https://lgtm.com/projects/g/ansible/ansible-lint/context:python
:alt: Language grade: Python

.. image:: https://img.shields.io/badge/pre--commit-enabled-brightgreen?logo=pre-commit&logoColor=white
:target: https://github.com/pre-commit/pre-commit
:alt: pre-commit

Ansible-lint

ansible-lint checks playbooks for practices and behaviour that could
potentially be improved.

Visit the Ansible Lint docs site <https://docs.ansible.com/ansible-lint/>_

Installing

.. installing-docs-inclusion-marker-do-not-remove

Using Pip

.. code-block:: bash

pip install ansible-lint

.. _installing_from_source:

From Source

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

.. code-block:: bash

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

.. _PyPA User Guide: https://packaging.python.org/tutorials/installing-packages/#ensure-pip-setuptools-and-wheel-are-up-to-date

.. installing-docs-inclusion-marker-end-do-not-remove

Usage

.. usage-docs-inclusion-marker-do-not-remove

Command Line Options

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

.. code-block:: bash

Usage: ansible-lint [options] [playbook.yml [playbook2 ...]], roledirectory

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 ['/path/to/ansible-
                        lint/lib/ansiblelint/rules'], unless -R is also used.
  -R                    Use default rules ['/path/to/ansible-
                        lint/lib/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 /path/to/file      Specify configuration file to use.  Defaults to
                          ".ansible-lint"

Linting Playbooks and Roles

It's important to note that ansible-lint accepts a list of Ansible playbook files or a list of role directories. Starting from a directory that contains the following, the playbook file, playbook.yml, or one of the role subdirectories, such as geerlingguy.apache, can be passed:

.. code-block:: bash

playbook.yml
roles/
geerlingguy.apache/
tasks/
handlers/
files/
templates/
vars/
defaults/
meta/
geerlingguy.elasticsearch/
tasks/
handlers/
files/
templates/
vars/
defaults/
meta/

The following lints the role geerlingguy.apache:

.. code-block:: bash

$ ansible-lint geerlingguy.apache

[305] Use shell only when shell functionality is required
/Users/chouseknecht/.ansible/roles/geerlingguy.apache/tasks/main.yml:19
Task/Handler: Get installed version of Apache.

[502] All tasks should be named
/Users/chouseknecht/.ansible/roles/geerlingguy.apache/tasks/main.yml:29
Task/Handler: include_vars apache-22.yml

[502] All tasks should be named
/Users/chouseknecht/.ansible/roles/geerlingguy.apache/tasks/main.yml:32
Task/Handler: include_vars apache-24.yml

Here's the contents of playbook.yml, which references multiples roles:

.. code-block:: yaml

  • name: Lint multiple roles
    hosts: all
    tasks:

    • include_role:
      name: geerlingguy.apache

    • include_role:
      name: geerlingguy.elasticsearch

The following lints playbook.yml, which evaluates both the playbook and the referenced roles:

.. code-block:: bash

$ ansible-lint playbook.yml

[305] Use shell only when shell functionality is required
/Users/chouseknecht/roles/geerlingguy.apache/tasks/main.yml:19
Task/Handler: Get installed version of Apache.

[502] All tasks should be named
/Users/chouseknecht/roles/geerlingguy.apache/tasks/main.yml:29
Task/Handler: include_vars apache-22.yml

[502] All tasks should be named
/Users/chouseknecht/roles/geerlingguy.apache/tasks/main.yml:32
Task/Handler: include_vars apache-24.yml

[502] All tasks should be named
/Users/chouseknecht/roles/geerlingguy.elasticsearch/tasks/main.yml:17
Task/Handler: service state=started name=elasticsearch enabled=yes

Since ansible-lint accepts a list of roles or playbooks, the following works as well, producing the same output as the example above:

.. code-block:: bash

$ ansible-lint geerlingguy.apache geerlingguy.elasticsearch

[305] Use shell only when shell functionality is required
/Users/chouseknecht/roles/geerlingguy.apache/tasks/main.yml:19
Task/Handler: Get installed version of Apache.

[502] All tasks should be named
/Users/chouseknecht/roles/geerlingguy.apache/tasks/main.yml:29
Task/Handler: include_vars apache-22.yml

[502] All tasks should be named
/Users/chouseknecht/roles/geerlingguy.apache/tasks/main.yml:32
Task/Handler: include_vars apache-24.yml

[502] All tasks should be named
/Users/chouseknecht/roles/geerlingguy.elasticsearch/tasks/main.yml:17
Task/Handler: service state=started name=elasticsearch enabled=yes

Examples

Included in ansible-lint/examples are some example playbooks with undesirable features. Running ansible-lint on them works, as demonstrated in the following:

.. code-block:: bash

$ ansible-lint examples/example.yml

[301] Commands should not change things if nothing needs doing
examples/example.yml:9
Task/Handler: unset variable

[206] Variables should have spaces before and after: {{ var_name }}
examples/example.yml:10
    action: command echo {{thisvariable}} is not set in this playbook

[301] Commands should not change things if nothing needs doing
examples/example.yml:12
Task/Handler: trailing whitespace

[201] Trailing whitespace
examples/example.yml:13
    action: command echo do nothing

[401] Git checkouts must contain explicit version
examples/example.yml:15
Task/Handler: git check

[401] Git checkouts must contain explicit version
examples/example.yml:18
Task/Handler: git check 2

[301] Commands should not change things if nothing needs doing
examples/example.yml:24
Task/Handler: executing git through command

[303] git used in place of git module
examples/example.yml:24
Task/Handler: executing git through command

[303] git used in place of git module
examples/example.yml:27
Task/Handler: executing git through command

[401] Git checkouts must contain explicit version
examples/example.yml:30
Task/Handler: using git module

[206] Variables should have spaces before and after: {{ var_name }}
examples/example.yml:34
    action: debug msg="{{item}}"

[201] Trailing whitespace
examples/example.yml:35
    with_items:

[403] Package installs should not use latest
examples/example.yml:39
Task/Handler: yum latest

[403] Package installs should not use latest
examples/example.yml:44
Task/Handler: apt latest

[101] Deprecated always_run
examples/example.yml:47
Task/Handler: always run

If playbooks include other playbooks, or tasks, or handlers or roles, these are also handled:

.. code-block:: bash

$ ansible-lint examples/include.yml

[301] Commands should not change things if nothing needs doing
examples/play.yml:5
Task/Handler: a bad play

[303] service used in place of service module
examples/play.yml:5
Task/Handler: a bad play

[401] Git checkouts must contain explicit version
examples/roles/bobbins/tasks/main.yml:2
Task/Handler: test tasks

[701] No 'galaxy_info' found
examples/roles/hello/meta/main.yml:1
{'meta/main.yml': {'dependencies': [{'role': 'bobbins', '__line__': 3, '__file__': '/Users/akx/build/ansible-lint/examples/roles/hello/meta/main.yml'}], '__line__': 1, '__file__': '/Users/akx/build/ansible-lint/examples/roles/hello/meta/main.yml', 'skipped_rules': []}}

[303] service used in place of service module
examples/roles/morecomplex/handlers/main.yml:1
Task/Handler: restart service using command

[301] Commands should not change things if nothing needs doing
examples/roles/morecomplex/tasks/main.yml:1
Task/Handler: test bad command

[302] mkdir used in place of argument state=directory to file module
examples/roles/morecomplex/tasks/main.yml:1
Task/Handler: test bad command

[301] Commands should not change things if nothing needs doing
examples/roles/morecomplex/tasks/main.yml:4
Task/Handler: test bad command v2

[302] mkdir used in place of argument state=directory to file module
examples/roles/morecomplex/tasks/main.yml:4
Task/Handler: test bad command v2

[301] Commands should not change things if nothing needs doing
examples/roles/morecomplex/tasks/main.yml:7
Task/Handler: test bad local command

[305] Use shell only when shell functionality is required
examples/roles/morecomplex/tasks/main.yml:7
Task/Handler: test bad local command

[504] Do not use 'local_action', use 'delegate_to: localhost'
examples/roles/morecomplex/tasks/main.yml:8
  local_action: shell touch foo

[201] Trailing whitespace
examples/tasks/x.yml:3
  args:

[201] Trailing whitespace
examples/tasks/x.yml:3
  args:

.. usage-docs-inclusion-marker-end-do-not-remove

Configuring

.. configuring-docs-inclusion-marker-do-not-remove

Configuration File

Ansible-lint supports local configuration via a .ansible-lint configuration file. Ansible-lint checks the working directory for the presence of this file and applies any configuration found there. The configuration file location can also be overridden via the -c path/to/file CLI flag.

If a value is provided on both the command line and via a config file, the values will be merged (if a list like exclude_paths), or the True value will be preferred, in the case of something like quiet.

The following values are supported, and function identically to their CLI counterparts:

.. code-block:: yaml

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

Pre-commit Setup

To use ansible-lint with pre-commit_, just add the following to your local repo's .pre-commit-config.yaml file. Make sure to change rev: to be either a git commit sha or tag of ansible-lint containing hooks.yaml.

.. code-block:: yaml

- repo: https://github.com/ansible/ansible-lint.git
  rev: v4.1.0
  hooks:
    - id: ansible-lint
      files: \.(yaml, yml)$

.. _pre-commit: https://pre-commit.com

.. configuring-docs-inclusion-marker-end-do-not-remove

Rules

.. rules-docs-inclusion-marker-do-not-remove

Specifying Rules at Runtime

By default, ansible-lint uses the rules found in ansible-lint/lib/ansiblelint/rules. To override this behavior and use a custom set of rules, use the -r /path/to/custom-rules option to provide a directory path containing the custom rules. For multiple rule sets, pass multiple -r options.

It's also possilbe to use the default rules, plus custom rules. This can be done by passing the -R to indicate that the deault rules are to be used, along with one or more -r options.

Using Tags to Include Rules


Each rule has an associated set of one or more tags. To view the list of tags for each available rule, use the ``-T`` option.

The following shows the available tags in an example set of rules, and the rules associated with each tag:

.. code-block:: bash

    $ ansible-lint -v -T

    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]']

To run just the *idempotency* rules, for example, run the following:

.. code-block:: bash

    $ ansible-lint -t idempotency playbook.yml

Excluding Rules
```````````````

To exclude rules from the available set of rules, use the ``-x SKIP_LIST`` option. For example, the following runs all of the rules except those with the tags *readability* and *safety*:

.. code-block:: bash

    $ ansible-lint -x readability,safety playbook.yml

It's also possible to skip specific rules by passing the rule ID. For example, the following excludes rule *502*:

.. code-block:: bash

    $ ansible-lint -x 502 playbook.yml

False Positives: Skipping Rules
-------------------------------

Some rules are a bit of a rule of thumb. Advanced *git*, *yum* or *apt* usage, for example, is typically difficult to achieve through the modules. In this case, you should mark the task so that warnings aren't produced.

To skip a specific rule for a specific task, inside your ansible yaml add ``# noqa [rule_id]`` at the end of the line. If the rule is task-based (most are), add at the end of any line in the task. You can skip multiple rules via a space-separated list.

.. code-block:: yaml

    - name: this would typically fire GitHasVersionRule 401 and BecomeUserWithoutBecomeRule 501
      become_user: alice  # noqa 401 501
      git: src=/path/to/git/repo dest=checkout

If the rule is line-based, ``# noqa [rule_id]`` must be at the end of the particular line to be skipped

.. code-block:: yaml

    - name: this would typically fire LineTooLongRule 204 and VariableHasSpacesRule 206
      get_url:
        url: http://example.com/really_long_path/really_long_path/really_long_path/really_long_path/really_long_path/really_long_path/file.conf  # noqa 204
        dest: "{{dest_proj_path}}/foo.conf"  # noqa 206


It's also a good practice to comment the reasons why a task is being skipped.

If you want skip running a rule entirely, you can use either:

* `command-line skip_list`_ via ``-x``
* `config file skip_list`_

A less-preferred method of skipping is to skip all task-based rules for a task (this does not skip line-based rules). There are two mechanisms for this: the ``skip_ansible_lint`` tag works with all tasks, and the ``warn`` parameter works with the *command* or *shell* modules only. Examples:

.. code-block:: yaml

    - name: this would typically fire CommandsInsteadOfArgumentRule 302
      command: warn=no chmod 644 X

    - name: this would typically fire CommandsInsteadOfModuleRule 303
      command: git pull --rebase
      args:
        warn: False

    - name: this would typically fire GitHasVersionRule 401
      git: src=/path/to/git/repo dest=checkout
      tags:
      - skip_ansible_lint

Creating Custom Rules
---------------------

Rules are described using a class file per rule. Default rules are named *DeprecatedVariableRule.py*, etc.

Each rule definition should have the following:

* ID: A unique identifier
* Short description: Brief description of the rule
* Description: Behaviour the rule is looking for
* Tags: one or more tags that may be used to include or exclude the rule
* At least one of the following methods:

  * ``match`` that takes a line and returns None or False, if the line doesn't match the test, and True or a custom message, when it does. (This allows one rule to test multiple behaviours - see e.g. the *CommandsInsteadOfModulesRule*.)
  * ``matchtask`` that operates on a single task or handler, such that tasks get standardized to always contain a *module* key and *module_arguments* key. Other common task modifiers, such as *when*, *with_items*, etc., are also available as keys, if present in the task.

An example rule using ``match`` is:

.. code-block:: python

    from ansiblelint import AnsibleLintRule

    class DeprecatedVariableRule(AnsibleLintRule):

        id = 'EXAMPLE002'
        shortdesc = 'Deprecated variable declarations'
        description = 'Check for lines that have old style ${var} ' + \
                      'declarations'
        tags = { 'deprecated' }

        def match(self, file, line):
            return '${' in line

An example rule using ``matchtask`` is:

.. code-block:: python

    import ansiblelint.utils
    from ansiblelint import AnsibleLintRule

    class TaskHasTag(AnsibleLintRule):
        id = 'EXAMPLE001'
        shortdesc = 'Tasks must have tag'
        description = 'Tasks must have tag'
        tags = ['productivity']

        def matchtask(self, file, task):
            # If the task include another task or make the playbook fail
            # Don't force to have a tag
            if not set(task.keys()).isdisjoint(['include','fail']):
                return False

            # Task should have tags
            if not task.has_key('tags'):
                  return True

        return False

The task argument to ``matchtask`` contains a number of keys - the critical one is *action*. The value of *task['action']* contains the module being used, and the arguments passed, both as key-value pairs and a list of other arguments (e.g. the command used with shell).

In ansible-lint 2.0.0, *task['action']['args']* was renamed *task['action']['module_arguments']* to avoid a clash when a module actually takes args as a parameter key (e.g. ec2_tag)

In ansible-lint 3.0.0 *task['action']['module']* was renamed *task['action']['__ansible_module__']* to avoid a clash when a module take module as an argument. As a precaution, *task['action']['module_arguments']* was renamed *task['action']['__ansible_arguments__']*.

.. rules-docs-inclusion-marker-end-do-not-remove

Contributing
============

Please read `Contribution guidelines`_ if you wish to contribute.

Authors
=======

ansible-lint was created by `Will Thames`_ and is now maintained as part of the `Ansible`_ by `Red Hat`_ project.

.. _Contribution guidelines: https://github.com/ansible/ansible-lint/blob/master/CONTRIBUTING.md
.. _Will Thames: https://github.com/willthames
.. _Ansible: https://ansible.com
.. _Red Hat: https://redhat.com
.. _command-line skip_list: https://docs.ansible.com/ansible-lint/usage/usage.html#command-line-options
.. _config file skip_list: https://docs.ansible.com/ansible-lint/configuring/configuring.html#configuration-file

主要指标

概览
名称与所有者ansible/ansible-lint
主编程语言Python
编程语言Python (语言数: 3)
平台
许可证GNU General Public License v3.0
所有者活动
创建于2013-08-14 11:08:00
推送于2025-06-10 15:43:58
最后一次提交
发布数160
最新版本名称v25.5.0 (发布于 )
第一版名称v3.1.1 (发布于 )
用户参与
星数3.7k
关注者数59
派生数686
提交数3k
已启用问题?
问题数1419
打开的问题数97
拉请求数2331
打开的拉请求数17
关闭的拉请求数422
项目设置
已启用Wiki?
已存档?
是复刻?
已锁定?
是镜像?
是私有?