NetBox (Export Template)
This guide shows how to use NetBox Export Templates with the HTTP provider to discover and sync targets.
Export Templates offer powerful filtering, transformation, and formatting directly in NetBox, reducing load on the operator and enabling complex discovery logic.
Overview
An Export Template is a Jinja2 template defined in NetBox that:
- Queries NetBox’s internal database (devices, interfaces, etc.)
- Filters results based on custom criteria
- Transforms data into your desired output format (JSON, YAML, CSV, etc.)
- Returns the formatted output via a custom REST API endpoint
When used with gNMIc’s HTTP provider, the operator simply fetches the rendered template and parses the result — no additional transformation needed.
Prerequisites
- A running Kubernetes cluster with gNMIc Operator installed
- A reachable NetBox instance with permissions to create Export Templates
- A NetBox API token
kubectlaccess to your cluster- Familiarity with Jinja2 templates
Step 1: Create a NetBox API Token
Step 1a: Create the API Token in NetBox
Create a dedicated API token in NetBox for gNMIc Operator access.
- Log in to NetBox.
- Go to Admin > API Tokens.
- Click Add or Add token.
- Enter a descriptive name such as
gNMIc Operator. - Do not grant “Write enabled”
- Copy the token value and store it safely; NetBox will not show it again.
Step 1b: Store the Token in a Kubernetes Secret
Create a Kubernetes Secret containing the token so it is not embedded in manifests.
# API Token Format: nbt_<Key>.<Token>
kubectl create secret generic netbox-api-token \
--from-literal=token=YOUR_NETBOX_TOKEN \
-n your-namespace
Verify the Secret was created:
kubectl get secret netbox-api-token -n your-namespace -o yaml
Step 2: Create an Export Template in NetBox
Log in to your NetBox instance and navigate to Customization > Export Templates.
Step 2a: Create a New Template
Click Add Export Template and fill in the details:
| Field | Value | Notes |
|---|---|---|
| Name | gNMIc Device Export | Descriptive name for your template |
| Content Type | dcim > device | Export template applies to Device objects |
| Template Code | (see below) | Jinja2 template |
| File Extension | json | Output format |
| Mime Type | application/json | Correct MIME type for JSON |
Step 2b: Template Code Example
Basic Template (All Devices)
{
"targets": [
{% for device in queryset %}
{
"name": "{{ device.name }}",
"address": "{{ device.primary_ip4.address.split('/')[0] }}:57400",
"labels": {
"site": "{{ device.site.name }}",
"role": "{{ device.device_role.name }}",
"region": "{{ device.site.region.name }}",
"type": "{{ device.device_type.model }}"
}
}{{ "," if not loop.last }}
{% endfor %}
]
}
Advanced Template (Filtered by Status and Role)
{
"targets": [
{% for device in queryset.filter(status='active', device_role__name__in=['leaf', 'spine']) %}
{
"name": "{{ device.name }}",
"address": "{{ device.primary_ip4.address.split('/')[0] }}:57400",
"labels": {
"site": "{{ device.site.name }}",
"role": "{{ device.device_role.name }}",
"region": "{{ device.site.region.name }}",
"model": "{{ device.device_type.model }}",
"serial": "{{ device.serial }}",
"asset_tag": "{{ device.asset_tag }}"
}
}{{ "," if not loop.last }}
{% endfor %}
]
}
Key template elements:
queryset: The filtered set of devices (all unless you add.filter())device.name: Device hostnamedevice.primary_ip4.address.split('/')[0]: Extract IP from CIDR (e.g.,192.0.2.1/24to192.0.2.1)device.site.name,device.device_role.name: NetBox relationships (site, role, etc.)loop.last: Jinja2 loop variable to avoid trailing comma on last item
Step 2c: Save and Access the Template
Once saved, NetBox exposes the template via:
http://netbox.example.com:8000/api/dcim/devices/?export=gNMIc+Device+Export
Or fetch it directly:
# Replace with your NetBox URL and template name
curl -H "Authorization: Token YOUR_NETBOX_TOKEN" \
"http://netbox.example.com:8000/api/dcim/devices/?export=gNMIc%20Device%20Export"
The response is a JSON array of targets ready for gNMIc.
Step 3: Create a TargetProfile
Define how discovered targets should be configured. The TargetProfile points to a Secret containing device credentials, such as username/password or client certificates.
Create a credentials Secret first, then reference it from the profile.
apiVersion: v1
kind: Secret
metadata:
name: device-credentials
namespace: your-namespace
type: Opaque
stringData:
username: gnmic
password: gnmicPass
apiVersion: operator.gnmic.dev/v1alpha1
kind: TargetProfile
metadata:
name: netbox-device
namespace: your-namespace
spec:
credentialsRef: device-credentials
timeout: 10s
For more TargetProfile options and credential handling, see the operator documentation for TargetProfile.
Step 4: Create a TargetSource Using Export Template
Create a TargetSource that references your NetBox export template endpoint:
apiVersion: operator.gnmic.dev/v1alpha1
kind: TargetSource
metadata:
name: netbox-export-source
namespace: your-namespace
spec:
# Specify the HTTP provider
provider:
http:
# NetBox API endpoint with export template query
# Replace: netbox.example.com, template name (gNMIc+Device+Export), token
url: "http://netbox.example.com:8000/api/dcim/devices/?export=gNMIc%20Device%20Export"
# Do not embed plaintext tokens in the TargetSource YAML. Instead, use a secret reference:
token:
scheme: Bearer
tokenSecretRef:
name: netbox-api-token
key: token
# Reference the TargetProfile
targetProfile: netbox-device
# Optional: Apply labels to all discovered targets
targetLabels:
inventory: netbox
sync-source: export-template
Step 5: Verify Target Discovery
Once the TargetSource is deployed, verify that targets are being discovered:
# List discovered targets
kubectl get targets -n your-namespace
# Check TargetSource status and sync details
kubectl describe ts netbox-export-source -n your-namespace
Successful sync shows:
status.status: “success”status.targetsCount: number of devicesstatus.lastSync: recent timestamp
Example: Complete Setup
Here’s a full example combining all components:
---
# Secret for NetBox API token
apiVersion: v1
kind: Secret
metadata:
name: netbox-api-token
namespace: gnmic
type: Opaque
data:
# base64-encoded token (echo -n "YOUR_TOKEN" | base64)
token: YOUR_BASE64_ENCODED_TOKEN
---
# TargetProfile for NetBox devices
apiVersion: operator.gnmic.dev/v1alpha1
kind: TargetProfile
metadata:
name: netbox-device
namespace: gnmic
spec:
credentialsRef: device-credentials
timeout: 10s
---
# TargetSource using Export Template
apiVersion: operator.gnmic.dev/v1alpha1
kind: TargetSource
metadata:
name: netbox-export-source
namespace: gnmic
spec:
provider:
http:
url: "http://netbox.example.com:8000/api/dcim/devices/?export=gNMIc%20Device%20Export"
targetProfile: netbox-device
targetLabels:
inventory: netbox
sync-source: export-template
---
# Device Credentials (referenced by TargetProfile)
apiVersion: v1
kind: Secret
metadata:
name: device-credentials
namespace: gnmic
type: Opaque
data:
username: Z25taWM= # base64: gnmic
password: Z25taaWNQYXNz= # base64: gnmicPass
Advantages of Export Templates
- Powerful Filtering: Filter devices by site, status, role, tags, etc. directly in NetBox
- Reduced Operator Load: NetBox handles data transformation; operator just fetches JSON
- Reusability: One template can serve multiple consumers
- Maintainability: Update discovery logic in NetBox without changing Kubernetes manifests
- Performance: Avoids REST API pagination for large inventories
Limitations & Considerations
1. Reverse Proxy and URL Path Rewriting
If NetBox is behind a reverse proxy with URL path rewriting:
- Issue: The export template endpoint uses query parameters that may not survive proxy transformation.
- Solution:
- Ensure the proxy preserves query strings exactly.
- Test the export URL directly:
curl -H "Authorization: Token YOUR_TOKEN" \ "http://netbox.example.com:8000/api/dcim/devices/?export=gNMIc%20Device%20Export" - If the proxy blocks or modifies parameters, consider using a direct NetBox endpoint without proxying.
2. Large Inventory Rendering
- Very large device counts can cause NetBox to take time rendering the template.
- Solution:
- Use
.filter()in your template to limit results. - Create separate export templates for different device groups (e.g., by site or role).
- Use
3. Complex Jinja2 Logic
- NetBox’s Jinja2 sandbox restricts some Python functions for security.
- Solution: Keep templates simple and use NetBox’s built-in filters and objects. Test in the NetBox UI before deploying.
Template Troubleshooting
Missing Data in Output
- Check: Are all required fields populated in NetBox? (e.g.,
primary_ip4may beNoneif not set) - Solution: Add conditional checks:
{% if device.primary_ip4 %} "address": "{{ device.primary_ip4.address.split('/')[0] }}" {% endif %}
Authorization Fails
If you get a 403 error:
- Verify the token is valid and not expired.
- Check token permissions in NetBox admin (User > API Tokens).
- Ensure the API token is enabled.