Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
07c7efe
added first draft for targetsource implementation docs
mcdillson May 13, 2026
8bab96c
aligning doc with existing pages
mcdillson May 13, 2026
2d1f5fb
updated targetSource guide based on new CRD
mcdillson May 21, 2026
abbbee4
renamed response field ip to address
mcdillson May 21, 2026
21496fc
moved http into a subfile of TargetSource
mcdillson May 21, 2026
db090b3
restructured http chapter hierarchy
mcdillson May 21, 2026
69d82bb
changed example router names
mcdillson May 21, 2026
7c34171
update http provider documentation
denyost May 29, 2026
28d8027
tune the http provider doc
denyost May 29, 2026
929a4c2
update default value of timeout
denyost May 29, 2026
c3fe3ca
fix CEL expression
denyost May 29, 2026
0389b9f
docs: update pull mode
denyost May 29, 2026
31fd036
update docs pagination and hybrid CEL mapping
denyost Jun 1, 2026
c12683d
add Netbox example
denyost Jun 1, 2026
b9ddb8b
imporve export template documentation
denyost Jun 1, 2026
9b7dc0b
docs: made TargetProfile optional
mcdillson Jun 1, 2026
b479017
changed authorization to authentication
mcdillson Jun 1, 2026
5086648
add netbox rest api example
denyost Jun 2, 2026
fc6af9c
fix incorrect namespace
denyost Jun 2, 2026
f0d63ff
update netbox export template guide
denyost Jun 2, 2026
0a2bc2b
Merge branch 'docs/targetsource-userguide' of https://github.com/gnmi…
denyost Jun 2, 2026
8aa4ac8
update authorization to authentication
denyost Jun 2, 2026
c3c58af
re-word credentialsSecretRef
denyost Jun 2, 2026
7ea9ade
update targetsource structure
denyost Jun 4, 2026
6050368
ad subsecrtion targetsource provider
denyost Jun 4, 2026
6fc57fc
update reference
denyost Jun 4, 2026
89feb1d
update weights
denyost Jun 4, 2026
1643d48
update description
denyost Jun 4, 2026
bc456c5
update reference
denyost Jun 4, 2026
0154766
refactor titles
denyost Jun 4, 2026
28e84d1
refactor http provider
denyost Jun 4, 2026
cf1104c
update netbox examples
denyost Jun 4, 2026
9fbb433
comment out relref
denyost Jun 4, 2026
80021b7
comment out relref
denyost Jun 4, 2026
9112eaf
comment out relref
denyost Jun 4, 2026
46ca88d
comment out links
denyost Jun 4, 2026
4ac7261
comment out netbox examples
denyost Jun 4, 2026
e43fcda
try finding docu compiling error
denyost Jun 4, 2026
3bd1c1e
try finding compile error
denyost Jun 4, 2026
c456806
add example folder NetBox
denyost Jun 4, 2026
ef97608
add example Netbox Export Template
denyost Jun 4, 2026
7a64601
minimize export template example
denyost Jun 4, 2026
3cd9666
add step 1
denyost Jun 4, 2026
9fb54c3
add step 2 & 3
denyost Jun 4, 2026
fcbd339
remove relref
denyost Jun 4, 2026
1dd827c
complete example without relrefs
denyost Jun 4, 2026
0da0fb0
add relrefs
denyost Jun 4, 2026
20accaa
add one relref
denyost Jun 4, 2026
47918d7
update relref
denyost Jun 4, 2026
e2d6000
replace relref
denyost Jun 4, 2026
1d3f577
add rest api examples
denyost Jun 4, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
399 changes: 399 additions & 0 deletions docs/content/docs/examples/NetBox/Export Template/_index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,399 @@
---
title: "NetBox (Export Template)"
linkTitle: "NetBox Export Template"
weight: 1
description: >
Discover targets from NetBox using HTTP provider with 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 the load on the operator.

## Overview

An **Export Template** is a Jinja2 template defined in NetBox that:

1. **Queries** NetBox's internal database (devices, interfaces, etc.)
2. **Filters** results based on custom criteria
3. **Transforms** data into your desired output format (JSON, YAML, CSV, etc.)
4. **Returns** the formatted output via a custom REST API endpoint

When used with gNMIc's HTTP provider, the operator simply fetches the rendered JSON template and parses the result — no additional gNMIc Operator transformation needed if done correctly.

---

## Prerequisites

- A running Kubernetes cluster with gNMIc Operator installed
- `kubectl` access to your cluster
- A reachable NetBox instance with permissions to create Export Templates
- A NetBox API token
- Familiarity with Jinja2 templates

---

## Step 1: Create a NetBox API Token and Store It Securely

### Step 1a: Create the API Token in NetBox

Create a dedicated API token in NetBox for gNMIc Operator access.

1. Log in to NetBox.
2. Open your user profile or go to **User > API Tokens**.
3. Click **Add** or **Add token**.
4. Enter a descriptive name such as `gNMIc Operator`.
5. Grant the minimum permissions required for read-only device discovery.
6. 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](https://kubernetes.io/docs/concepts/configuration/secret/) containing the token.

```bash
# Substitute YOUR_NETBOX_API_TOKEN with your actual token
# Bearer Token Format (v2): nbt_<key>.<token>
kubectl create secret generic netbox-api-token \
--from-literal=token=YOUR_NETBOX_API_TOKEN \
-n gnmic-system
```

Verify the Secret was created:

```bash
kubectl get secret netbox-api-token -n gnmic-system -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

The following Export Templates only work for devices that have a primary IPv4 address set in NetBox. If primary_ip4 is missing, the expression returns '', so those devices will not yield a valid target address. For NetBox data model details, see the [NetBox Devices Data Model](https://netboxlabs.com/docs/netbox/models/dcim/device/) documentation.

See the HTTP provider's "Default Response Format" section for the expected JSON structure: [HTTP provider docs](../../user-guide/targetsource/providers/http.md)

#### Basic Template (All Devices)

```jinja2
[
{% for device in queryset %}
{
"name": "{{ device.name }}",
"address": "{{ device.primary_ip4.address.ip }}",
"labels": {
"site": "{{ device.site.name }}",
"role": "{{ 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)

```jinja2
[
{% for device in queryset.filter(status='active', role__name__in=['leaf', 'spine']) %}
{
"name": "{{ device.name }}",
"address": "{{ device.primary_ip4.address.ip }}",
"labels": {
"site": "{{ device.site.name }}",
"role": "{{ 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 hostname
- `device.primary_ip4.address.ip`: Primary IPv4 address
- `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:

```bash
# Replace with your NetBox URL and template name
# Substitute YOUR_NETBOX_API_TOKEN with your actual token
# Bearer Token Format (v2): nbt_<key>.<token>
curl -H "Authorization: Bearer YOUR_NETBOX_API_TOKEN" \
"http://netbox.example.com:8000/api/dcim/devices/?export=gNMIc%20Device%20Export"
```

The response should be a JSON array of targets ready for the gNMIc Operator.

Sample JSON output produced by the basic export template:

```json
[

{
"name": "edge-rtr-01.dc1.example.com",
"address": "203.0.113.1",
"labels": {
"site": "DC1",
"role": "edge",
"region": "eu-central-1",
"type": "router"
}
},

]
```

> Ensure the response is valid JSON and contains no hidden or invalid characters, otherwise the gNMIc Operator will fail to parse it.

> If you instead return a JSON object with a nested array, add a mapping section such as `targetsField: "self.targets"` to the TargetSource CR.

---

## Step 3: Create a TargetProfile

Define how discovered targets should be configured. The `TargetProfile` points to a [Kubernetes Secret](https://kubernetes.io/docs/concepts/configuration/secret/) containing device credentials, such as username/password or client certificates.

Create a credentials Secret first, then reference it from the TargetProfile.

```yaml
# Replace YOUR_DEVICE_USERNAME and YOUR_DEVICE_PASSWORD with your corresponding default device username and password
apiVersion: v1
kind: Secret
metadata:
name: device-credentials
namespace: gnmic-system
type: Opaque
stringData:
username: YOUR_DEVICE_USERNAME
password: YOUR_DEVICE_PASSWORD
```

```yaml
apiVersion: operator.gnmic.dev/v1alpha1
kind: TargetProfile
metadata:
name: netbox-device
namespace: gnmic-system
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:

```yaml
apiVersion: operator.gnmic.dev/v1alpha1
kind: TargetSource
metadata:
name: netbox-export-source
namespace: gnmic-system
spec:
targetPort: 57400
targetProfile: netbox-device
targetLabels:
inventory: netbox
sync-source: export-template
provider:
http:
url: "http://netbox.example.com:8000/api/dcim/devices/?export=gNMIc%20Device%20Export"
method: GET
interval: 30m
timeout: 30s
authentication:
token:
scheme: Token
tokenSecretRef:
name: netbox-api-token
key: token
```

---

## Step 5: Verify Target Discovery

Once the `TargetSource` is deployed, verify that targets are being discovered:

```bash
# List discovered targets
kubectl get targets -n gnmic-system

# Check TargetSource status and sync details
kubectl describe targetsource netbox-export-source -n gnmic-system
```

Successful sync shows:

- `status.status`: "success" (or similar) <!-- todo: to be verivied -->
- `status.targetsCount`: number of devices
- `status.lastSync`: recent timestamp

---

## Example: Complete Setup

Here's a full example combining all components:

```yaml
---
# Secret for NetBox API token
apiVersion: v1
kind: Secret
metadata:
name: netbox-api-token
namespace: gnmic-system
type: Opaque
data:
# base64-encoded token (echo -n "YOUR_TOKEN" | base64)
token: YOUR_BASE64_ENCODED_TOKEN

---
# Secret for Target Credential
apiVersion: v1
kind: Secret
metadata:
name: device-credentials
namespace: gnmic-system
type: Opaque
stringData:
username: YOUR_DEVICE_USERNAME
password: YOUR_DEVICE_PASSWORD

---
# TargetProfile
apiVersion: operator.gnmic.dev/v1alpha1
kind: TargetProfile
metadata:
name: netbox-device
namespace: gnmic-system
spec:
credentialsRef: device-credentials
timeout: 10s


---
# TargetSource using Export Template
apiVersion: operator.gnmic.dev/v1alpha1
kind: TargetSource
metadata:
name: netbox-export-source
namespace: gnmic-system
spec:
targetPort: 57400
targetProfile: netbox-device
targetLabels:
inventory: netbox
sync-source: export-template
provider:
http:
url: "http://netbox.example.com:8000/api/dcim/devices/?export=gNMIc%20Device%20Export"
method: GET
interval: 30m
timeout: 30s
authentication:
token:
scheme: Token
tokenSecretRef:
name: netbox-api-token
key: token
```

---

## 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:
```bash
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).

### 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 the URL with curl or similar before deploying.

---

## Template Troubleshooting

### Missing Targets in Kubernetes

- **Check**: Are all required fields populated in NetBox? (e.g., `primary_ip4` may be `None` if not set)
- **Solution**: Add conditional checks:
```jinja2
{% if device.primary_ip4 %}
"address": "{{ device.primary_ip4.address.ip }}"
{% endif %}
```

### Authorization Fails

If you get a 403 error:

- Verify the token is valid and not expired.
- Ensure the API token is enabled.

---
Loading