Ansible Lint#
Ansible Lint – это утилита командной строки, предназначенная для проверки качества и стиля кода в сценариях, ролях и коллекциях Ansible. Она помогает следовать лучшим практикам при написании кода, выявлять распространенные ошибки и потенциальные проблемы, а также поддерживать чистоту и читаемость кода.
Основные возможности Ansible Lint#
Основные возможности Ansible Lint:
Проверка на соответствие стандартам.
Ansible Lint содержит правила написания кода из лучших практик, что позволяет избежать ошибок, ухудшающих качество и поддерживаемость кода.
Автоматическое выявление ошибок.
Утилита анализирует контент Ansible, указывая на места, которые могут быть потенциально проблемными или нестандартными.
Адаптация к новым версиям Ansible.
Ansible Lint помогает адаптировать код к новым версиям Ansible, что упрощает его обновление и предотвращает возможные несовместимости.
Установка#
Для установки Ansible Lint выполните следующие действия:
Подключите репозиторий Astra Automation.
Инструкция по подключению репозитория
В каталоге
/etc/apt/sources.list.d/
создайте файлastra-automation.list
со ссылкой на репозиторий Astra Automation:deb https://dl.astralinux.ru/aa/aa-debs-for-alse-1.7 <version> main
Вместо <version> необходимо подставить версию устанавливаемой платформы, например,
1.1-upd1
.Доступные версии продукта опубликованы в таблице История обновлений.
Обновите список доступных пакетов:
sudo apt update
Выполните команду:
sudo apt-get install ansible-lint --yes
Установка при отсутствии доступа к интернету описана в документе Инструменты.
Настройка Ansible Lint#
Ansible Lint предоставляет различные возможности для настройки в проектах:
игнорирование определенных правил;
включение дополнительных проверок;
настройка профилей под конкретные нужды.
Ansible Lint можно настроить с помощью следующих компонентов:
При вычислении действующих значений аргументов используется следующий порядок (значения, указанные на более поздних этапах, заменяют значения, указанные ранее):
Переменные окружения.
Файл настроек.
Аргументы команды.
По умолчанию Ansible Lint начинает поиск файла настроек с текущего каталога. Возможные названия и расположения файлов:
.ansible-lint
;.config/ansible-lint.yml
;.config/ansible-lint.yaml
.
Если файл настроек не найден в текущем каталоге, Ansible Lint попытается найти его в родительских каталогах.
Если используется Git, то поиск осуществляется только в пределах текущего репозитория.
Путь к файлу настроек можно указать явно с помощью аргумента -c
, например:
ansible-lint -c ansible-lint-config.yml
Настройки в конфигурационном файле задаются следующим образом:
Пример файла настроек
---
# .ansible-lint
profile: null # min, basic, moderate, safety, shared, production
# Allows dumping of results in SARIF format
# sarif_file: result.sarif
# exclude_paths included in this file are parsed relative to this file's location
# and not relative to the CWD of execution. CLI arguments passed to the --exclude
# option are parsed relative to the CWD of execution.
exclude_paths:
- .cache/ # implicit unless exclude_paths is defined in config
- test/fixtures/formatting-before/
- test/fixtures/formatting-prettier/
# parseable: true
# quiet: true
# strict: true
# verbosity: 1
# Mock modules or roles in order to pass ansible-playbook --syntax-check
mock_modules:
- zuul_return
# note the foo.bar is invalid as being neither a module or a collection
- fake_namespace.fake_collection.fake_module
- fake_namespace.fake_collection.fake_module.fake_submodule
mock_roles:
- mocked_role
- author.role_name # old standalone galaxy role
- fake_namespace.fake_collection.fake_role # role within a collection
# Enable checking of loop variable prefixes in roles
loop_var_prefix: "^(__|{role}_)"
# Enforce variable names to follow pattern below, in addition to Ansible own
# requirements, like avoiding python identifiers. To disable add `var-naming`
# to skip_list.
var_naming_pattern: "^[a-z_][a-z0-9_]*$"
use_default_rules: true
# Load custom rules from this specific folder
# rulesdir:
# - ./rule/directory/
# Ansible-lint is able to recognize and load skip rules stored inside
# `.ansible-lint-ignore` (or `.config/ansible-lint-ignore.txt`) files.
# To skip a rule just enter filename and tag, like "playbook.yml package-latest"
# on a new line.
# Optionally you can add comments after the tag, prefixed by "#". We discourage
# the use of skip_list below because that will hide violations from the output.
# When putting ignores inside the ignore file, they are marked as ignored, but
# still visible, making it easier to address later.
skip_list:
- skip_this_tag
# Ansible-lint does not automatically load rules that have the 'opt-in' tag.
# You must enable opt-in rules by listing each rule 'id' below.
enable_list:
- args
- empty-string-compare # opt-in
- no-log-password # opt-in
- no-same-owner # opt-in
- name[prefix] # opt-in
- galaxy-version-incorrect # opt-in
# add yaml here if you want to avoid ignoring yaml checks when yamllint
# library is missing. Normally its absence just skips using that rule.
- yaml
# Report only a subset of tags and fully ignore any others
# tags:
# - jinja[spacing]
# Ansible-lint does not fail on warnings from the rules or tags listed below
warn_list:
- skip_this_tag
- experimental # experimental is included in the implicit list
# - role-name
# - yaml[document-start] # you can also use sub-rule matches
# Some rules can transform files to fix (or make it easier to fix) identified
# errors. `ansible-lint --fix` will reformat YAML files and run these transforms.
# By default it will run all transforms (effectively `write_list: ["all"]`).
# You can disable running transforms by setting `write_list: ["none"]`.
# Or only enable a subset of rule transforms by listing rules/tags here.
# write_list:
# - all
# Offline mode disables installation of requirements.yml and schema refreshing
offline: true
# Define required Ansible's variables to satisfy syntax check
extra_vars:
foo: bar
multiline_string_variable: |
line1
line2
complex_variable: ":{;\t$()"
# Uncomment to enforce action validation with tasks, usually is not
# needed as Ansible syntax check also covers it.
# skip_action_validation: false
# List of additional kind:pattern to be added at the top of the default
# match list, first match determines the file kind.
kinds:
# - playbook: "**/examples/*.{yml,yaml}"
# - galaxy: "**/folder/galaxy.yml"
# - tasks: "**/tasks/*.yml"
# - vars: "**/vars/*.yml"
# - meta: "**/meta/main.yml"
- yaml: "**/*.yaml-too"
# List of additional collections to allow in only-builtins rule.
# only_builtins_allow_collections:
# - example_ns.example_collection
# List of additions modules to allow in only-builtins rule.
# only_builtins_allow_modules:
# - example_module
# Allow setting custom prefix for name[prefix] rule
task_name_prefix: "{stem} | "
# Complexity related settings
# Limit the depth of the nested blocks:
# max_block_depth: 20
# Also recognize these versions of Ansible as supported:
# supported_ansible_also:
# - "2.14"
Подробное описание параметров см. в справочнике.
Игнорирование правил для определенных файлов#
Чтобы при проверке файлов Ansible Lint не использовал определенные правила, создайте файл .ansible-lint-ignore
или .config/ansible-lint-ignore.txt
.
Созданный файл должен быть размещен в том же каталоге, что и файл основных настроек Ansible Lint.
Каждая строка содержит путь к файлу и через пробел идентификатор правила.
Пример заполнения:
# Игнорирование правила package-latest для файла playbook.yml
playbook.yml package-latest
# Игнорирование правила deprecated-module для playbook.yml
playbook.yml deprecated-module
# Игнорирование правила no-tabs для роли my_role
roles/my_role/tasks/main.yml no-tabs
Создание правил#
Ansible Lint позволяет создавать правила, содержащие собственные уникальные проверки, для поддержки стиля кодирования, принятого в вашей организации.
Каждое правило необходимо создавать в отдельном файле Python и описывать в виде класса, который наследует AnsibleLintRule
.
Файл с правилом следует именовать согласно цели правила, например, DeprecatedVariableRule.py
.
Внутри каждого класса должны быть следующие поля:
id
– уникальный идентификатор правила;description
– краткое описание правила (какой тип ошибок оно выявляет);tags
– список тегов для группировки правил, близких по смыслу.
Для проверки кода по заданному правилу используют следующие методы:
match
;matchtask
.
Метод match
работает с каждой строкой и возвращает результат проверки.
Если строка не соответствует критерию, метод возвращает None
или False
.
Если строка соответствует критерию, метод возвращает True
или настраиваемое сообщение.
Пример правила, реализующего метод match
:
class DeprecatedVariableRule(AnsibleLintRule):
"""Deprecated variable declarations."""
id = 'DEPRECATED_VAR'
description = 'Check for deprecated variable syntax ${var}'
tags = ['deprecations']
def match(self, line: str) -> Union[bool, str]:
return '${' in line
Метод matchtask
обрабатывает каждую задачу или обработчик (handler).
Все задачи стандартизируются, чтобы включать ключи module
и module_arguments
.
Если в задаче присутствуют модификаторы when
, with_items
, tags
и другие, они также доступны для проверки.
Пример правила, реализующего метод matchtask
:
from ansiblelint.rules import AnsibleLintRule
from typing import Union
class TaskHasTag(AnsibleLintRule):
"""Ensure every task has a tag for better organization."""
id = 'TASK_TAG'
description = 'Tasks must have a tag to improve organization and filtering'
tags = ['department', 'team']
def matchtask(self, task, file=None) -> Union[bool, str]:
if 'tags' not in task:
return "Task missing a tag"
return False
Примечание
Для создания более сложных правил рекомендуется изучить методы и свойства класса AnsibleLintRule
и его родительских классов.
Пример#
Для изучения Ansible Lint на практике, сделайте клон репозитория, содержащего примеры сценариев:
git clone https://github.com/ansible/ansible-lint.git
Проверка сценария#
Для проверки сценария example.yml
выполните команду:
ansible-lint --offline -p ansible-lint/examples/playbooks/example.yml
Пример вывода:
Пример создания правила#
Чтобы создать правила на основе методов match
и matchtask
и проверить с помощью этих правил сценарий example.com
, выполните следующие действия:
Создайте каталог для правил и перейдите в него, например:
mkdir my_custom_rules && cd my_custom_rules
Создайте файл
TaskHasTag.py
, содержащий правило для проверки наличия тега:from __future__ import annotations from typing import TYPE_CHECKING, Union from ansiblelint.rules import AnsibleLintRule if TYPE_CHECKING: from ansiblelint.file_utils import Lintable from ansiblelint.utils import Task class TaskHasTag(AnsibleLintRule): """Tasks must have tag.""" id = 'EXAMPLE001' description = 'Tasks must have tag' tags = ['custom', 'core'] def matchtask(self, task: Task, file: Lintable | None = None ) -> Union[bool, str]: # Эта проверка исключает задачи include и fail из требований наличия тегов, # так как для них теги не обязательны: # Если задача включает другие задачи (include) или намеренно завершает выполнение (fail), # она исключается из проверки на наличие тегов, возвращая False. if not set(task.keys()).isdisjoint(['include', 'fail']): return False if not task.get("tags"): return True return False
Создайте файл
TestRule.py
, содержащий правило для проверки наличия определенного слова:from typing import Union from ansiblelint.rules import AnsibleLintRule class TestRule(AnsibleLintRule): """Deprecated variable declarations.""" id = 'EXAMPLE002' description = 'This rule triggers on tasks containing the word "task".' tags = ['custom', 'core'] def match(self, line: str) -> Union[bool, str]: # Срабатывает только для строк, содержащих "task" — для тестирования return 'task' in line
Запустите проверку сценария
example.com
:ansible-lint \ --offline \ -r my_custom_rules/ \ -t custom ~/ansible-lint/examples/playbooks/example.yml
Пример вывода: