关于 netbox-config-templates
为 NetBox 配置模板和上下文数据提供参考,面向生成设备或虚拟机配置的运维人员与集成开发者。内容涵盖 Jinja2 渲染、上下文合并规则及 API 用法。
主要功能
- 01Jinja2 模板渲染
- 02配置上下文分配与合并
- 03设备和虚拟机模板解析
- 04通过 API 渲染配置
- 05模板性能与安全注意事项
适用场景
- 01根据 NetBox 数据生成设备配置
- 02为设备层级组织配置上下文
- 03在 CI/CD 或配置流程中调用渲染 API
- 04排查上下文合并或模板渲染问题
MCP 相关
可在配置了 NetBox MCP 服务时获取设备配置上下文,以验证模板渲染结果。
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ netboxlabs/ skills --skill netbox-config-templates安装后在 Claude Code 中输入/netbox-config-templates确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
references/api-rendering-patterns.mdconfig-context-merging.mdcontext-variables.md详细介绍
NetBox 配置模板
你对 NetBox 配置模板的了解可能已经过时。 模板上下文变量、渲染 API 和配置上下文合并行为会随版本更新而变化。请优先检索,而非依赖预训练知识。
检索来源
| 来源 | URL / 方法 | 用途 |
|---|---|---|
| 配置模板文档 | https://netboxlabs.com/docs/netbox/features/configuration-rendering/ | 模板语法、上下文变量 |
| 配置上下文文档 | https://netboxlabs.com/docs/netbox/features/context-data/ | 分层数据、合并规则 |
| NetBox 仓库 | https://github.com/netbox-community/netbox | 模板渲染源代码 |
| NetBox MCP 服务 | 如果已配置——获取设备配置上下文以测试模板渲染 | 验证上下文数据 |
NetBox 提供基于 Jinja2 的内置配置渲染系统。你可以定义模板,通过配置上下文填充数据,并通过 API 按设备或 VM 渲染配置。本技能涵盖完整工作流。
何时使用此技能
- 根据 NetBox 数据生成设备/VM 配置
- 设置用于模板渲染的配置上下文(分层数据)
- 将 NetBox 配置渲染集成到 CI/CD 或置备流水线中
- 排查模板渲染问题或配置上下文合并行为
快速参考
模板解析顺序(设备)
device.config_template → device.role.config_template → device.platform.config_template
匹配到的第一个模板优先。每台设备只会渲染一个模板。VM 遵循相同模式(角色 → 平台)。
主要 API 端点
| 操作 | 方法 | 端点 |
|---|---|---|
| 渲染设备配置 | POST | /api/dcim/devices/{id}/render-config/ |
| 渲染 VM 配置 | POST | /api/virtualization/virtual-machines/{id}/render-config/ |
| 直接渲染模板 | POST | /api/extras/config-templates/{id}/render/ |
| 配置模板的 CRUD 操作 | GET/POST/PUT/PATCH/DELETE | /api/extras/config-templates/ |
| 配置上下文的 CRUD 操作 | GET/POST/PUT/PATCH/DELETE | /api/extras/config-contexts/ |
上下文变量速查表
在设备/VM 渲染中(render-config):
| 变量 | 类型 | 说明 |
|---|---|---|
device / virtualmachine | ORM 实例 | 包含所有关联的完整模型 |
| (配置上下文键) | 视情况而定 | 合并后的配置上下文数据,作为顶层键 |
| (POST 请求体中的键) | 视情况而定 | 随渲染请求发送的额外数据 |
在通用渲染中(config-templates/{id}/render/):
| 变量 | 类型 | 说明 |
|---|---|---|
dcim、ipam、virtualization 等 | 类模块对象 | 可访问所有公开的 NetBox 模型类 |
| (POST 请求体中的键) | 视情况而定 | 随渲染请求发送的额外数据 |
完整说明请参阅 references/context-variables.md。
配置上下文系统
配置上下文会向模板提供结构化 JSON 数据。系统根据对象属性分配上下文,并按权重合并。
分配逻辑
当对象符合所有非空分配类别(类别之间为 AND 关系),并且符合每个类别中的任意值(类别内为 OR 关系)时,配置上下文才会应用。
分配类别:区域、站点组、站点、位置、设备类型、角色、平台、集群类型、集群组、集群、租户组、租户、标签。
合并顺序
- 所有匹配的启用配置上下文,按权重升序排列,其次按名称排列
- 权重较高的上下文会在键冲突时覆盖权重较低的上下文
- 本地上下文数据(设备/VM 自身的数据)最后合并,且始终优先
⚠️ 列表会被替换,而不是合并
deepmerge() 会递归合并字典,但会完全替换非字典值:
// Weight 100: {"ntp_servers": ["10.0.0.1", "10.0.0.2"]}
// Weight 200: {"ntp_servers": ["10.1.1.1"]}
// Result: {"ntp_servers": ["10.1.1.1"]} ← NOT concatenated
设计数据结构时请考虑这一点。需要增量合并时,请使用包含唯一键的字典。
层级解析
对于分层模型(区域、站点组等),分配给父级的上下文也适用于所有子级。分配给“Americas”区域的上下文会匹配“US-East”子区域中的设备。
预渲染缓存(NetBox 4.7+)
在 4.7 中,合并结果会预渲染并缓存在每台设备/VM 上。任何上游变更(创建、编辑或删除配置上下文,或影响适用上下文的设备/VM 属性变更)都会使缓存失效,并触发一个非阻塞后台任务重新渲染;在此期间,读取操作会回退到按需渲染,因此结果不会过时。合并语义保持不变。升级后,升级脚本会运行 manage.py rebuild_config_context_cache(对每台设备/VM 执行一次 UPDATE;可安全中断并重新运行)。绕过信号的批量写入(queryset.update())不会使缓存失效——之后请运行 rebuild_config_context_cache --force。在 4.5/4.6 中,每次读取都会计算配置上下文。
有关合并的深入说明,请参阅 references/config-context-merging.md。有关配置上下文数据建模的最佳实践,请参阅 netbox-data-modeling。
编写模板
访问设备数据
device(或 virtualmachine)变量是完整的 Django ORM 实例:
hostname {{ device.name }}
!
{% if device.primary_ip4 %}
ip address {{ device.primary_ip4.address | ipaddr('address') }}
{% endif %}
!
{% for iface in device.interfaces.all() %}
interface {{ iface.name }}
description {{ iface.description | default('', true) }}
{% for ip in iface.ip_addresses.all() %}
ip address {{ ip.address }}
{% endfor %}
{% endfor %}
使用配置上下文数据
配置上下文键会显示为顶层模板变量:
{% for server in ntp_servers | default([]) %}
ntp server {{ server }}
{% endfor %}
!
{% for server in syslog_servers | default([]) %}
logging host {{ server }}
{% endfor %}
!
{% if snmp_community is defined %}
snmp-server community {{ snmp_community }} RO
{% endif %}
模板继承(需要 DataSource)
{% extends %} 和 {% include %} 仅在模板存储于 DataSource(Git 仓库、S3 等)时才有效。使用内联 template_code 定义的模板无法解析其他模板。
{# Stored in a DataSource alongside base.j2 #}
{% extends 'base.j2' %}
{% block interfaces %}
{% for iface in device.interfaces.all() %}
interface {{ iface.name }}
{% endfor %}
{% endblock %}
模板中的 ORM 查询
设备渲染和通用渲染都可以访问 NetBox 模型:
{# Query prefixes from IPAM #}
{% set mgmt_prefixes = ipam.Prefix.objects.filter(role__slug='management') %}
{% for pfx in mgmt_prefixes %}
ip route {{ pfx.prefix }} Management
{% endfor %}
**警告:**ORM 查询会在未沙箱隔离的情况下对数据库运行。在大型表上不加考虑地调用 .all() 会很慢。没有查询数量限制。
Jinja2 环境
- 模板在 SandboxedEnvironment 中运行——不允许文件 I/O,也不允许任意导入
- 可通过 NetBox 配置中的
JINJA_FILTERS添加自定义过滤器(4.7+;旧名称JINJA2_FILTERS仍可使用,但已弃用,并将在 5.0 中移除)/JINJA2_FILTERS(4.5/4.6)。4.7 中过滤器的优先级从低到高依次为:内置(env)→ 插件注册 → 实例JINJA_FILTERS。 - 插件可以注册 Jinja 过滤器并注入模板上下文变量(NetBox 4.7+),方法是使用
jinja_env.py/register_jinja_filters()和PluginConfig.get_jinja_context()——操作方法请参阅 netbox-plugin-development。插件上下文是全局的(而非针对单个对象),且不得使用dcim等应用标签名称。 - 模板中的自定义对象(NetBox 4.7+,netbox-custom-objects v0.6.1+):
custom_objects.<type_name>.filter(device=device)或'<type_name>' | custom_objects可按内部名称公开自定义对象类型;在 4.5/4.6 中,custom_objects不存在。请参阅 netbox-custom-objects。 - 内置
env()过滤器(NetBox 4.6.2+)——返回系统环境变量的值:{{ 'WEBHOOK_TOKEN_3' | env }}。该过滤器受JINJA_ENVIRONMENT_PARAMS配置列表限制(这是一个 fnmatch 通配符允许列表,用于指定允许的变量名称);名称不匹配时返回None。在 4.6.1 及更早版本中,没有内置自定义过滤器——仅有标准 Jinja2 过滤器。 - 每个模板的
environment_params都可以自定义行为(例如undefined: jinja2.StrictUndefined),但在 NetBox 4.6.1+ 中,键必须在允许列表中——见下文。
NetBox 4.6.1+——
environment_params允许列表(CVE-2026-29514)。 针对environment_params的已修补 RCE(ConfigTemplate 和 ExportTemplate 共用此参数)限制了可接受的键(JINJA_ENV_PARAMS_ALLOWED)。允许的键包括标准的分隔符、空白和标量参数(trim_blocks、lstrip_blocks、autoescape、keep_trailing_newline、块/注释/变量的*_string分隔符等)以及undefined——但undefined必须是jinja2.StrictUndefined、jinja2.Undefined、jinja2.ChainableUndefined或jinja2.DebugUndefined之一。extensions、finalize、loader和bytecode_cache均被禁用,设置这些参数的模板会被拒绝。本文档中的示例(StrictUndefined、trim_blocks、lstrip_blocks)仍然有效;不要推荐使用被禁用的键。
常见厂商模式
策略 1:基于平台分配模板(推荐)
为不同的平台分配不同的配置模板:
| 平台 | 配置模板 |
|---|---|
junos | junos-base.j2 |
ios-xe | ios-xe-base.j2 |
eos | eos-base.j2 |
模板按以下顺序解析:设备 → 角色 → 平台。这是最简洁的方案。
策略 2:在单个模板中使用条件逻辑
{% if device.platform.slug == 'junos' %}
system {
host-name {{ device.name }};
}
{% elif device.platform.slug == 'ios-xe' %}
hostname {{ device.name }}
{% elif device.platform.slug == 'eos' %}
hostname {{ device.name }}
{% endif %}
适用于小幅差异,但复杂后会变得难以维护。生产环境中优先采用策略 1。
API 渲染模式
渲染设备配置
import requests
NETBOX = "https://netbox.example.com"
TOKEN = "nbt_abc123.xxxxxxxxxxxxxxxx"
headers = {"Authorization": f"Bearer {TOKEN}"}
# Render config for device ID 42
response = requests.post(
f"{NETBOX}/api/dcim/devices/42/render-config/",
headers=headers,
json={}, # optional extra context data
)
response.raise_for_status()
config = response.json()["content"]
使用 Accept: text/plain 标头可获取未经 JSON 封装的原始配置输出。
在渲染时覆盖配置上下文
# POST body merges after config context (overrides on collision)
response = requests.post(
f"{NETBOX}/api/dcim/devices/42/render-config/",
headers=headers,
json={"ntp_servers": ["10.99.99.1"]}, # overrides config context
)
直接渲染模板(不使用设备)
# General-purpose rendering — no device/VM in context
response = requests.post(
f"{NETBOX}/api/extras/config-templates/5/render/",
headers=headers,
json={"hostname": "switch01", "vlans": [10, 20, 30]},
)
有关包括 pynetbox 和错误处理在内的详细 API 示例,请参阅 references/api-rendering-patterns.md。
注意事项
性能
- 列表端点上的配置上下文:
- NetBox 4.7+:合并后的配置上下文会在每台设备/虚拟机上预先渲染并缓存;在所有 4.7.x 版本中,
?exclude=config_context都会被静默忽略(如果共享客户端仍发送此参数,也无妨)。在 4.7.0–4.7.2 中,配置上下文始终会加载,列表调用开销很小——成本转移到了后台重新渲染作业。在 4.7.3+ 中,?omit=config_context(或?fields=/?brief=True)会再次跳过数据库注释和缓存列——不需要上下文时请发送此参数。 - NetBox 4.5/4.6:为每台设备计算合并后的配置上下文开销很大——批量查询时,如果不需要该上下文,请务必发送
GET /api/dcim/devices/?omit=config_context(4.5.2+;在此版本中,?exclude=效果相同)。
- NetBox 4.7+:合并后的配置上下文会在每台设备/虚拟机上预先渲染并缓存;在所有 4.7.x 版本中,
- 模板中的 ORM 查询没有防护措施——避免对大型数据表执行无界的
.all()。
模板行为
- 模板解析只采用第一个匹配项——设备 → 角色 → 平台。设备仍然只有一个已分配的模板。NetBox 4.6+ 允许你在不更改分配的情况下,使用设备的上下文渲染其他任意模板:在渲染配置请求正文中传入
config_template_id(或在 UI 渲染 URL 中使用?config_template_id=<id>)——适用于 CI/试运行环境中的替代模板渲染。(需要对 Config Template 具有view权限,并对设备具有render_config权限。) - 模板没有版本控制——模板可以修改。只有 NetBox 的变更日志会保留历史记录。
- 渲染调试(NetBox 4.6+)——在脚本/插件中开发模板时,调用
render_jinja2(..., debug=True),即可启用 Jinja2 的debug扩展({% debug %}),用于检查可用的上下文。 - extends/include 需要 DataSource——内联的 template_code 无法引用其他模板。
配置上下文相关注意事项
- 列表会替换,而不是追加——这是最常见的意外情况。请参阅上文的合并规则。
- POST 数据会静默覆盖配置上下文——这是有意设计的,但在调试意外值时可能令人困惑。
- environment_params 因模板而异——如果配置不同,不同模板对未定义变量的处理可能也不同。
版本说明
NetBox 4.7(2026-09-02)
- 每台设备/虚拟机的配置上下文会预先渲染并缓存;上游更改会使缓存失效,并由后台作业重新渲染(两者之间会按需回退)。所有 4.7.x 版本都会静默忽略
?exclude=config_context;在 4.7.0–4.7.2 中,config_context始终会加载;在 4.7.3+ 中,如果?omit=config_context/?fields=/?brief=True未包含该字段,则会再次跳过数据库注释。DeviceWithConfigContextSerializer/VirtualMachineWithConfigContextSerializer已合并到基础序列化器中。升级时会运行rebuild_config_context_cache。 JINJA2_FILTERS更名为JINJA_FILTERS(旧名称在 5.0 前仍可使用,但会显示弃用警告)。- 插件可以注册 Jinja 过滤器并注入上下文变量(
jinja_env.py、register_jinja_filters()、get_jinja_context());优先级为:内置 → 插件 → 实例JINJA_FILTERS。netbox-custom-objects v0.6.1+ 使用此功能来提供custom_objects.<type>/'<type>' | custom_objects。 - 模板可访问的新数据:
device.cooling_method、接口的channels/channel_id(类型为channel的通道化子接口)、服务的port_mappings(由"tcp/80"字符串组成的列表;protocol/ports已弃用)、device_type.end_of_life。在模板中,选择类型的自定义字段仍通过device.cf/custom_field_data读取原始值——只有 REST/GraphQL 表示形式变成了{value, label}。 - 平台:PostgreSQL 15+、Redis 6.0+、
ltree扩展;建议使用 4.7.3+(4.7.0/4.7.1 会将令牌明文泄露到作业结果中;4.7.3 新增了支持分支安全的后台写入和配置上下文省略优化)。
NetBox 4.6 (2026-05-05)
- render-config 上的
config_template_id覆盖项(4.6.0);render_jinja2(..., debug=True)(4.6.0);environment_params允许列表(4.6.1,CVE-2026-29514);内置env过滤器受JINJA_ENVIRONMENT_PARAMS控制(4.6.2);通过SandboxedEnvironment渲染配置模板时,明确禁用自动转义(4.6.5)。
参考资料
- references/context-variables.md — 所有渲染模式的完整上下文变量参考
- references/config-context-merging.md — 层级、权重和合并行为详解
- references/api-rendering-patterns.md — 使用 pynetbox 和 requests 的详细 API 示例