Docs
Concepts

Variables

How a design takes input, passes values to the designs it uses, and computes values.

Variables make one design build many things. The compute rack builds any rack in any site, because the rack's name and its site are variables.

Declaring them

A design declares its variables at the top:

variables:
  rack_name: {type: netbox_new, model: Rack, field: name, description: "The rack's name, such as R1"}
  site_slug: {type: netbox_ref, model: Site, description: "The site the rack stands in, by its slug"}
  status: active
ValueMeans
A mapping with a typeA typed input. You give it when you plan, in the form its type asks for, and it is checked before anything plans: a number, a prefix, one of a list of choices, a value a NetBox field takes, a new object's name or slug, an object your NetBox has. See Typed variables
$USERText you must give when you plan, checked by nothing until a field uses it
$USER_OPTIONALText you may give. Left out, every field that uses it is left out
A value, such as activeA default. The deploy page doesn't ask for it
An expression, such as '{{ variables.site_name | slugify }}'Computed from other variables

Using them

Anywhere a value can go, an expression in {{ }} can too:

  • {{ variables.rack_name }} is a variable's value. The rack is named '{{ variables.rack_name }}', and its switch '{{ variables.rack_name }}-TOR-01'.
  • {{ parent }} is the object that contains this one, and {{ parent.site }} a field of it.
  • {{ loop.i }} is the current pass of an nbd_loop, so the servers are numbered '{{ variables.rack_name }}-COMPUTE-{{ loop.i | zeropad }}': R1-COMPUTE-01 to R1-COMPUTE-10.
  • Filters change a value: zeropad pads a number to two digits, and lower, upper and slugify change text.
  • Arithmetic works on numbers: each server's second data port connects to switch port {{ loop.i * 2 }}.

Passing them to the designs you use

A design included with nbd: has variables of its own. Its template_vars sets them:

- design: nbd:devices/Dell_R640_w_module
  template_vars:
    name: '{{ variables.rack_name }}-COMPUTE-{{ loop.i | zeropad }}'
    position: '{{ loop.i }}'
    site: '{{ parent.site }}'
    rack: '{{ parent }}'

Each value is worked out in the including design, where variables, parent and loop mean the rack's. The server design then sees them as its own variables.name, variables.position and so on. The server design declares serial as optional (required: false), and the rack doesn't pass one, so no server has a serial.

A variable can say what it is. Declared as spine_count: {type: int, min: 1, max: 32, default: 2}, or status: {type: netbox_field, model: Rack, field: status}, it is checked when you deploy, before anything plans: a word where a number goes, a status Rack doesn't take, an address that isn't one. The deploy page asks for each in the right form, and shows the description you give it. What a NetBox field takes comes from your NetBox's own data model, so a design never spells out a status list or a slug rule. Variables reference has the types.

Variables reference covers computed defaults, optional variables and the rules for passing values down.

On this page