NetStacksNetStacks

Template Basics

TeamsEnterprise

Introduction to configuration templates in NetStacks -- what they are, how to create one, and when to use them for network config management.

Overview

Configuration templates are the foundation of NetStacks' config management workflow. A template is a Jinja2-based document that defines device configuration as reusable, parameterized code. Instead of manually typing the same interface descriptions, SNMP communities, and NTP servers across hundreds of switches, you write the configuration once with variable placeholders and let NetStacks fill in device-specific values at deployment time.

Templates solve several problems that network engineers face daily:

  • Consistency — Every device gets the same baseline configuration structure, eliminating drift caused by manual edits
  • Speed — Deploy standardized configs to dozens or hundreds of devices in a single operation instead of one at a time
  • Auditability — Every template change is versioned, so you can see who changed what and when
  • Safety — Preview rendered output and diff it against the running config before pushing anything to production

Templates are part of the Stacks plugin. A template on its own defines configuration logic. When you attach templates to a Stack, you get a complete deployment workflow with target devices, variable values, and deployment history.

How It Works

The template lifecycle follows a straightforward path from authoring to deployment:

  1. Author — Write configuration using Jinja2 syntax with{{ variable }} placeholders for device-specific values
  2. Extract — NetStacks automatically parses your template source and discovers all variable names from {{ }} expressions
  3. Version — Every save creates a new version. The template tracks a current_version number and stores the full history of previous versions
  4. Render — Combine the template with variable values to produce final device configuration. Preview output before deployment
  5. Deploy — Push rendered configuration to target devices through a Stack instance, with rollback support if something goes wrong

Templates are stored as JinjaTemplate objects with a name, description, the raw template source, a list of extracted variable names, and version metadata. The Jinja2 rendering engine runs in a sandboxed environment — templates cannot access the file system, make network calls, or import arbitrary code. This makes it safe to run templates authored by any team member.

Sandboxed Execution

Template rendering is sandboxed for security. Templates can use built-in Jinja2 filters and control structures but cannot execute arbitrary code, read files, or make network requests.

Step-by-Step Guide

Follow these steps to create your first configuration template.

Step 1: Navigate to the Templates Section

In the NetStacks Terminal, open the Stacks plugin from the sidebar and select the Templates tab. This shows all templates in your organization.

Step 2: Create a New Template

Click New Template. Enter a descriptive name and an optional description. Use a naming convention that identifies the configuration type and target platform, such as snmp-config-ios or bgp-neighbor-nxos.

Naming Convention

Use a consistent naming pattern like <purpose>-<platform>. Examples: snmp-config-ios, vlan-setup-nxos, ospf-area-junos. This makes templates easy to find and filter.

Step 3: Write the Template Content

Use Jinja2 syntax to write your configuration. Place variable placeholders where device-specific values belong:

example-snippet.j2jinja2
hostname {{ hostname }}
!
snmp-server community {{ snmp_community }} RO
snmp-server location {{ location }}
snmp-server contact {{ contact }}

Step 4: Review Extracted Variables

After entering your template content, NetStacks automatically extracts variable names from {{ }} expressions. You will see the list of discovered variables — in this case: hostname, snmp_community, location, and contact.

Step 5: Save the Template

Click Save. NetStacks creates the template at version 1. Every subsequent edit will increment the version number, and you can always view or restore previous versions.

Step 6: Test with Preview

Before deploying, use the render/preview feature to see the final output with sample variable values. This confirms your template produces valid configuration.

Code Examples

SNMP Configuration Template

A basic SNMP template for Cisco IOS devices with community strings, location, contact, and trap host configuration:

snmp-config-ios.j2jinja2
{# SNMP Configuration - Cisco IOS #}
{# Variables: snmp_community, snmp_rw_community, location, contact, trap_hosts #}

snmp-server community {{ snmp_community }} RO
{% if snmp_rw_community is defined and snmp_rw_community %}
snmp-server community {{ snmp_rw_community }} RW
{% endif %}
snmp-server location {{ location | default('DC1 Row-A Rack-12') }}
snmp-server contact {{ contact | default('noc@example.com') }}
snmp-server enable traps
{% for host in trap_hosts %}
snmp-server host {{ host }} version 2c {{ snmp_community }}
{% endfor %}

Interface Configuration Template

A Layer 3 interface template with IP addressing, description, and optional HSRP:

interface-l3-ios.j2jinja2
{# Layer 3 Interface Configuration - Cisco IOS #}
{# Variables: interface_name, ip_address, subnet_mask, description, hsrp_enabled, hsrp_vip, hsrp_priority #}

interface {{ interface_name }}
 description {{ description }}
 ip address {{ ip_address }} {{ subnet_mask }}
 no ip proxy-arp
{% if hsrp_enabled | default(false) %}
 standby 1 ip {{ hsrp_vip }}
 standby 1 priority {{ hsrp_priority | default(100) }}
 standby 1 preempt
{% endif %}
 no shutdown

NTP Server Configuration Template

An NTP configuration template that supports multiple NTP servers with a preferred server and source interface:

ntp-config-ios.j2jinja2
{# NTP Configuration - Cisco IOS #}
{# Variables: ntp_servers, source_interface #}

{% for server in ntp_servers %}
ntp server {{ server }}{% if loop.first %} prefer{% endif %}

{% endfor %}
ntp source {{ source_interface | default('Loopback0') }}
ntp authenticate
ntp trusted-key 1
ntp authentication-key 1 md5 {{ ntp_auth_key | default('NtpSecure!') }}

Questions & Answers

Q: What are configuration templates in NetStacks?
A: Templates are Jinja2-based documents that define device configuration as reusable, parameterized code. You write the configuration structure once with variable placeholders like {{ hostname }} and {{ ip_address }}, then render the template with device-specific values to produce final configuration output. Templates are stored, versioned, and managed through the Stacks plugin.
Q: What templating language does NetStacks use?
A: NetStacks uses Jinja2, a widely adopted templating language from the Python ecosystem. Jinja2 provides variable substitution ({{ }}), control structures like conditionals ({% if %}) and loops ({% for %}), filters for transforming output, and macros for reusable blocks. If you have used Ansible templates, the syntax is identical.
Q: How are variables defined in a template?
A: You do not need to declare variables separately. Simply use {{ variable_name }} anywhere in your template source. When you save the template, NetStacks automatically parses the Jinja2 expressions and extracts a list of all variable names. These appear in the variables array on the template object.
Q: Can I use the same template for different device types?
A: Yes. You can use Jinja2 conditionals to branch on a device type variable. For example, {% if platform == 'cisco_ios' %} produces IOS-style commands while {% elif platform == 'juniper_junos' %} produces JunOS set commands. Alternatively, create separate templates per platform and attach the appropriate one to each stack.
Q: Are templates versioned automatically?
A: Yes. Every time you save changes to a template, NetStacks creates a new version with an incremented version number. The template stores the current version number and you can retrieve the full version history to compare changes, view diffs, or roll back to a previous version.
Q: What happens if I reference a variable that has no value at render time?
A: Jinja2 will raise an undefined variable error by default. You can guard against this by using the default filter: {{ contact | default('noc@example.com') }}. For optional blocks, wrap them in {% if variable is defined %} conditionals.

Troubleshooting

Template syntax errors on save

If the template fails to save, check for unclosed Jinja2 tags. Every {% if %} needs a matching {% endif %}, and every {% for %} needs a matching {% endfor %}. Use the validation endpoint to get detailed error messages with line numbers:

validate-error.jsonjson
POST /plugins/stacks/admin/templates/validate
Content-Type: application/json

{
  "template_source": "{% if enable_snmp %}\nsnmp-server community {{ community }} RO"
}

# Response (error):
{
  "valid": false,
  "error": "Unexpected end of template. Expected 'endif' at line 2."
}

Variables not being extracted

If your variables do not appear in the extracted list, verify that you are using double curly braces: {{ variable_name }}. Single braces like { variable_name } are not Jinja2 syntax. Also check that variable names use only letters, numbers, and underscores — names like {{ my-variable }} with hyphens are not valid Python identifiers.

Template will not save — required fields missing

Every template requires a name and template_source. The description field is optional. If the save button is disabled, check that you have entered a template name and that the template content is not empty.

Rendered output looks incorrect

Use the preview feature to render your template with test values. If the output has extra blank lines, use Jinja2 whitespace control: {%- if ... -%} strips whitespace around the tag. See the Jinja2 Syntax page for details.

Continue learning about the template workflow with these related pages:

  • Jinja2 Syntax — Full reference for filters, conditionals, loops, macros, and template inheritance
  • Variables & Extraction — How variables are discovered, typed, and populated from multiple sources
  • Template Versioning — View version history, compare diffs, and roll back changes
  • Rendering & Preview — Preview rendered output and validate syntax before deployment
  • Example Templates — Real-world templates for VLAN, ACL, BGP, OSPF, and interface configs
  • Stack Templates — Combine templates into deployment stacks with target devices and variables