Chapter 02

Ansible lint のコマンドオプション

mamono210
mamono210
2022.12.23に更新

Ansible lint のコマンドについて解説します。

$ ansible-lint --help
usage: ansible-lint [-h] [-L | -T]
                    [-f {rich,plain,md,json,codeclimate,quiet,pep8,sarif,docs}]
                    [-q]
                    [-P [{min,basic,moderate,safety,shared,production} ...]]
                    [-p] [--progressive] [--project-dir PROJECT_DIR]
                    [-r RULESDIR] [-R] [-s] [--write [WRITE_LIST]]
                    [--show-relpath] [-t TAGS] [-v] [-x SKIP_LIST]
                    [-w WARN_LIST] [--enable-list ENABLE_LIST] [--nocolor]
                    [--force-color] [--exclude EXCLUDE_PATHS] [-c CONFIG_FILE]
                    [--offline] [--version]
                    [lintables ...]

positional arguments:
  lintables             One or more files or paths. When missing it will
                        enable auto-detection mode.

options:
  -h, --help            show this help message and exit
  -L, --list-rules      List all the rules. For listing rules only the
                        following formats for argument -f are supported:
                        {plain, rich, md}
  -T, --list-tags       List all the tags and the rules they cover. Increase
                        the verbosity level with `-v` to include 'opt-in' tag
                        and its rules.
  -f {rich,plain,md,json,codeclimate,quiet,pep8,sarif,docs}, --format {rich,plain,md,json,codeclimate,quiet,pep8,sarif,docs}
                        stdout formatting, json being an alias for
                        codeclimate. (default: rich)
  -q                    quieter, reduce verbosity, can be specified twice.
  -P [{min,basic,moderate,safety,shared,production} ...], --profile [{min,basic,moderate,safety,shared,production} ...]
                        Specify which rules profile to be used, or displays
                        available profiles when no argument is given.
  -p, --parseable       parseable output, same as '-f pep8'
  --progressive         Return success if it detects a reduction in number of
                        violations compared with previous git commit. This
                        feature works only in git repositories.
  --project-dir PROJECT_DIR
                        Location of project/repository, autodetected based on
                        location of configuration file.
  -r RULESDIR, --rules-dir RULESDIR
                        Specify custom rule directories. Add -R to keep using
                        embedded rules from /home/docs/checkouts/readthedocs.o
                        rg/user_builds/ansible-
                        lint/envs/latest/lib/python3.10/site-
                        packages/ansiblelint/rules
  -R                    Keep default rules when using -r
  -s, --strict          Return non-zero exit code on warnings as well as
                        errors
  --write [WRITE_LIST]  Allow ansible-lint to reformat YAML files and run rule
                        transforms (Reformatting YAML files standardizes
                        spacing, quotes, etc. A rule transform can fix or
                        simplify fixing issues identified by that rule). You
                        can limit the effective rule transforms (the
                        'write_list') by passing a keywords 'all' or 'none' or
                        a comma separated list of rule ids or rule tags. YAML
                        reformatting happens whenever '--write' or '--write='
                        is used. '--write' and '--write=all' are equivalent:
                        they allow all transforms to run. The effective list
                        of transforms comes from 'write_list' in the config
                        file, followed whatever '--write' args are provided on
                        the commandline. '--write=none' resets the list of
                        transforms to allow reformatting YAML without running
                        any of the transforms (ie '--write=none,rule-id' will
                        ignore write_list in the config file and only run the
                        rule-id transform).
  --show-relpath        Display path relative to CWD
  -t TAGS, --tags TAGS  only check rules whose id/tags match these values
  -v                    Increase verbosity level (-vv for more)
  -x SKIP_LIST, --skip-list SKIP_LIST
                        only check rules whose id/tags do not match these
                        values
  -w WARN_LIST, --warn-list WARN_LIST
                        only warn about these rules, unless overridden in
                        config file. Current version default value is: avoid-
                        implicit, experimental, fqcn[action], fqcn[redirect],
                        jinja[spacing], name[casing], name[play], role-name,
                        warning[empty-playbook], role-name[path]
  --enable-list ENABLE_LIST
                        activate optional rules by their tag name
  --nocolor             disable colored output, same as NO_COLOR=1
  --force-color         Force colored output, same as FORCE_COLOR=1
  --exclude EXCLUDE_PATHS
                        path to directories or files to skip. This option is
                        repeatable.
  -c CONFIG_FILE, --config-file CONFIG_FILE
                        Specify configuration file to use. By default it will
                        look for '.ansible-lint' or '.config/ansible-lint.yml'
  --offline             Disable installation of requirements.yml
  --version

基本的なコマンド

ansible-lint <ファイル名>

になります。ファイル名が省略された場合は Ansible lint が playbook、role、collection 等のファイルを自動的に検出し lint 処理を実行します。

全てのルールを表示する 【-L, --list-rules】

ansible-lint -L
## もしくは 
## ansible-lint --list-rules

出力形式は「rich、plain、md」を指定できます。何も指定しないとrich形式の出力になります。

タグで定められたルールを表示する(ルールの小分類を表示する) 【-T, --list-tags】

それぞれのルールがどのように分類されているか表示します。またこれらの分類はタグを指定する事で指定されたタグのルールのみ lint を実行することもできます。Ansible lint のルールの基本的な考え方が分かります。

ansible-lint -T
## もしくは
ansible-lint --list-tags

# List of tags and rules they cover
command-shell:  # Specific to use of command and shell modules
  - command-instead-of-module
  - command-instead-of-shell
  - deprecated-command-syntax
  - inline-env-var
  - no-changed-when
  - risky-shell-pipe
core:  # Related to internal implementation of the linter
  - internal-error
  - load-failure
  - parser-error
  - syntax-check
  - warning
  - schema
deprecations:  # Indicate use of features that are removed from Ansible
  - deprecated-bare-vars
  - deprecated-command-syntax
  - deprecated-local-action
  - deprecated-module
  - no-jinja-when
  - role-name
experimental:  # Newly introduced rules, by default triggering only warnings
  - warning
  - avoid-implicit
  - galaxy
  - ignore-errors
  - key-order
  - no-free-form
  - no-log-password
  - no-prompting
  - only-builtins
  - risky-file-permissions
  - run-once
  - schema
  - var-naming
formatting:  # Related to code-style
  - yaml
  - fqcn
  - jinja
  - key-order
  - no-tabs
  - playbook-extension
  - risky-octal
idempotency:  # Possible indication that consequent runs would produce different results
  - latest
  - no-changed-when
  - package-latest
idiom:  # Anti-pattern detected, likely to cause undesired behavior
  - command-instead-of-module
  - command-instead-of-shell
  - empty-string-compare
  - inline-env-var
  - literal-compare
  - loop-var-prefix
  - name
  - no-handler
  - no-relative-paths
  - run-once
  - var-naming
metadata:  # Invalid metadata, likely related to galaxy, collections or roles
  - galaxy
  - meta-incorrect
  - meta-no-info
  - meta-no-tags
  - meta-video-links
  - role-name
opt-in:  # Rules that are not used unless manually added to `enable_list`
  - empty-string-compare
  - galaxy
  - no-log-password
  - no-prompting
  - no-same-owner
  - only-builtins
risk:
  - no-free-form
security:  # Rules related o potentially security issues, like exposing credentials
  - no-log-password
syntax:
  - no-free-form
unpredictability:  # Warn about code that might not work in a predictable way
  - avoid-implicit
  - ignore-errors
  - partial-become
  - risky-file-permissions
unskippable:  # Indicate a fatal error that cannot be ignored or disabled
  - load-failure
yaml:  # External linter which will also produce its own rule codes
  - yaml

出力形式を指定する 【-f <format-name>, --format <format-name>】

コマンドの実行結果の出力形式を指定します。指定できる形式は

  • rich
  • plain
  • md
  • json
  • codeclimate
  • quiet
  • pep8
  • sarif
  • docs

になります。

ansible-lint
WARNING  Listing 1 violation(s) that are fatal
roles/create-backup:1: role-name: Role name create-backup does not match ``^*$`` pattern. (warning)

                  Rule Violation Summary                  
 count tag       profile rule associated tags             
     1 role-name basic   deprecations, metadata (warning) 

Passed with min profile: 0 failure(s), 1 warning(s) on 15 files.
A new release of ansible-lint is available: 6.8.4 → 6.8.5 Upgrade by running: pip3 install --user --upgrade ansible-lint
ansible-lint -f json
[{"type": "issue", "check_name": "role-name", "categories": ["deprecations", "metadata"], "url": "https://ansible-lint.readthedocs.io/rules/role-name/", "severity": "info", "description": "Role name create-backup does not match ``^\\[a-z]\\[a-z0-9_]*$`` pattern.", "fingerprint": "b6a7a8b84b404967d988b9ffb58662ac0ed3115f22e6bda953b27e89632dac75", "location": {"path": "roles/create-backup", "lines": {"begin": 1}}}]

                  Rule Violation Summary                  
 count tag       profile rule associated tags             
     1 role-name basic   deprecations, metadata (warning) 

Passed with min profile: 0 failure(s), 1 warning(s) on 15 files.
A new release of ansible-lint is available: 6.8.4 → 6.8.5 Upgrade by running: pip3 install --user --upgrade ansible-lint

表示される情報を少なくする 【-q】

ansible-lint -q
roles/create-backup:1: role-name (warning)

Profileを指定する 【-P <profile-name>, --profile <profile-name>】

適用する Profile を指定します。指定できる profile は

  • min
  • basic
  • moderate
  • safety
  • shared
  • production

です。

何も指定しないとproductionが適用されます。

通常 (何も指定しないと profile に production が指定される)

ansible-lint
WARNING  Listing 1 violation(s) that are fatal
roles/create-backup:1: role-name: Role name create-backup does not match ``^*$`` pattern. (warning)

                  Rule Violation Summary                  
 count tag       profile rule associated tags             
     1 role-name basic   deprecations, metadata (warning) 

Passed with min profile: 0 failure(s), 1 warning(s) on 15 files.
A new release of ansible-lint is available: 6.8.4 → 6.8.5 Upgrade by running: pip3 install --user --upgrade ansible-lint

必要最低限の lint を実行する (profile に min を指定する)

ansible-lint -p min

Passed with production profile: 0 failure(s), 0 warning(s) on 1 files.
A new release of ansible-lint is available: 6.8.4 → 6.8.5 Upgrade by running: pip3 install --user --upgrade ansible-lint

前回の commit と比べて改善があれば success を返す 【--progress】

Git での開発が前提です。前回の commit 時と内容を比べ1つでもルール違反が少なくなっていれば success を返します。

ansible-lint --progress

プロジェクトディレクトリを指定する 【--project-dir <project-dir>】

なぞのオプションです。プロジェクト内にある Galaxy role 等のパスを指定するとその Role をチェックします。しかしその Role に対して Ansible lint は実行されません。(Ansible lint 6.8系で動作確認時)

警告をエラーと見なす 【-s, --strict】

Ansible lint を strict モードで実行します。

ansible-lint -s
## もしくは
ansible-lint --strict

YAML ファイルを Ansible lint の推奨する形式に書き直す 【--write】

YAMLファイルが Ansible lint が推奨する形式に書き換えられます。

ansible-lint --write

例えば

tasks/main.yml
 - name: Create WordPress install directory
   ansible.builtin.file:
-    dest: '{{ wp_install_path }}'
+    dest: "{{ wp_install_path }}"
     state: directory
     owner: apache
     group: apache
     mode: 0755
-    recurse: yes
+    recurse: true
.yamllint
 yaml-files:
-  - '*.yaml'
-  - '*.yml'
-  - '.yamllint'
+  - "*.yaml"
+  - "*.yml"
+  - .yamllint

のようにフォーマットされます。

主にインデント、クウォート、スペース等がチェックされますが記事執筆時の 6.8 系では例えば fqcn の修正等の Ansible 独自の機能や yamllintkey-ordering のようなフォーマットは行われないみたいです。

タグで指定されたルール群のみ適用する 【-t TAGS, --tags TAGS】

ansible-lint --list-tagsで分類されているタグを利用して特定のルール群のみ Ansible lint を適用します。

ansible-lint -t

例えば Module の FQCN を記述していない場合は通常通り Ansible lint を実行すると以下のようなエラーが出ます。

tasks/main.yml
---
- name: Install cowsay
  package:
    name: cowsay
    state: present
ansible-lint tasks/main.yml
WARNING  Listing 1 violation(s) that are fatal
tasks/main.yml:2: fqcn[action-core]: Use FQCN for builtin module actions (package).
You can skip specific rules or tags by adding them to your configuration file:
# .config/ansible-lint.yml
warn_list:  # or 'skip_list' to silence them completely
  - fqcn[action-core]  # Use FQCN for builtin actions.

                 Rule Violation Summary                  
 count tag               profile    rule associated tags 
     1 ]8;id=404615;https://ansible-lint.readthedocs.io/rules/fqcn\fqcn[action-core]]8;;\ production formatting           

Failed after shared profile, 4/5 star rating: 1 failure(s), 0 warning(s) on 1 files.

Exited with code exit status 2

これをタグ名coreに属するルールのみ適用すると FQCN 等のルールは適用されないためエラーになりません。

nsible-lint -t core tasks/main.yml

Passed with production profile: 0 failure(s), 0 warning(s) on 1 files.

Verbose モードで実行する 【-v, -vv】

ログの出力が細かくなります。vは2つまでで3つ以上つけてもそれ以上表示は変わらないみたいです。

ansible-lint tasks/main.yml -v

INFO     Set ANSIBLE_LIBRARY=/home/mamono210/.cache/ansible-compat/244210/modules:/home/mamono210/.ansible/plugins/modules:/usr/share/ansible/plugins/modules
INFO     Set ANSIBLE_COLLECTIONS_PATH=/home/mamono210/.cache/ansible-compat/244210/collections:/home/mamono210/.ansible/collections:/usr/share/ansible/collections
INFO     Set ANSIBLE_ROLES_PATH=/home/mamono210/.cache/ansible-compat/244210/roles:/home/mamono210/.ansible/roles:/usr/share/ansible/roles:/etc/ansible/roles
INFO     Using /home/mamono210/.cache/ansible-compat/244210/roles/mamono210.cowsay symlink to current repository in order to enable Ansible to find the role using its expected full name.

Passed with production profile: 0 failure(s), 0 warning(s) on 1 files.
ansible-lint tasks/main.yml -vv

DEBUG    Logging initialized to level 10
DEBUG    Options: Namespace(cache_dir='/home/mamono210/.cache/ansible-compat/244210', colored=True, configured=True, cwd=PosixPath('/home/mamono210/project'), display_relative_path=True, exclude_paths=['.cache', '.git', '.hg', '.svn', '.tox'], format='rich', lintables=['tasks/main.yml'], listrules=False, listtags=False, write_list=[], parseable=True, quiet=False, rulesdirs=['/home/mamono210/.local/lib/python3.11/site-packages/ansiblelint/rules'], skip_list=[], tags=[], verbosity=2, warn_list=['avoid-implicit', 'experimental', 'fqcn[action]', 'fqcn[redirect]', 'jinja[spacing]', 'name[casing]', 'name[play]', 'role-name', 'warning[empty-playbook]', 'role-name[path]'], kinds=[{'jinja2': '**/*.j2'}, {'jinja2': '**/*.j2.*'}, {'yaml': '.github/**/*.{yaml,yml}'}, {'text': '**/templates/**/*.*'}, {'execution-environment': '**/execution-environment.yml'}, {'ansible-lint-config': '**/.ansible-lint'}, {'ansible-lint-config': '**/.config/ansible-lint.yml'}, {'ansible-navigator-config': '**/ansible-navigator.{yaml,yml}'}, {'inventory': '**/inventory/**.{yaml,yml}'}, {'requirements': '**/meta/requirements.{yaml,yml}'}, {'galaxy': '**/galaxy.yml'}, {'reno': '**/releasenotes/*/*.{yaml,yml}'}, {'tasks': '**/tasks/**/*.{yaml,yml}'}, {'playbook': '**/playbooks/*.{yml,yaml}'}, {'playbook': '**/*playbook*.{yml,yaml}'}, {'role': '**/roles/*/'}, {'handlers': '**/handlers/*.{yaml,yml}'}, {'vars': '**/{host_vars,group_vars,vars,defaults}/**/*.{yaml,yml}'}, {'test-meta': '**/tests/integration/targets/*/meta/main.{yaml,yml}'}, {'meta': '**/meta/main.{yaml,yml}'}, {'meta-runtime': '**/meta/runtime.{yaml,yml}'}, {'arg_specs': '**/meta/argument_specs.{yaml,yml}'}, {'yaml': '.config/molecule/config.{yaml,yml}'}, {'requirements': '**/molecule/*/{collections,requirements}.{yaml,yml}'}, {'yaml': '**/molecule/*/{base,molecule}.{yaml,yml}'}, {'requirements': '**/requirements.{yaml,yml}'}, {'playbook': '**/molecule/*/*.{yaml,yml}'}, {'yaml': '**/{.ansible-lint,.yamllint}'}, {'yaml': '**/*.{yaml,yml}'}, {'yaml': '**/.*.{yaml,yml}'}], mock_filters=[], mock_modules=[], mock_roles=[], loop_var_prefix=None, var_naming_pattern=None, offline=False, project_dir='.', extra_vars=None, enable_list=[], skip_action_validation=True, strict=False, rules={}, profile=None, progressive=False, rulesdir=[], use_default_rules=False, config_file='/home/mamono210/project/.ansible-lint', version=False, cache_dir_lock=<filelock._unix.UnixFileLock object at 0x7f318b9f4d10>)
DEBUG    /home/mamono210/project
DEBUG    Loading custom .yamllint config file, this extends our internal yamllint config.
DEBUG    Effective yamllint rules used: {'braces': {'level': 'error', 'forbid': False, 'min-spaces-inside': 0, 'max-spaces-inside': 0, 'min-spaces-inside-empty': -1, 'max-spaces-inside-empty': -1}, 'brackets': {'level': 'error', 'forbid': False, 'min-spaces-inside': 0, 'max-spaces-inside': 0, 'min-spaces-inside-empty': -1, 'max-spaces-inside-empty': -1}, 'colons': {'level': 'error', 'max-spaces-before': 0, 'max-spaces-after': 1}, 'commas': {'level': 'error', 'max-spaces-before': 0, 'min-spaces-after': 1, 'max-spaces-after': 1}, 'comments': {'level': 'error', 'require-starting-space': True, 'ignore-shebangs': True, 'min-spaces-from-content': 2}, 'comments-indentation': {'level': 'error'}, 'document-end': False, 'document-start': {'level': 'error', 'present': True}, 'empty-lines': {'level': 'error', 'max': 2, 'max-start': 0, 'max-end': 0}, 'empty-values': False, 'float-values': False, 'hyphens': {'level': 'error', 'max-spaces-after': 1}, 'indentation': {'level': 'error', 'spaces': 'consistent', 'indent-sequences': True, 'check-multi-line-strings': False}, 'key-duplicates': {'level': 'error'}, 'key-ordering': False, 'line-length': False, 'new-line-at-end-of-file': {'level': 'error'}, 'new-lines': {'level': 'error', 'type': 'unix'}, 'octal-values': False, 'quoted-strings': False, 'trailing-spaces': {'level': 'error'}, 'truthy': False}
INFO     Set ANSIBLE_LIBRARY=/home/mamono210/.cache/ansible-compat/244210/modules:/home/mamono210/.ansible/plugins/modules:/usr/share/ansible/plugins/modules
INFO     Set ANSIBLE_COLLECTIONS_PATH=/home/mamono210/.cache/ansible-compat/244210/collections:/home/mamono210/.ansible/collections:/usr/share/ansible/collections
INFO     Set ANSIBLE_ROLES_PATH=/home/mamono210/.cache/ansible-compat/244210/roles:/home/mamono210/.ansible/roles:/usr/share/ansible/roles:/etc/ansible/roles
INFO     Using /home/mamono210/.cache/ansible-compat/244210/roles/mamono210.cowsay symlink to current repository in order to enable Ansible to find the role using its expected full name.
DEBUG    Examining tasks/main.yml of type tasks
DEBUG    Attempting to release lock 139850772598032 on /home/mamono210/.cache/ansible-compat/244210/.lock
DEBUG    Lock 139850772598032 released on /home/mamono210/.cache/ansible-compat/244210/.lock

DEBUG    Determined rule-profile order: {'internal-error': (0, 'min'), 'load-failure': (1, 'min'), 'parser-error': (2, 'min'), 'syntax-check': (3, 'min'), 'command-instead-of-module': (4, 'basic'), 'command-instead-of-shell': (5, 'basic'), 'deprecated-bare-vars': (6, 'basic'), 'deprecated-command-syntax': (7, 'basic'), 'deprecated-local-action': (8, 'basic'), 'deprecated-module': (9, 'basic'), 'inline-env-var': (10, 'basic'), 'key-order': (11, 'basic'), 'literal-compare': (12, 'basic'), 'jinja': (13, 'basic'), 'no-jinja-when': (14, 'basic'), 'no-tabs': (15, 'basic'), 'partial-become': (16, 'basic'), 'playbook-extension': (17, 'basic'), 'role-name': (18, 'basic'), 'schema': (19, 'basic'), 'name': (20, 'basic'), 'var-naming': (21, 'basic'), 'yaml': (22, 'basic'), 'name[template]': (23, 'moderate'), 'name[imperative]': (24, 'moderate'), 'name[casing]': (25, 'moderate'), 'no-free-form': (26, 'moderate'), 'spell-var-name': (27, 'moderate'), 'avoid-implicit': (28, 'safety'), 'latest': (29, 'safety'), 'package-latest': (30, 'safety'), 'risky-file-permissions': (31, 'safety'), 'risky-octal': (32, 'safety'), 'risky-shell-pipe': (33, 'safety'), 'galaxy': (34, 'shared'), 'ignore-errors': (35, 'shared'), 'layout': (36, 'shared'), 'meta-incorrect': (37, 'shared'), 'meta-no-info': (38, 'shared'), 'meta-no-tags': (39, 'shared'), 'meta-video-links': (40, 'shared'), 'meta-version': (41, 'shared'), 'meta-unsupported-ansible': (42, 'shared'), 'no-changed-when': (43, 'shared'), 'no-changelog': (44, 'shared'), 'no-handler': (45, 'shared'), 'no-relative-paths': (46, 'shared'), 'max-block-depth': (47, 'shared'), 'max-tasks': (48, 'shared'), 'unsafe-loop': (49, 'shared'), 'avoid-dot-notation': (50, 'production'), 'disallowed-ignore': (51, 'production'), 'fqcn': (52, 'production'), 'import-task-no-when': (53, 'production'), 'meta-no-dependencies': (54, 'production'), 'single-entry-point': (55, 'production'), 'use-loop': (56, 'production')}
Passed with production profile: 0 failure(s), 0 warning(s) on 1 files.

設定ファイルのパスを変更する 【-c <config-file>, --config-file <config-file>】

Ansible lint の設定ファイルはプロジェクト内の .ansible-lint もしくは .config/ansible-lint.ymlのどちらかに配置されることにより実行時に内容が反映されます。

設定ファイルのパスを状況に応じて変更する場合(例えば開発時とプロダクション時で Ansible lint の設定を変更したい等)はパスの指定で変更可能です。

requirements.ymlからインストールしない 【--offline】

謎のオプションです。Ansible lint 以外のツールとの連携を図るために用意されているのかもしれません。

Ansible lintのバージョンを表示する 【--version】

Ansible lint のバージョン情報を表示します。

ansible-lint --version

ansible-lint 6.8.6 using ansible 2.13.6

Ansible のバージョン情報等が必要な場合はansible --versionansible-community --versionもあわせて実行します。

ansible --version
ansible [core 2.13.5]
  config file = None
  configured module search path = ['/home/mamono210/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /home/mamono210/.local/lib/python3.11/site-packages/ansible
  ansible collection location = /home/mamono210/.ansible/collections:/usr/share/ansible/collections
  executable location = /home/mamono210/.local/bin/ansible
  python version = 3.11.0 (main, Oct 25 2022, 05:00:36) [GCC 10.2.1 20210110]
  jinja version = 3.1.2
  libyaml = True

ansible-community --version
Ansible community version 6.5.0

参考サイト