This page lists guidelines for developing Python code or Jinja2 templates in the AVD context. These rules apply to creating or updating any Python or Jinja2 file available in a aristanetworks/avd
repository.
As AVD is an Ansible collection, we're required to follow guidelines from the official Ansible documentation for all Python code.
Furthermore, the CI Pipeline (& pre-commit) for AVD enforces the following:
- Maximum line length of 160
- Black version 23.12.1
- isort version 5.13.2
- Flake-8 version 4.0.1
- pylint version 2.6.0
Configurations for the above tools can be found in:
-
Description
A single space shall be added between Jinja2 curly brackets and a variable's name.
-
Example
{{ ethernet_interface }}
-
Description
When variables are used in combination with a filter,
|
shall be enclosed by space. -
Example
{{ my_value | to_json }}
-
Description
The nested jinja code block shall follow the following rules:
- All J2 statements must be enclosed by one space
- All J2 statements must be indented by four more spaces within the jinja delimiter
- To close a control, the end tag must have the same indentation level as the opening tag
- Indentation must be four spaces and NOT tabulation
-
Example
{# Initial block indentation #} {% if my_variable is arista.avd.defined %} {# Nested block indentation #} {% for ethernet_interface in ethernet_interfaces %} {% if ethernet_interface.name is arista.avd.defined %} {% set result = ethernet_interface.name %} {# ..... output truncated ..... #} {% endif %} {% endfor %}
-
Description
Instead of doing a for loop on a single line, the
join
filter should be leveraged as much as possible. -
Example
{{ ciphers | join(", ") }}
-
Description
To test if a variable is part of a list, the
in
operator should be used as much as possible to avoid longif/elif/else
block. -
Example
{% if underlay_routing_protocol is arista.avd.defined and underlay_routing_protocol in ['isis', 'ospf'] %}
-
Description
When a long CLI with multiple options must be built, use pure J2 logic and print.
-
Example
{% for ip_helper in vlan_interfaces[vlan_interface].ip_helpers | arista.avd.natural_sort %} {% set ip_helper_cli = "ip helper-address " ~ ip_helper %} {% if vlan_interfaces[vlan_interface].ip_helpers[ip_helper].vrf is arista.avd.defined %} {% set ip_helper_cli = ip_helper_cli ~ " vrf " ~ vlan_interfaces[vlan_interface].ip_helpers[ip_helper].vrf %} {% endif %} {% if vlan_interfaces[vlan_interface].ip_helpers[ip_helper].source_interface is arista.avd.defined %} {% set ip_helper_cli = ip_helper_cli ~ " source-interface " ~ vlan_interfaces[vlan_interface].ip_helpers[ip_helper].source_interface %} {% endif %} {{ ip_helper_cli }} {% endfor %}
-
Description
All variables shall use lowercase.
-
Example
{{ variable }}
-
Description
An underscore
_
should be used as a separator for a multi-word variable. -
Example
{{ my_variable_name }}
-
Description
For an iterable variable, the plural form shall be used.
-
Example
{{ ethernet_interfaces }}
-
Description
For variables in a for loop, the singular form shall be used.
-
Example
{{ ethernet_interfaces[ethernet_interface] }}
-
Description
Tilde
~
should be used for string concatenation as it automatically converts variables to a string. -
Example
{% set ip_helper_cli = ip_helper_cli ~ " source-interface " ~ vlan_interfaces[vlan_interface].ip_helpers[ip_helper].source_interface %}
-
Description
To test the type of a variable, it's recommended to use
is
/is not
keywords. -
Example
{# Test if variable is string #} {% if ethernet_interface is string %} {# Test if variable is not a string #} {% if ethernet_interface is not string %}
-
Description
To test the content of a variable, it's recommended to use
==
/!=
keywords. -
Example
{# Test if variable is equal to 'Ethernet1' #} {% if ethernet_interface == 'Ethernet1' %} {# Test if variable is not equal to 'Ethernet1' #} {% if ethernet_interface != 'Ethernet1' %}
!!! info PLUGIN-2 can do a test if the variable is defined and has a specific value
-
Description
All strings should be compared based on lowercase format.
-
Example
{% if underlay_routing_protocol is arista.avd.defined and underlay_routing_protocol | lower in ['isis', 'ospf'] %}
See the menu on the left for Ansible Collection Plugins.
-
Description
All tests to check if a variable is defined shall be done with
arista.avd.defined
. This test also does a deep test and doesn't require a test at an upper level. -
Example
{# Simple test #} {% if ethernet_interfaces is arista.avd.defined %} {# Deep test #} {% if router_bgp.vrfs[vrf].rd is arista.avd.defined %}
-
Description
The test
arista.avd.defined
shall be used to test if a variable is defined and has a specific value. -
Example
{% if vlan.name is arista.avd.defined('test') %}
-
Description
If a default value must be used, the
arista.avd.default
plugin shall be used instead of anif/else
block. The plugin can be used to fallback to different values until one of them is defined and valid. -
Example
{# Simple default test with one default value #} {{ vlan.name | arista.avd.default('test_vlan') }} {# Default test with a list of default options #} {{ vlan.name | arista.avd.default(default.vlan.name, 'test_vlan') }}