Add NetBox to Infrahub sync tutorial#134
Conversation
Adds a tutorial for syncing public NetBox demo data into a local Infrahub instance and exposes it in the docs sidebar.
Validation:
- uv run pytest -q
- npx markdownlint-cli2 "docs/docs/**/*.{md,mdx}"
- uv run invoke docs.docusaurus
Generated with Codex.
WalkthroughAdds a new tutorial page for syncing the public NetBox demo into Infrahub, updates the docs sidebar to surface it, and rewrites the example sync configuration to use environment-based credentials with expanded DCIM, interface, circuit, and IPAM mappings. 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Deploying infrahub-sync with
|
| Latest commit: |
1213a7d
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://ea4c95b2.infrahub-sync.pages.dev |
| Branch Preview URL: | https://feature-netbox-demo-tutorial.infrahub-sync.pages.dev |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@docs/docs/tutorials/netbox-demo-to-infrahub.mdx`:
- Around line 435-439: The bash command in the token troubleshooting section
checks the wrong environment variable. Instead of echoing INFRAHUB_ADDRESS,
update the command to verify that INFRAHUB_API_TOKEN is actually set and
exported. Replace the echo command that references INFRAHUB_ADDRESS with a
command that checks for the presence of INFRAHUB_API_TOKEN and provides clear
feedback on whether the token environment variable is properly configured for
authentication.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 8a8a9674-104d-4ac3-a7b7-625ca4465ccd
📒 Files selected for processing (2)
docs/docs/tutorials/netbox-demo-to-infrahub.mdxdocs/sidebars.ts
Refreshes the tutorial after local validation: pins commands to the published 2.0.0 package, documents demo token and startup behavior, aligns verification with current public NetBox data, and keeps the order guidance focused on auto-derived write ordering. Also fixes the NetBox example config serial_number Transformation expression by removing a stray trailing brace and corrects the dmi01 comment so reviewers can inspect that config change directly. Generated with Codex.
|
Updated this PR after local tutorial validation. Main changes:
Reviewer attention requested: this also includes a small non-doc fix in |
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
docs/docs/tutorials/netbox-demo-to-infrahub.mdx (1)
1-545:⚠️ Potential issue | 🟠 MajorFix markdownlint-cli2 line-length violations.
The file fails markdownlint-cli2 validation with 4 line-length errors (MD013). All lines must be 80 characters or fewer:
- Line 5: 110 characters (30 over limit)
- Line 6: 103 characters (23 over limit)
- Line 31: 89 characters (9 over limit)
- Line 191: 114 characters (34 over limit)
Shorten these lines to pass the markdownlint-cli2 check required by the coding guidelines for documentation files.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@docs/docs/tutorials/netbox-demo-to-infrahub.mdx` around lines 1 - 545, The markdown file has four lines that exceed the 80-character line-length limit required by markdownlint-cli2: Line 5 (110 characters) which contains the opening sentence about using Infrahub Sync to copy data from NetBox demo, Line 6 (103 characters) which continues about starting from scratch, Line 31 (89 characters) which mentions linking to related pages, and Line 191 (114 characters) which is in the normalization section. Break each of these lines into multiple shorter lines that each stay under 80 characters while preserving the meaning and markdown formatting, ensuring no content is lost or modified beyond line wrapping.Source: Coding guidelines
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Outside diff comments:
In `@docs/docs/tutorials/netbox-demo-to-infrahub.mdx`:
- Around line 1-545: The markdown file has four lines that exceed the
80-character line-length limit required by markdownlint-cli2: Line 5 (110
characters) which contains the opening sentence about using Infrahub Sync to
copy data from NetBox demo, Line 6 (103 characters) which continues about
starting from scratch, Line 31 (89 characters) which mentions linking to related
pages, and Line 191 (114 characters) which is in the normalization section.
Break each of these lines into multiple shorter lines that each stay under 80
characters while preserving the meaning and markdown formatting, ensuring no
content is lost or modified beyond line wrapping.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 5e0c4f13-487b-45e4-ae44-0095e247f39d
📒 Files selected for processing (3)
docs/docs/tutorials/netbox-demo-to-infrahub.mdxdocs/sidebars.tsexamples/netbox_to_infrahub/config.yml
✅ Files skipped from review due to trivial changes (1)
- docs/sidebars.ts
| python3 -m venv .venv | ||
| source .venv/bin/activate | ||
| pip install "infrahub-sync==2.0.0" pynetbox | ||
| ``` |
There was a problem hiding this comment.
We very strongly recommend using UV (or poetry) to manage dependencies
| cd ~/repos | ||
| git clone https://github.com/opsmill/infrahub.git | ||
| cd infrahub | ||
| export INFRAHUB_INITIAL_ADMIN_TOKEN="06438eb2-8019-4776-878c-0941b1f1d1ec" | ||
| docker compose up -d |
There was a problem hiding this comment.
We don't need to clone the entire repository, it's possible to just curl the docker compose file https://docs.infrahub.app/deploy-manage/install-configure/install/community
There was a problem hiding this comment.
- I don't think
export INFRAHUB_INITIAL_ADMIN_TOKEN="06438eb2-8019-4776-878c-0941b1f1d1ec"is needed as it's already the default value
|
|
||
| ```bash | ||
| cd ~/repos/demo-infrahub-sync | ||
| infrahubctl schema load ~/repos/infrahub/models/examples/netbox/netbox.yml |
There was a problem hiding this comment.
Eventually this will change and point to the new schema
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@examples/netbox_to_infrahub/config.yml`:
- Around line 211-293: The config defines two DcimDevice mappings with the same
kind, but incremental sync uses the first match from list_changed_since(), so
site-only devices are skipped. Update the DcimDevice entries in the
Netbox-to-Infrahub config to use a single mapping with combined rack/site filter
logic, or adjust the lookup in list_changed_since() to consider all matching
schema_mapping entries instead of stopping at the first one.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: a6507911-171b-42a0-9bcd-1f68ff841385
📒 Files selected for processing (1)
examples/netbox_to_infrahub/config.yml
| - name: DcimDevice | ||
| identifiers: ["location", "name"] | ||
| mapping: dcim.devices | ||
| fields: | ||
| - name: name # /!\ Netbox allows duplicate device names within a virtual-chassis. | ||
| mapping: name | ||
| - name: serial | ||
| mapping: serial | ||
| - name: description | ||
| mapping: description | ||
| - name: position | ||
| mapping: position | ||
| - name: rack_face | ||
| mapping: face.value | ||
| - name: status | ||
| mapping: status.value | ||
| # NOTE: schema changes are required to support role sync (see related note) | ||
| # - name: role | ||
| # mapping: role.slug | ||
| - name: device_type | ||
| mapping: device_type | ||
| reference: DcimDeviceType | ||
| - name: platform | ||
| mapping: platform | ||
| reference: DcimPlatform | ||
| - name: location | ||
| mapping: rack | ||
| reference: LocationRack | ||
| - name: tags | ||
| mapping: tags | ||
| reference: BuiltinTag | ||
| - name: primary_address | ||
| mapping: primary_ip | ||
| reference: IpamIPAddress | ||
| filters: | ||
| - field: parent_device # Most lickely for sub-devices (e.g. stacks...) you'd have a dedicated node in Infrahub | ||
| operation: "is_empty" | ||
| - field: rack | ||
| operation: "is_not_empty" | ||
| - field: name # /!\ Netbox allows empty name for devices | ||
| operation: "is_not_empty" | ||
|
|
||
| - name: DcimDevice | ||
| identifiers: ["location", "name"] | ||
| mapping: dcim.devices | ||
| fields: | ||
| - name: name | ||
| mapping: name | ||
| - name: serial_number | ||
| - name: serial | ||
| mapping: serial | ||
| - name: asset_tag | ||
| mapping: asset_tag | ||
| - name: description | ||
| mapping: description | ||
| - name: model | ||
| - name: position | ||
| mapping: position | ||
| - name: rack_face | ||
| mapping: face.value | ||
| - name: status | ||
| mapping: status.value | ||
| # NOTE: schema changes are required to support role sync (see related note) | ||
| # - name: role | ||
| # mapping: role.slug | ||
| - name: device_type | ||
| mapping: device_type | ||
| reference: ChoiceDeviceType | ||
| - name: organization | ||
| mapping: tenant | ||
| reference: OrganizationGeneric | ||
| - name: role | ||
| mapping: role | ||
| reference: RoleGeneric | ||
| # - name: status | ||
| # mapping: status | ||
| # reference: StatusGeneric | ||
| reference: DcimDeviceType | ||
| - name: platform | ||
| mapping: platform | ||
| reference: DcimPlatform | ||
| - name: location | ||
| mapping: site | ||
| reference: LocationGeneric | ||
| - name: rack | ||
| mapping: rack | ||
| reference: InfraRack | ||
| reference: LocationSite | ||
| - name: tags | ||
| mapping: tags | ||
| reference: BuiltinTag | ||
| # Showcase Filters | ||
| # It will import the ones with dmu01 in their name *AND* without pdu | ||
| - name: primary_address | ||
| mapping: primary_ip | ||
| reference: IpamIPAddress | ||
| filters: | ||
| - field: name | ||
| operation: "contains" | ||
| value: "dmi01" | ||
| - field: name | ||
| operation: "not contains" | ||
| value: "pdu" | ||
| # Showcase Transforms | ||
| transforms: | ||
| - field: name | ||
| expression: "{{ name.lower() if name else '' }}" | ||
| - field: serial_number | ||
| expression: "{{ serial.lower() if serial else '' }}}" | ||
| - field: parent_device | ||
| operation: "is_empty" | ||
| - field: rack | ||
| operation: "is_empty" | ||
| - field: name # /!\ Netbox allows empty name for devices | ||
| operation: "is_not_empty" |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Inspect how schema_mapping entries are enumerated vs. looked up by name.
fd -e py . infrahub_sync | xargs rg -nP -C3 '\bschema_mapping\b'
# Specifically any name-based single lookups that could miss duplicate names.
rg -nP -C3 'next\(\s*\(?e for e in .*schema_mapping' infrahub_sync
# Any de-dup or grouping by element name during full model_loader.
rg -nP -C3 'model_loader|for .* in .*schema_mapping' infrahub_syncRepository: opsmill/infrahub-sync
Length of output: 50377
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== netbox adapter =="
sed -n '1,220p' infrahub_sync/adapters/netbox.py
echo
echo "== sync loop / cursor handling =="
sed -n '150,240p' infrahub_sync/__init__.py
echo
echo "== config schema model and order fields =="
sed -n '70,140p' infrahub_sync/__init__.py
echo
echo "== duplicate-name behavior in example config =="
python3 - <<'PY'
from pathlib import Path
p = Path("examples/netbox_to_infrahub/config.yml")
text = p.read_text()
for needle in ["- name: DcimDevice", "mapping: dcim.devices", "operation: \"is_empty\"", "operation: \"is_not_empty\""]:
print(f"{needle}: {text.count(needle)}")
PYRepository: opsmill/infrahub-sync
Length of output: 16591
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== where incremental extraction calls list_changed_since =="
rg -n -C 3 'list_changed_since\(' infrahub_sync
echo
echo "== where cursor tiers drive incremental vs full loads =="
rg -n -C 3 'cursor_tier_for\(|CursorTier|incremental' infrahub_sync
echo
echo "== netbox adapter name lookup sites =="
rg -n -C 3 'next\(\s*\(e for e in self\.config\.schema_mapping if e\.name == model_name\)' infrahub_sync/adapters/netbox.py
echo
echo "== example config incremental block =="
rg -n -C 3 '^incremental:|full_resync_every|order:|schema_mapping:' examples/netbox_to_infrahub/config.ymlRepository: opsmill/infrahub-sync
Length of output: 23779
Duplicate DcimDevice mappings skip site-only devices on incremental runs. list_changed_since() takes the first schema_mapping entry for a kind, so cursor-driven syncs will only apply the rack-filtered block here. Merge the rack/site filters into one mapping, or make the incremental lookup handle all matching entries.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@examples/netbox_to_infrahub/config.yml` around lines 211 - 293, The config
defines two DcimDevice mappings with the same kind, but incremental sync uses
the first match from list_changed_since(), so site-only devices are skipped.
Update the DcimDevice entries in the Netbox-to-Infrahub config to use a single
mapping with combined rack/site filter logic, or adjust the lookup in
list_changed_since() to consider all matching schema_mapping entries instead of
stopping at the first one.
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@docs/docs/tutorials/netbox-demo-to-infrahub-v2.mdx`:
- Around line 146-153: The tutorial examples in the Infrahub Sync setup still
expose the seeded API token in both the environment export block and the later
snippet, so replace those hardcoded credential values with a redacted
placeholder or a token-acquisition step. Update the examples around the
INFRAHUB_ADDRESS and INFRAHUB_API_TOKEN usage to keep them minimal and
copy/paste-safe, and ensure the surrounding text no longer implies the published
token should be reused.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: b74145e4-b1b0-415d-9cce-cc45dad1e829
📒 Files selected for processing (2)
docs/docs/tutorials/netbox-demo-to-infrahub-v2.mdxexamples/netbox_to_infrahub/config.yml
🚧 Files skipped from review as they are similar to previous changes (1)
- examples/netbox_to_infrahub/config.yml
Summary
docs/docs/tutorials/netbox-demo-to-infrahub.mdx) that walks a reader from zero — no existing Infrahub instance required — through scaffolding a project, starting Infrahub, installing Infrahub Sync, loading a schema, and running a first NetBox → Infrahub sync against the public NetBox demo. Readers who already have Infrahub running are pointed straight to the NetBox adapter docs instead.examples/netbox_to_infrahub/config.yml) to target the production-grade schema-library schema instead of the ad-hoc example schema used previously, covering DCIM, IPAM, and organization objects with the same core domains as NetBox.docs/sidebars.ts.What's covered
Sites, racks, devices and interfaces, VRFs/VLANs, prefixes/IP addresses, circuits, tags, and organizations (manufacturers, providers, RIRs).
Known limitations / follow-ups
TODOs inconfig.yml.curlloop and the pinned-commit config download are stand-ins until schema distribution moves through the marketplace and config distribution firms up.