Categories
Cisco Dev SDA

Cisco Catalyst Center Jinja Templating: Part 1

Manually configuring hundreds of network devices creates unnecessary friction, even when the differences between configs are minimal. Jinja templating in Catalyst Center lets you parameterise device configurations, so you write a template once and provision devices at scale by feeding in different variable values. This approach eliminates copy-paste errors and makes configuration management auditable and repeatable.

What is Catalyst Center templating?

Catalyst Center offers two templating interfaces: the newer Template Hub (available in v2.3.5 and later) and the older Template Editor. Both let you write network device configurations as templates with variables and logic. The interface provides syntax highlighting, integrated validation, and a version control system that works a bit like a simplified Git — you stage changes, then commit them as numbered versions.

The simulator is the feature I’d point anyone to first. It renders your template output using values you provide, against any device in your inventory, without touching production. You can catch logic errors and whitespace issues immediately rather than discovering them mid-deployment. It cannot validate whether the rendered config will actually work on the target device, but for catching template mistakes it’s invaluable.

Jinja2 fundamentals

Jinja uses three types of delimiters. Expression delimiters {{ }} output variable values or expressions. Statement delimiters {% %} execute logic like loops and conditionals. Comment delimiters {# #} let you add notes that don’t render in the output.

Here’s a simple example:

{# Set the management interface details #}
hostname {{ device_name }}
!
interface {{ interface_name }}
 description {{ description }}
 ip address {{ ip_address }} {{ netmask }}
 no shutdown

If device_name is SITE-A-CORE-01, interface_name is GigabitEthernet0/0/0, and ip_address is 10.1.1.1, this produces:

hostname SITE-A-CORE-01
!
interface GigabitEthernet0/0/0
 description WAN Link to HQ
 ip address 10.1.1.1 255.255.255.0
 no shutdown

The comment line disappears entirely from the output. That’s worth knowing early, because comments also cause blank lines — which matters when your output needs to be clean IOS config. You can suppress the blank line by adding a dash after the opening statement tag: {%-.

Data types in Jinja

Jinja supports the same basic data types as Python: strings (text in quotes), integers (whole numbers), booleans (true/false in lowercase), lists (ordered collections), and dictionaries (key-value pairs).

Lists are useful when you need to iterate over items:

{% for vlan_id in vlan_list %}
vlan {{ vlan_id }}
{% endfor %}

Dictionaries are the networking power tool. Think of them like a VLAN database: instead of knowing an arbitrary index number, you look up a value by a meaningful key name. DNS is a useful analogy here — it’s easier to recall management than to remember that VLAN 10 is index 3 in a list.

{% set vlan_db = {
  "10": "Management VLAN",
  "20": "Voice VLAN",
  "30": "Guest VLAN",
  "999": "Blackhole VLAN"
} %}

You retrieve a value with vlan_db["10"] (subscript notation) or vlan_db.10. Dictionaries are also easy to extend: the update() method merges in new key-value pairs without rebuilding the whole structure.

A practical example: VLAN provisioning

Here’s a template that accepts a comma-separated list of VLAN IDs from the user, looks each one up in a dictionary, and generates the correct vlan name command — using a predefined name from the database if one exists, or generating a generic name if it doesn’t.

{% set vlan_db = {
  "10": "Management VLAN",
  "20": "Voice VLAN",
  "123": "Guest VLAN",
  "777": "POS VLAN",
  "999": "Blackhole VLAN"
} %}

{%- set create_vlan_list = create_vlan_list | split(",") %}
{% for vlan in create_vlan_list %}
{% set vlan_str = vlan | string %}
vlan {{ vlan }}
{% if vlan_db[vlan_str] is defined %}
 name {{ vlan_db[vlan_str] }}
{% else %}
 name VLAN_{{ vlan }}
{% endif %}
{% endfor %}

With user input create_vlan_list: 10,50,999, the output is:

vlan 10
 name Management VLAN
vlan 50
 name VLAN_50
vlan 999
 name Blackhole VLAN

A few things worth noting: the split(",") filter converts the user’s comma-separated string into a list Jinja can loop over. The is defined test checks whether a key exists in the dictionary before trying to use it — without this, referencing a missing key would cause an error. The | string filter converts each integer VLAN ID to a string so it matches the string keys in the dictionary.

Catalyst Center special keywords

In addition to standard Jinja syntax, Catalyst Center adds a set of proprietary keywords for situations that the templating engine needs to handle specially.

#MODE_ENABLE and #MODE_END_ENABLE wrap any commands that must run in privileged EXEC mode rather than the default global configuration mode:

#MODE_ENABLE
show running-config
#MODE_END_ENABLE

#INTERACTIVE and #ENDS_INTERACTIVE handle IOS commands that prompt for confirmation. The <IQ> tag follows the command on the same line and contains a search string from the expected prompt; <R> follows immediately with the response to send:

#INTERACTIVE
no crypto pki trustpoint DNAC-CA<IQ>yes/no<R>yes
#ENDS_INTERACTIVE

Without this, the template execution would hang waiting for an interactive response that never arrives. In practice, you’ll encounter this with any command that asks “yes/no” or “confirm”.

The compliance ignore tags suppress false-positive alerts from the Catalyst Center compliance engine. Some commands — particularly those using the no keyword or commands where IOS rewrites the config line after applying it (like hashed passwords) — can trigger alerts even when the configuration is correct:

! @start_ignore_compliance
no interface Loopback0
! @end_ignore_compliance

Use these sparingly and document why you’ve added them, otherwise your compliance reports lose meaning over time.


That covers the fundamentals: the template interface, Jinja delimiters, data types, and the special keywords you need to know before writing anything production-facing. Part 2 picks up with conditionals, more advanced filters, and for loop techniques for generating complex configs from structured data. In the meantime, use the simulator liberally — it’s the fastest way to build intuition for how Jinja renders output, and it costs nothing to break things there.

Leave a Reply

Your email address will not be published. Required fields are marked *