NetStacksNetStacks

Variables

Enterprise

How NetStacks detects template variables, how values are typed (strings, numbers, lists), and where values come from when you deploy.

Overview

A variable is any name a template reads but does not define itself, for example vlan_id in switchport access vlan {{ vlan_id }}. You do not declare variables anywhere: NetStacks reads them out of the template source. You supply values when you preview the template and when you deploy it through a stack.

Automatic Detection

When you save a template, the Controller parses the source and records every undeclared variable. They appear as chips under Template Source and as fields under Test Variables.

Variables chips under the template source: logging_buffer, logging_level, ntp_servers (list), site, syslog_server
  • Names you create inside the template (loop variables such as server in {% for server in ntp_servers %}, or {% set %} names) are not variables. Only ntp_servers is.
  • For an object such as {{ uplink.name }}, only the top-level name (uplink) is listed.
  • Every detected variable is marked required (the * on the chip).

NetStacks also guesses a type for each variable, shown as a small tag:

TagWhen it is used
listThe variable is looped over: {% for x in VARIABLE %}
numberThe variable appears unquoted after a colon, as in a JSON template: "mtu": {{ mtu }}
(no tag)Everything else is treated as a string.
Save to refresh the variable list

On the edit page, Test Variables lists the variables from the last saved version. After you add a new {{ variable }} to the source, click Save to get a field for it.

Entering Values and Types

Every value field (in Test Variables, and in an instance's Shared Variables and Per-Device Variables) is a text box. Before rendering, NetStacks converts text that looks like another type:

You typeThe template receives
["10.90.0.5", "10.90.0.4"]A list of two strings
{"name": "Gi1/0/1", "vlan": 10}An object with name and vlan
true / falseA boolean
120, 1.5A number
Anything elseThe text as a string

Lists and Objects

Enter list and object values as valid JSON, with double quotes around strings. A comma-separated value such as 10.90.0.5,10.90.0.4 stays a single string, and a for loop over a string walks through it one character at a time.

{# allowed_pollers = ["10.90.0.6", "10.90.0.7"] #}
{% for poller in allowed_pollers %}
access-list 60 permit host {{ poller }}
{% endfor %}
Check list values before you deploy

Before you deploy, check that every list variable in an instance still holds a JSON array (square brackets and quotes), and use Render Preview to confirm the loop output looks right.

Numbers and Booleans

Conversion happens for every value, whatever the variable's type tag. Two consequences to keep in mind:

  • Values made only of digits lose leading zeros. 0100 becomes 100. A decimal such as 1.10 becomes 1.1.
  • The text false becomes a boolean, so {% if enabled %} behaves as you would expect.

If a value must keep its exact text (for example an identifier with leading zeros), add a non-numeric character in the template instead, such as a prefix written in the source (ID-{{ site_number }}), or format it with the format filter: {{ "%04d" | format(site_number) }}.

Where Values Come From at Deploy Time

Test values typed in the template editor are only for previewing; they are not saved. Real values are set on a stack and its instances:

  1. Scope (on the stack). In the stack editor's Detected Variables card, each variable is marked Shared or Per Device.
  2. Shared Variables (on the instance). One value used for every device the service targets, for example ntp_servers.
  3. Per-Device Variables (on the instance). A value for each device, for example interface and port_description.
  4. Resolve from API. A stack variable can be configured to fetch its value from an API Resource such as NetBox. Click Resolve from API in the instance to fill it in.

When the same variable has more than one value, a per-device value wins over a shared value, which wins over any default stored on the stack's service. Details and screenshots are in Shared & Per-Device Variables.

Device Data

Templates do not get device facts automatically. There is no built-in device or hostname variable at render time. To use device-specific data:

  • Make the variable Per Device and enter the value per device, or
  • Use Configure API on the stack variable. The API Path can include device fields, for example /api/dcim/devices/?name={{ device.name }}. The fields available there are device.name, device.host (also device.hostname), device.site, device.platform, device.manufacturer, device.model, device.device_type, device.serial_number, device.asset_tag, and device.id.

Tips

  • Use descriptive, lowercase names with underscores (syslog_server, not s1). The name is the only label people see in the instance form.
  • Variables with the same name in different templates of one stack share one scope setting. Use that on purpose (one site for every service) or pick distinct names.
  • Give optional values a fallback with default: {{ logging_level | default("informational") }}.