Coding style guides are becoming fairly common in larger organizations. (As examples at the deepest end of the pool, Google publishes guides for Python, Java, C++ and other languages.) Some coding style guides are more ambitious than others. Some are probably more reality-bound than others. We can debate the merits of enforcing code styles in modern software development, but we can’t really debate the reality of having code styles in modern software development shops.
Ansible isn’t exactly a language like Python is a language. But like Python, the infrastructure codebase you end up writing with Ansible is going to be built and maintained by multiple people and even teams in your organization over time. Which means that readability (which is what style ultimately means in this context) matters.
Enter ansible-lint. The Ansible by Red Hat project currently maintains ansible-lint as a way to communicate its summary view of global default best practices and “syntactic sugar” to the wider community. If you aren’t already incorporating linting as part of your standard infrastructure code release pre-checks, no judgment! But the Level Up team does recommend it for Ansible, primarily because it has saved us time and trouble on so many occasions.
Granted, your team may not always end up agreeing with ansible-lint’s default worldview. Which is totally fine. There are both runtime (the -x flag) and config file options available to exclude rules either by the rule ID or any matching tag. If and when you encounter false-positives, or have other reasons to want to reduce warning “noise” in your linting efforts, you can simply share your ansible-lint config files somewhere like GitHub that the rest of your team can consume as well.
With that said, ansible-lint becomes super-charged when you combine its default rules with custom rules created by you and your team.
As a simplified example, let’s say that your team has decided that the disabling of gathering facts should never be overridden in your playbooks. Because gathering facts tends to be time-inefficient at any real scale, you are probably running a base role which always disables it via “gather_facts: False” in one of its playbooks. But if a new person on your team doesn’t happen to know why this is your policy and wants to gather facts for some purpose in a new playbook anyway, generally speaking, all she really has to do is add a “gather_facts: True” line with the right precedence ordering and her playbook will begin impacting the run times of her playbook AND anything else that ever includes her playbook in the future. So in this case, a way to flag the policy for her and anyone doing peer code review is to create a match rule like so (for this example, the file should be named “GatherFactsRule.py”):
from ansiblelint import AnsibleLintRule class GatherFactsRule(AnsibleLintRule): id = 'ANSIBLE1313' shortdesc = 'DevOps team rule: gather_facts should never be set to True' description = 'Check if gather_facts: True' tags = { 'resources' } def match(self, file, line): return 'gather_facts: True' in line
Next we can set up a quick test of ansible-lint’s matching powers by introducing the gather_facts line into any playbook:
--- - name: iterator demo hosts: all gather_facts: True tasks: - command: echo {{ item }} with_items: [ 0, 1, 1, 2, 3, 5, 8, 13, 21, 34 ] when: item > 7
Finally you can verify your new custom rule on the command line:
$ ansible-lint -r/path/to/custom_rules /path/to/test_playbook.yml [ANSIBLE1313] DevOps team rule: gather_facts should never be set to True /path/to/test_playbook.yml:8 gather_facts: True $
So to summarize, using a comprehensive and extensible source code analyzer like ansible-lint, in a matter of a few minutes you can go from relying on external docs or similar “institutional knowledge” about “how we do things around here” with predictably unpredictable results, to creating a foundation for a repeatable, self-documenting and obvious way to start capturing and expressing your team’s infrastructure code standards as code itself.