feat(dcim): support NetBox device-type and module-type imports - #76
Open
petercrocker wants to merge 1 commit into
Open
feat(dcim): support NetBox device-type and module-type imports#76petercrocker wants to merge 1 commit into
petercrocker wants to merge 1 commit into
Conversation
Deploying schema-library with
|
| Latest commit: |
dc9ec12
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://849969a7.schema-library.pages.dev |
| Branch Preview URL: | https://feat-netbox-import-module-ba.schema-library.pages.dev |
petercrocker
force-pushed
the
feat-netbox-import-module-bays
branch
4 times, most recently
from
August 6, 2026 11:34
0e14203 to
b8df83d
Compare
Contributor
|
@petercrocker I completely revisited the device module extension here https://github.com/opsmill/schema-library/pull/75/changes#diff-3388ec71d8a9c2c95e93b3f50658e4fb0de13acc38cdc98e3908738c435e3b0d |
Merged
petercrocker
force-pushed
the
feat-netbox-import-module-bays
branch
from
September 3, 2026 20:26
b8df83d to
84b7773
Compare
petercrocker
marked this pull request as ready for review
September 3, 2026 20:33
petercrocker
force-pushed
the
feat-netbox-import-module-bays
branch
from
September 3, 2026 20:43
84b7773 to
5a225fb
Compare
Importing the NetBox devicetype-library into Infrahub loses most of what a modular chassis and a module type describe, and a batch of module types fails to load outright. This closes the remaining gaps against the v2 model landed in #75, which already introduced DcimModuleBay, DcimGenericModule and DcimGenericModuleType in extensions/device_module. Three pieces of the original change are already delivered by #75 and are dropped here: generate_template on DcimDevice, the non-unique part_number on the module-type generic, and a ModuleBay node of its own (extensions/module_bay is superseded by DcimModuleBay). extensions/device_module/device_module.yml DcimModuleBay.position becomes Text. Bay positions are free-form: a DCS-7508N uses '1'..'10' but also 'F1'..'F6' and 'PSU-1'..'PSU-8', so a Number attribute with min_value 1 rejects 14 of its 24 bays. Add DcimModuleBay.bay_label. The NetBox label lands here, NOT in an attribute named label - Infrahub auto-populates an attribute literally named label from name when unset, and title-cases it, so an unlabelled bay comes back labelled with its own name and 'no label' becomes indistinguishable from 'label equals name'. On a DCS-7508N only 10 of 24 bays carry one. Distinct from the existing role dropdown, which enumerates the bay's purpose rather than carrying NetBox's free text. Add DcimGenericModuleType.weight_grams. Infrahub has no float attribute kind, so a weight is a whole number or nothing, and modules are exactly the light hardware that integer kilograms destroy: a transceiver or a supervisor rounds to 0 kg, which reads as data rather than as a missing value. extensions/module_port (new) The ports a module provides, as declared by its module type - what NetBox lists under interfaces, console-ports and power-ports. These deliberately are not DcimInterface. DcimInterface.device is a mandatory Parent, and Infrahub requires relationships used in a uniqueness constraint to be mandatory, so relaxing it fails with "cannot use device relationship, relationship must be mandatory" and would break the device__name__value human_friendly_id too. A DcimModulePort is a declaration parented by DcimGenericModule, carrying name, category, the NetBox type slug, mgmt_only and maximum_draw. Keyed on module__computed_name__value, not serial_number: #75 made DcimGenericModule.serial_number optional and non-unique, so it cannot key anything, while computed_name is unique and mandatory. port_type is Text, not Dropdown: NetBox uses well over a hundred type slugs across the three lists, and a Dropdown fails the load on every slug not enumerated. Port names keep NetBox's {module} token verbatim - a template is not bound to a bay, so it cannot be resolved at import time. Substituting it and creating the real device interfaces is a generator step once the module is installed; the traversal it needs is documented in the file. experimental/modules_linecards/linecard.yml Enable generate_template on DeviceLinecard, so a module type can be imported as a reusable blueprint rather than as an installed card. DeviceLinecard.slot becomes optional. A NetBox module type describes a model rather than an installed card and carries no slot, so a mandatory slot made every imported module type unloadable. objects/extensions/{device_module,device_psu_module} Quote the demo bay positions now that position is Text. Reference docs regenerated with invoke docs.generate.
petercrocker
force-pushed
the
feat-netbox-import-module-bays
branch
from
September 6, 2026 12:43
5a225fb to
dc9ec12
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Importing the NetBox devicetype-library into Infrahub loses most of what a modular chassis and a module type describe, and a batch of module types fails to load outright.
Rebased onto Schema Library v2 (#75)
This PR predates #75, which landed the v2 model and delivered a good part of what this branch originally carried. It has been rebased, and three pieces are now dropped because #75 already ships them:
generate_template: trueonDcimDevicemain(base/dcim.yml)uniquefrom the module type'spart_numbermain—DcimGenericModuleType.part_numberis not uniqueextensions/module_bay(a newDcimModuleBay)DcimModuleBayinextensions/device_moduleextensions/modules/modules.ymlwas deleted by #75, so the changes this PR made to it are re-homed ontoextensions/device_module/device_module.yml. What remains is the delta that v2 does not yet cover.Changes
All additive or relaxing. Nothing is removed.
extensions/device_module/device_module.ymlTwo design deltas ported onto #75's
DcimModuleBay, plus one onto its module type generic.DcimModuleBay.positionbecomesText. Bay positions are free-form. The DCS-7508N alone usesF1–F6andPSU-1–PSU-8alongside1–10, andA9K-AC-PEM-V3starts its bays atposition: '0'. Against v2'sNumberwithmin_value: 1, 15 of the DCS-7508N's 24 bays fail — the 14 non-numeric ones, plus'0', which is numeric but still violates the minimum.DcimModuleBay.bay_label. The NetBox label lands here, not in an attribute namedlabel. Infrahub auto-populates an attribute literally namedlabelfromnamewhen unset, and title-cases it, so "NetBox supplied no label" becomes indistinguishable from "label equals name". On a DCS-7508N only 10 of 24 bays carry one. This is distinct from v2's existingroledropdown, which enumerates a bay's purpose (supervisor,line_card, …) rather than carrying NetBox's free text — the two coexist.DcimGenericModuleType.weight_grams(Number). Infrahub has no float attribute kind, so a weight is a whole number or nothing — and modules are exactly the light hardware that integer kilograms destroy. A transceiver or supervisor rounds to0kg, which reads as data rather than as a missing value.extensions/module_port(new)The one piece with no equivalent anywhere in v2. The ports a module provides, as declared by its module type — what NetBox lists under
interfaces,console-portsandpower-ports.These are deliberately not
DcimInterface. I tested that first:DcimInterface.deviceis a mandatoryParent, and Infrahub requires relationships used in a uniqueness constraint to be mandatory, so relaxing it so an interface could hang off a module fails outright:Every interface kind is keyed
[device, name__value]with adevice__name__valueHFID, so that route means dismantling interface identity schema-wide.A
DcimModulePortis instead a declaration parented by the module:name,category(interface/console/power/front/rear),port_type,mgmt_only,maximum_draw. One typed collection onDcimGenericModule.portsrather than five parallel relationships.port_typeisText, notDropdown. NetBox uses well over a hundred type slugs across the three lists; aDropdownfails the load on every slug not enumerated.module__computed_name__value, notserial_number. The pre-rebase version used the module's serial number. Schema library v2 #75 madeDcimGenericModule.serial_numberoptional and non-unique, so it can no longer key anything;computed_nameis unique and mandatory.{module}token verbatim. A template is not bound to a bay, so the token cannot be resolved at import time. Substituting it and creating the real device interfaces is a generator step once the module is installed — the traversal a generator needs is documented in the file.experimental/modules_linecards/linecard.ymlgenerate_templateonDeviceLinecard, so a module type can be imported as a reusable blueprint rather than as an installed card.DeviceLinecard.slotbecomes optional. A NetBox module type describes a model rather than an installed card and carries no slot, so a mandatory slot made every imported module type unloadable.objects/extensions/{device_module,device_psu_module}Quote the demo bay positions, now that
positionisText.Docs
Regenerated with
invoke docs.generate— unlike the pre-rebase version of this PR, which skipped them.Verification
Full CI-equivalent schema load against a live Infrahub (
latest):invoke schemas.load-all-schemasloads all 57 extensions,All good! ✨.Bay positions round-trip — the real DCS-7508N and A9K-AC-PEM-V3 values:
The
bay_labelnaming is load-bearing, probed with a throwaway node carrying both alabelattribute and a control:An attribute named
labelis auto-populated fromnameand title-cased.bay_labelcorrectly reads backNonewhere NetBox supplied nothing.Module templating works end to end.
TemplateDcimDevice,TemplateDcimModuleBay,TemplateDcimModulePortandTemplateDeviceLinecardall generate. Creating the realDCS-7500R-36CQline card as a template, with all 36 interfaces from the fixture:(
first / lastis lexical, hence/9/1last; the fixture declaresEthernet{module}/1/1throughEthernet{module}/36/1.)Note
module_bay: None—DcimGenericModule.module_bayis a mandatory relationship, but Infrahub relaxes mandatory relationships on generated templates the same way it omits unique attributes, so a module type templates fine without being installed anywhere.yamllint,markdownlintandfind_cycles.pyclean.Notes for reviewers
extensions/device_module/device_module.ymland its demo objects). That is deliberate: keeping the v2DcimModuleBayand adding a second, near-identical bay node would ship two overlapping models. If you would rather theposition/bay_labelchange be argued separately from the newmodule_portextension, say so and I will split it.DcimDeviceType.weightis untouched, but it has a known sharp edge. With no float kind, importers round to whole kilograms — which rounds roughly 300 published device types (sub-500 g transceivers and access points) to0, and a zero looks like data. Fixing it properly means aweight_gramsattribute onDcimDeviceTypetoo, mirroring what this adds for modules. Left out to avoid two competing weight attributes in the core schema without a maintainer decision; happy to add it.uniquedoes not take effect on an already-loaded branch. Re-loading a corrected schema onto a branch that already hadunique: trueleaves the constraint in place; only a fresh branch picks it up. No longer this PR's concern (Schema library v2 #75 shipspart_numbernon-unique), but worth knowing for anyone migrating an existing instance.main, not fixed here.invoke docs.generateoverwrites hand-written notes inextensions/{location_minimal,location_site,rack}/README.md, anddocs/docs/reference/security.mdxis stale against its schema (it still saysInfraIPAddress/InfraGenericDevicewhereexperimental/security/security.ymlhas saidIpamIPAddress/DcimGenericDevicesince d5ae01b). Both reverted out of this branch to keep the diff honest; both worth a separate fix.