From dc9ec121e60364a7da4f1932560b78554f2915cc Mon Sep 17 00:00:00 2001 From: Pete Crocker Date: Sun, 2 Aug 2026 21:12:25 +0100 Subject: [PATCH] feat(dcim): support NetBox device-type and module-type imports 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. --- .metadata.yml | 11 ++ docs/docs/home.mdx | 1 + docs/docs/reference/device_module.mdx | 22 ++- docs/docs/reference/module_port.mdx | 153 ++++++++++++++++++ docs/docs/reference/modules_linecards.mdx | 4 +- experimental/modules_linecards/linecard.yml | 7 + extensions/device_module/device_module.yml | 33 +++- extensions/module_port/README.md | 3 + extensions/module_port/module_port.yml | 149 +++++++++++++++++ .../device_module/device_module.yml | 6 +- .../device_module_psu/device_module_psu.yml | 4 +- 11 files changed, 378 insertions(+), 15 deletions(-) create mode 100644 docs/docs/reference/module_port.mdx create mode 100644 extensions/module_port/README.md create mode 100644 extensions/module_port/module_port.yml diff --git a/.metadata.yml b/.metadata.yml index e08f946e..ff1feeac 100644 --- a/.metadata.yml +++ b/.metadata.yml @@ -229,6 +229,17 @@ extensions/mlag: Not covered yet: the layer 3 overlay for MLAG interfaces (loopback, peer address ...) and surfacing MLAG interfaces on each device in the domain. name: MLAG +extensions/module_port: + dependencies: + - base + - extensions/device_module + description: | + This schema extension adds module ports: the ports a module provides, as declared by its module type - what NetBox module-type definitions list under `interfaces`, `console-ports` and `power-ports`. + + These are deliberately not DcimInterface objects. DcimInterface.device is a mandatory Parent, and Infrahub requires the relationships used in a uniqueness constraint to be mandatory, so an interface cannot hang off a module instead of a device. A DcimModulePort is a declaration parented by the module, carrying the port name, its category (interface, console, power, front, rear), the NetBox type slug, and power draw. + + NOTE: port names keep NetBox's `{module}` bay-position token verbatim, because a template is not bound to a bay. Substituting it and creating the real device interfaces is a generator step once the module is installed. + name: Module Port extensions/optical_multiplexer: dependencies: - base diff --git a/docs/docs/home.mdx b/docs/docs/home.mdx index a82ecea8..e91ca9da 100644 --- a/docs/docs/home.mdx +++ b/docs/docs/home.mdx @@ -124,6 +124,7 @@ This list provides an overview of the schemas available in this repository. Each | **[Location Minimal](./reference/location_minimal.mdx)** | This schema extension provides a self-contained Region -> Country -> Metro -> Site hierarchy for storing location data, with the Site carrying facility, physical address, timezone and status. Its Site node is the same as the one in extensions/location_site, so the two can be loaded together. A location name is unique across every tier, so a single-country deployment should enter the hierarchy at Country, with Region as the national node, rather than repeating a country under several regions. | | **[Location Site](./reference/location_site.mdx)** | This schema extension introduces a Site node with facility, physical address, timezone and status, for deployments that want a flat list of sites without a hierarchy. It is the same Site node as in extensions/location_minimal, which adds Region, Country and Metro tiers above it. | | **[MLAG](./reference/mlag.mdx)** | This schema extension contains the foundations to capture Multi-Chassis Link Aggregation Groups (MLAG). It comes on top of the LAG extension. In this implementation, a MLAG interface is essentially a LAG interface but linked to a MLAG domain (instead of a device). The MLAG domain regroups devices together (usually 2) and is built over LAG interfaces used as peer-link between the devices. MLAG interfaces defined at the MLAG domain level are then spread across all devices in the domain. This is a deliberately minimal implementation of MLAG, meant to blend with models you already have. For example, in a data center fabric you might already have a LeafGroup or similar concept: have it inherit from GenericMlagDomain and add the relationships and attributes you need. Not covered yet: the layer 3 overlay for MLAG interfaces (loopback, peer address ...) and surfacing MLAG interfaces on each device in the domain. | +| **[Module Port](./reference/module_port.mdx)** | This schema extension adds module ports: the ports a module provides, as declared by its module type - what NetBox module-type definitions list under `interfaces`, `console-ports` and `power-ports`. These are deliberately not DcimInterface objects. DcimInterface.device is a mandatory Parent, and Infrahub requires the relationships used in a uniqueness constraint to be mandatory, so an interface cannot hang off a module instead of a device. A DcimModulePort is a declaration parented by the module, carrying the port name, its category (interface, console, power, front, rear), the NetBox type slug, and power draw. NOTE: port names keep NetBox's `{module}` bay-position token verbatim, because a template is not bound to a bay. Substituting it and creating the real device interfaces is a generator step once the module is installed. | | **[Optical Multiplexer](./reference/optical_multiplexer.mdx)** | This schema extension models optical add-drop multiplexers (OADM) and the wavelength division multiplexing (WDM) channels they carry, for both CWDM and DWDM. It adds an Optical Multiplexer device with front and rear interfaces, a WDM Channel node holding channel number, wavelength and frequency, and a WDM Transceiver flavour of the transceiver model tuned to a channel. Some vendors configure tunable optics by wavelength or frequency rather than channel number; the WDM Channel node gives you a single entry in Infrahub for all three. Not designed to be loaded together with experimental/optical_transport, which covers the same domain in more depth. | | **[Patch Panel](./reference/patch_panel.mdx)** | This schema extension allows you to capture patch panel related information like rear and front interfaces and the mapping between them. You can insert the patch panel into a rack and leverage the device type model. Cassettes and other inserts are tracked as regular device modules in module bays, through extensions/device_module. The front and rear interfaces accept all sorts of connectors, so you can plug cables, circuits and cross-connects into them. | | **[Physical Disk](./reference/physical_disk.mdx)** | Simple schema allowing you to capture physical disk information for inventory and lifecycle management. This extension works with any kind of device: apply the DcimDeviceWithPhysicalDisks generic to a model to enable disk tracking. You might also link disks to a location, for instance to capture spares. | diff --git a/docs/docs/reference/device_module.mdx b/docs/docs/reference/device_module.mdx index 7d7865bf..2a7c103a 100644 --- a/docs/docs/reference/device_module.mdx +++ b/docs/docs/reference/device_module.mdx @@ -29,7 +29,8 @@ It ships a ready-to-use Module and Module Type pair, plus the generic Module and | ---- | ----------- | ---- | -------- | ------------- | ------- | | computed_name | Name computed from the device and bay name. | Text | False | | | | name | Name of the bay, e.g. 'slot 1' or 'psu 1'. | Text | False | | | -| position | Numeric position of the bay within the device (e.g. slot 1, 2, 3). | Number | True | | | +| position | Position of the bay within the device, e.g. '1', 'F3' or 'PSU-2'. | Text | True | | | +| bay_label | What the bay is for, for example 'Supervisor' or 'Line Card'. | Text | True | | | | description | | Text | True | | | | role | The role of the module bay, indicating the type of module it is intended to receive. | Dropdown | True | | supervisor, line_card, power_supply, fan | @@ -110,6 +111,7 @@ It ships a ready-to-use Module and Module Type pair, plus the generic Module and | name | Name of the module type. | Text | False | | | | description | Description of the module type. | Text | True | | | | part_number | Part number of the module. | Text | True | | | +| weight_grams | Weight of the module in grams. | Number | True | | | #### Relationships @@ -241,6 +243,12 @@ generics: optional: true description: Part number of the module. order_weight: 1200 + - name: weight_grams + label: Weight (g) + kind: Number + optional: true + description: Weight of the module in grams. + order_weight: 1300 relationships: - name: manufacturer peer: OrganizationManufacturer @@ -284,12 +292,16 @@ nodes: description: Name of the bay, e.g. 'slot 1' or 'psu 1'. order_weight: 1000 - name: position - kind: Number + kind: Text optional: true - parameters: - min_value: 1 - description: Numeric position of the bay within the device (e.g. slot 1, 2, 3). + description: Position of the bay within the device, e.g. '1', 'F3' or 'PSU-2'. order_weight: 1050 + - name: bay_label + label: Bay Label + kind: Text + optional: true + description: What the bay is for, for example 'Supervisor' or 'Line Card'. + order_weight: 1060 - name: description kind: Text optional: true diff --git a/docs/docs/reference/module_port.mdx b/docs/docs/reference/module_port.mdx new file mode 100644 index 00000000..fd667ec1 --- /dev/null +++ b/docs/docs/reference/module_port.mdx @@ -0,0 +1,153 @@ +--- +title: Module Port +--- + +This schema extension adds module ports: the ports a module provides, as declared by its module type - what NetBox module-type definitions list under `interfaces`, `console-ports` and `power-ports`. + +These are deliberately not DcimInterface objects. DcimInterface.device is a mandatory Parent, and Infrahub requires the relationships used in a uniqueness constraint to be mandatory, so an interface cannot hang off a module instead of a device. A DcimModulePort is a declaration parented by the module, carrying the port name, its category (interface, console, power, front, rear), the NetBox type slug, and power draw. + +NOTE: port names keep NetBox's `{module}` bay-position token verbatim, because a template is not bound to a bay. Substituting it and creating the real device interfaces is a generator step once the module is installed. + +## Details + +- **Dependencies:** + - [base](dcim) + - [extensions/device_module](device_module) + +## Nodes + +### ModulePort + +- **Label:** Module Port +- **Description:** A port provided by a module, as declared by its module type. +- **Namespace:** Dcim +- **Icon:** mdi:ethernet +- **Uniqueness Constraints:** + - module, name__value +- **Human Friendly ID:** module__computed_name__value, name__value + +#### Attributes + +| name | description | kind | optional | default_value | choices | +| ---- | ----------- | ---- | -------- | ------------- | ------- | +| name | Port name as declared by the module type, e.g. `Ethernet{module}/1`. | Text | False | | | +| category | Which NetBox component list this port came from. | Dropdown | | interface | interface, console, power, front, rear | +| port_type | NetBox type slug, e.g. '1000base-t', 'rj-45', 'iec-60320-c14'. | Text | True | | | +| mgmt_only | Whether the port is reserved for out-of-band management. | Boolean | | False | | +| maximum_draw | Maximum power draw, for power ports. | Number | True | | | + +#### Relationships + +| name | peer | optional | cardinality | kind | +| ---- | ---- | -------- | ----------- | ---- | +| module | DcimGenericModule | False | one | Parent | + +## Extensions + +:::note + +In this context "extensions" refer to modifications or additions to the existing schema, such as adding new attributes, relationships, or other schema elements. + +::: + +### DcimGenericModule + +#### Relationships + +| name | peer | optional | cardinality | kind | +| ---- | ---- | -------- | ----------- | ---- | +| ports | DcimModulePort | True | many | Component | + +## Code + +```yaml +version: '1.0' +nodes: +- name: ModulePort + namespace: Dcim + label: Module Port + description: A port provided by a module, as declared by its module type. + icon: mdi:ethernet + include_in_menu: false + menu_placement: DcimGenericModule + display_label: name__value + order_by: + - module__computed_name__value + - name__value + human_friendly_id: + - module__computed_name__value + - name__value + uniqueness_constraints: + - - module + - name__value + attributes: + - name: name + kind: Text + optional: false + description: Port name as declared by the module type, e.g. `Ethernet{module}/1`. + order_weight: 1000 + - name: category + kind: Dropdown + description: Which NetBox component list this port came from. + default_value: interface + order_weight: 1100 + choices: + - name: interface + label: Interface + description: A network interface. + color: '#A9CCE3' + - name: console + label: Console Port + description: A console port. + color: '#E2D4C6' + - name: power + label: Power Port + description: A power inlet. + color: '#F4CCCC' + - name: front + label: Front Port + description: A front-facing pass-through port. + color: '#D2B4DE' + - name: rear + label: Rear Port + description: A rear-facing pass-through port. + color: '#B4E0DC' + - name: port_type + label: Port Type + kind: Text + optional: true + description: NetBox type slug, e.g. '1000base-t', 'rj-45', 'iec-60320-c14'. + order_weight: 1200 + - name: mgmt_only + label: Management Only + kind: Boolean + default_value: false + description: Whether the port is reserved for out-of-band management. + order_weight: 1300 + - name: maximum_draw + label: Maximum Draw (W) + kind: Number + optional: true + description: Maximum power draw, for power ports. + order_weight: 1400 + relationships: + - name: module + peer: DcimGenericModule + identifier: module__port + optional: false + cardinality: one + kind: Parent + order_weight: 1050 +extensions: + nodes: + - kind: DcimGenericModule + relationships: + - name: ports + peer: DcimModulePort + identifier: module__port + optional: true + cardinality: many + kind: Component + order_weight: 1600 + +``` \ No newline at end of file diff --git a/docs/docs/reference/modules_linecards.mdx b/docs/docs/reference/modules_linecards.mdx index cfc74055..7bc110af 100644 --- a/docs/docs/reference/modules_linecards.mdx +++ b/docs/docs/reference/modules_linecards.mdx @@ -38,7 +38,7 @@ This schema extension allows you to capture Linecard related information like th | name | description | kind | optional | default_value | choices | | ---- | ----------- | ---- | -------- | ------------- | ------- | -| slot | The slot number where the Linecard is installed within the device | Number | | | | +| slot | The slot number where the Linecard is installed within the device | Number | True | | | | bng_enabled | BNG activated or deactivated on the Linecard | Boolean | True | False | | #### Relationships @@ -122,11 +122,13 @@ nodes: label: Linecard icon: bi:pci-card menu_placement: DcimGenericModule + generate_template: true inherit_from: - DcimGenericModule attributes: - name: slot kind: Number + optional: true description: The slot number where the Linecard is installed within the device order_weight: 1050 - name: bng_enabled diff --git a/experimental/modules_linecards/linecard.yml b/experimental/modules_linecards/linecard.yml index dfa4ce06..cde4a4ec 100644 --- a/experimental/modules_linecards/linecard.yml +++ b/experimental/modules_linecards/linecard.yml @@ -30,11 +30,18 @@ nodes: label: "Linecard" icon: "bi:pci-card" menu_placement: DcimGenericModule + # Generates TemplateDeviceLinecard, so a NetBox module type can be + # imported as a reusable blueprint rather than as an installed card. + generate_template: true inherit_from: - DcimGenericModule attributes: - name: slot kind: Number + # Optional: a NetBox module type describes a model, not an installed + # card, so it carries no slot. A mandatory slot makes every imported + # module type unloadable. + optional: true description: "The slot number where the Linecard is installed within the device" order_weight: 1050 - name: bng_enabled diff --git a/extensions/device_module/device_module.yml b/extensions/device_module/device_module.yml index 503666e3..5703a1b9 100644 --- a/extensions/device_module/device_module.yml +++ b/extensions/device_module/device_module.yml @@ -111,6 +111,18 @@ generics: optional: true description: "Part number of the module." order_weight: 1200 + - name: weight_grams + label: Weight (g) + kind: Number + optional: true + # Grams, not kilograms. 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. Grams keep every published module weight distinct + # and sortable. + description: "Weight of the module in grams." + order_weight: 1300 relationships: - name: manufacturer peer: OrganizationManufacturer @@ -154,12 +166,25 @@ nodes: description: "Name of the bay, e.g. 'slot 1' or 'psu 1'." order_weight: 1000 - name: position - kind: Number - parameters: - min_value: 1 + kind: Text optional: true - description: "Numeric position of the bay within the device (e.g. slot 1, 2, 3)." + # Text, not Number: bay positions are free-form. A DCS-7508N uses + # '1'..'10' but also 'F1'..'F6' and 'PSU-1'..'PSU-8', so a Number + # attribute would reject 14 of its 24 bays. + description: "Position of the bay within the device, e.g. '1', 'F3' or 'PSU-2'." order_weight: 1050 + - name: bay_label + label: Bay Label + kind: Text + optional: true + # NOT named `label`. Infrahub auto-populates an attribute literally + # named `label` from `name` when it is unset - and title-cases it, so + # "no label supplied" becomes indistinguishable from "the label equals + # the name". On a DCS-7508N only 10 of 24 bays carry one, so the + # distinction is worth keeping. Free text, unlike `role` below, which + # enumerates the bay's purpose. + description: "What the bay is for, for example 'Supervisor' or 'Line Card'." + order_weight: 1060 - name: description kind: Text optional: true diff --git a/extensions/module_port/README.md b/extensions/module_port/README.md new file mode 100644 index 00000000..026f5507 --- /dev/null +++ b/extensions/module_port/README.md @@ -0,0 +1,3 @@ +# module_port + +Please refer to the [reference page](https://docs.infrahub.app/schema-library/reference/module_port) for the corresponding documentation. diff --git a/extensions/module_port/module_port.yml b/extensions/module_port/module_port.yml new file mode 100644 index 00000000..af107c4b --- /dev/null +++ b/extensions/module_port/module_port.yml @@ -0,0 +1,149 @@ +--- +# yaml-language-server: $schema=https://schema.infrahub.app/infrahub/schema/latest.json +# --------------------------------------------------------------------------- +# This schema is a starting point for building with Infrahub, not a finished production model. +# Adapting it for your environment typically requires architectural review, see +# docs.infrahub.app, or reach out to OpsMill for help. +# --------------------------------------------------------------------------- +# +# Module ports — the ports a module provides, as declared by its module type. +# +# Why these are NOT DcimInterface: +# DcimInterface.device is a mandatory Parent, and Infrahub requires the +# relationships used in uniqueness_constraints to be mandatory. Relaxing it +# so an interface could hang off a module instead fails outright with +# "DcimInterface.uniqueness_constraints: cannot use device relationship, +# relationship must be mandatory", and would also break the +# device__name__value human_friendly_id. So a module's ports cannot be +# modelled as device interfaces. +# +# What this is instead: a declaration. A module port records the port a module +# provides, parented by the module. It carries NetBox's `{module}` token +# verbatim in `name` — a template is not bound to a bay, so the token cannot +# be resolved at import time. Materialising these as real InterfacePhysical +# objects on the device, with `{module}` replaced by the bay position, is a +# generator's job at install time; see the note at the bottom. + +version: "1.0" + +nodes: + - name: ModulePort + namespace: Dcim + label: Module Port + description: "A port provided by a module, as declared by its module type." + icon: mdi:ethernet + include_in_menu: false + menu_placement: DcimGenericModule + display_label: name__value + order_by: + - module__computed_name__value + - name__value + human_friendly_id: + # Keyed on the module's computed_name, not its serial_number: + # DcimGenericModule.serial_number is optional and not unique, so it + # cannot key anything. computed_name is unique and mandatory. + - module__computed_name__value + - name__value + uniqueness_constraints: + - [module, name__value] + attributes: + - name: name + kind: Text + optional: false + # The `{module}` token stays inside backticks: this description is + # rendered verbatim into a Markdown table in the generated MDX, and + # MDX parses a bare {...} as a JSX expression - `module` resolves to + # the MDX module object and the docs build fails with "Objects are + # not valid as a React child". + description: "Port name as declared by the module type, e.g. `Ethernet{module}/1`." + order_weight: 1000 + - name: category + kind: Dropdown + description: "Which NetBox component list this port came from." + default_value: interface + order_weight: 1100 + choices: + - name: interface + label: Interface + description: "A network interface." + color: "#A9CCE3" + - name: console + label: Console Port + description: "A console port." + color: "#E2D4C6" + - name: power + label: Power Port + description: "A power inlet." + color: "#F4CCCC" + - name: front + label: Front Port + description: "A front-facing pass-through port." + color: "#D2B4DE" + - name: rear + label: Rear Port + description: "A rear-facing pass-through port." + color: "#B4E0DC" + - name: port_type + label: Port Type + kind: Text + optional: true + # Text, not Dropdown. NetBox uses well over a hundred type slugs + # across interfaces, console and power ports (1000base-t, rj-45, + # iec-60320-c14, ...). A Dropdown would fail the load on every slug + # not enumerated; Text trades UI validation for coverage. + description: "NetBox type slug, e.g. '1000base-t', 'rj-45', 'iec-60320-c14'." + order_weight: 1200 + - name: mgmt_only + label: Management Only + kind: Boolean + default_value: false + description: "Whether the port is reserved for out-of-band management." + order_weight: 1300 + - name: maximum_draw + label: Maximum Draw (W) + kind: Number + optional: true + description: "Maximum power draw, for power ports." + order_weight: 1400 + relationships: + - name: module + peer: DcimGenericModule + identifier: module__port + optional: false + cardinality: one + kind: Parent + order_weight: 1050 + +extensions: + nodes: + # The Component half. On the DcimGenericModule generic so every concrete + # module kind (DcimModule, DeviceLinecard, DevicePsuModule and any + # sibling) gets ports, and so any of them that declares generate_template + # gets a TemplateDcimModulePort to nest under its module template. + - kind: DcimGenericModule + relationships: + - name: ports + peer: DcimModulePort + identifier: module__port + optional: true + cardinality: many + kind: Component + order_weight: 1600 + +# Resolving {module} +# ------------------ +# A DcimModulePort keeps the token form. Turning it into real ports on a +# device needs the bay position, which is only known once the module is +# installed, so it is a generator step rather than a template one: +# +# for bay in device.module_bays: +# module = bay.installed_module +# for port in module.ports: +# if port.category == "interface": +# create InterfacePhysical( +# device=device, +# name=port.name.replace("{module}", bay.position), +# ...) +# +# That keeps DcimInterface's invariants intact: the created interfaces belong +# to the device, exactly as every other interface does. diff --git a/objects/extensions/device_module/device_module.yml b/objects/extensions/device_module/device_module.yml index 7dee2553..0d81463e 100644 --- a/objects/extensions/device_module/device_module.yml +++ b/objects/extensions/device_module/device_module.yml @@ -41,7 +41,7 @@ spec: # match the existing nyc1-rtr01 fixture exactly, so this upserts/matches # it instead of creating a duplicate. - name: "slot 1" - position: 1 + position: "1" description: "Primary route processor slot." device: &nyc1_rtr01 kind: DcimDevice @@ -54,12 +54,12 @@ spec: site: NYC1 - name: "slot 2" - position: 2 + position: "2" description: "Secondary route processor slot." device: *nyc1_rtr01 - name: "fan tray 1" - position: 3 + position: "3" description: "Fan tray slot." device: *nyc1_rtr01 diff --git a/objects/extensions/device_module_psu/device_module_psu.yml b/objects/extensions/device_module_psu/device_module_psu.yml index b511afc2..ec12df1a 100644 --- a/objects/extensions/device_module_psu/device_module_psu.yml +++ b/objects/extensions/device_module_psu/device_module_psu.yml @@ -50,7 +50,7 @@ spec: # New bays, distinct from the existing "slot 1"/"slot 2"/"fan tray 1" # (already occupied), used below to install the PSU modules. - name: "PSU slot 1" - position: 4 + position: "4" description: "Primary power supply slot." device: &nyc1_rtr01 kind: DcimDevice @@ -63,7 +63,7 @@ spec: site: NYC1 - name: "PSU slot 2" - position: 5 + position: "5" description: "Secondary power supply slot." device: *nyc1_rtr01