Conversation
Deploying schema-library with
|
| Latest commit: |
1c4d1b7
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://89a78266.schema-library.pages.dev |
| Branch Preview URL: | https://ic-add-otn-to-schema-v2-2eca.schema-library.pages.dev |
Both schemas covered the same domain and each warned against loading the other. They are replaced by extensions/otn, which models the optical transport network in its own namespace. BREAKING CHANGE: extensions/optical_multiplexer was a stable extension. Deployments loading it must migrate to extensions/otn.
The monitor kinds modelled readings, not intended state, and inherited OtnGenericPort so a device's ports list mixed interfaces with measurement snapshots. The optical path and hop budget fields were an optical planning tool's output, mandatory and recomputed whenever a span loss changed. The service refusal fields were a provisioning workflow no generator here runs. None of it had a producer in this library. OtnService.customer now points at OrganizationGeneric rather than carrying a free-text name. BREAKING CHANGE: removes OtnMonitor, OtnChannelMonitor, OtnAmplifierMonitor, OtnRoadmDegreeMonitor, OtnMuxDemuxMonitor, OtnRamanMonitor and OtnReceiverMonitor, and changes OtnService.customer from an attribute to a relationship.
Two comments opened by restating the description below them, one cited the demo's design history, and the inverse-relationship rule sat below the identifiers it explains. The variable attenuator note pointed its relative clause at the wrong attribute.
The library declares on_delete only when the answer is cascade, so the exceptional cases are the ones a reader finds. This file stated the default 65 times, which hid the two relationships that really do cascade.
OtnOpticalPath.service was mandatory but modelled as a cross-reference, so deleting a service left its paths behind with the link unset. Component and Parent with cascade makes the ownership explicit, and the delete now reaches the hops each path already owns.
LocationSite already inherits a devices relationship from LocationHosting, peering DcimPhysicalDevice, so adding a second one named devices would have put two GraphQL fields of the same name on one node. It is renamed otn_devices, matching the otn_facility rename beside it, and keeps its identifier so the forward side is unchanged. site_type is no longer mandatory. LocationSite is shared across this library, and a mandatory OTN field would have declared every site in an estate a PoP. The block's attribute order weights move to 1600, 1700 and 1800, clear of the weights LocationSite already carries, and its relationships are listed in ascending weight order. BREAKING CHANGE: LocationSite.devices added by extensions/otn is now LocationSite.otn_devices.
Six port kinds restated the connector_type Dropdown byte for byte from the generic they inherit it from, which is the hazard the generic's own comment warned about. The six remaining Text plus enum attributes become Dropdowns, so every closed vocabulary in the extension is a Dropdown with labels. element_class no longer describes an optical budget engine, which this library does not ship.
…y site is a PoP The extension had fourteen top-level sidebar entries. Nine kinds now nest under the five a user actually lands on, matching how patch_panel, modules_linecards and routing_ospf nest their own kinds. site_type no longer defaults to pop. LocationSite is shared across this library, and an optional attribute with a default still applies it on create, so loading OTN was declaring every site in an estate a PoP. A site with no stated OTN role now reports nothing.
Three top-level entries instead of five. A pluggable is fitted into a device port and a carrier realises a service, so both nest where the relationship already exists. This library ships no menu file, so a single named OTN heading is not available; nesting is what the automatic sidebar offers, and depth three is what routing and patch panel already use.
OTN shipped its own transceiver inventory beside extensions/transceiver, so a user had two places to record one module and the sidebar showed two Transceiver entries. OtnTransceiver is gone. DcimGenericTransceiver now carries otn_port, where the module is fitted, because no OTN port is a DcimEndpoint and interface cannot serve, and otn_type, which part it is. The part catalogue stays on the OTN side: OtnTransceiverType references optical modes, so moving it into extensions/transceiver would make that extension depend on this one. Its vendor Text becomes a relationship to OrganizationManufacturer, matching the Dcim field. BREAKING CHANGE: OtnTransceiver is removed. Record an optical pluggable as a DcimStandardTransceiver with otn_port and otn_type set.
…ratings The outside plant had no operational state, so a span or a section could not be marked planned or under maintenance while a device could. A service could not carry a protect path beside its working one, because OtnOpticalPath had no role and its uniqueness constraint allowed one path per sequence. Both were modelled by the extension this branch replaces. OtnService regains maintenance and failed, OtnOpticalCarrier gains reserved so a wavelength can be held before it is lit, and OtnAmplifier gains its nameplate type, stage and output ceiling. The dense grid's scope is now stated: one 50 GHz C band plan, with L band, C plus L and flexgrid out of scope.
objects/extensions/dwdm never existed, so that mention is a pre-existing error rather than something this change made stale. It is fixed separately, outside this branch.
Five gaps the removed extensions covered and this one did not. Capacity gives utilisation a denominator, so occupied channels can be read against a nameplate. The CDC flags are planning inputs for which wavelength can be added where. The three dates are the extension's first, and they record intended state rather than a reading: a commissioning date is entered once, unlike a measurement, which is why the monitoring exclusion still holds. Degree direction and the express role restore how operators label a ROADM's degrees, and external_circuit_id gives a partner's own reference somewhere to live beside our name for the circuit.
b92d55c to
8276299
Compare
48e3869 to
af60790
Compare
Every OTN port kind now inherits DcimEndpoint, so extensions/cable terminates on optical gear and an intra-site jumper is a DcimCable rather than a port attribute. OtnGenericPort.connected_to is gone: in the G.872 layering a section owns its adjacency and a port only terminates it, so the cable, OtnFiberSpan.terminating_ports and OtnOpticalPath already answer that question at their own layers. A cardinality-one symmetric edge could model neither a 1:N splitter nor a unidirectional element, and it flattened the panel out of a run that physically passes through one. Removes two attributes that restated what the graph already held. element_class duplicated the node kind and could contradict it, since an OtnMuxDemux was free to declare itself a roadm. OtnFrequencyGrid stored channel_number beside center_frequency_mhz with the formula living only in a description, and the demo data had already drifted, pairing channel 21 with 192.1 THz, which is channel 16 on the 50 GHz plan this extension models. channel_number and OtnCwdmChannel.band are computed now, so neither can disagree with the quantity it derives from. Computed attributes are Text or URL only, so the grid's identity moves to center_frequency_mhz, which stays a Number and keeps its range filter. An optical multiplex section terminates on the new OtnOmsEndpoint generic instead of OtnRoadm, so a fixed point-to-point system built from passive multiplexers is modellable, and with it the amplifier chain and the carrier sections that hang off a section. OtnRouter becomes an OtnOpticalElement, so an IPoDWDM path can hop through the routers on its own ends and a router carries the vendor and model every other device kind has. Adds plan, mux_role and technology to OtnMuxDemux, which gives a fixed OADM a home; technology to OtnRoadm; description to OtnGenericPort; and a derived centre wavelength to the dense grid. BREAKING CHANGE: element_class, connected_to and the stored channel_number are removed, and OtnOpticalMultiplexSection.roadm_a and roadm_b become endpoint_a and endpoint_b. The Dropdown to Text changes cannot be applied over an instance carrying the previous schema, which fails with "Can only specify 'choices' for kind=Dropdown"; load onto a fresh instance instead.
An OtnPathHop now carries an `action` and an ingress and egress port, so a hop states what the element does to the carrier and across which port pair. On a ROADM that pair is the cross-connect, which the model could not express before: the path knew which elements the light crossed but not which degree or add/drop port it entered on and left by, and `add` and `drop` had no representation at all. Both ports are optional, so a hop through an element whose ports are not modelled still records the order of travel. The inverses live on OtnGenericPort as `hops_ingress` and `hops_egress`, so a ROADM's switching state reads from its own ports rather than only by walking every service's path. A hop pair is also now unique per path position, since `path` plus `sequence` is a uniqueness constraint. Replaces OtnService.service_profile with `service_type` on the wavelength, transport and IP transit axis. The old dropdown encoded one deployment's customer taxonomy, which does not belong in a shared library; `sla` and `max_latency_ns` already carry the commitments and `client_signal` and `containers` carry the client layer. Keeps OtnPatchPanel, which an earlier review had proposed removing. It is the optical face of a frame and the only way a panel can be a lossy hop on a path, so removing it would lose that. The terminations belong on the physical side instead, where extensions/patch_panel models the front and rear interfaces and the mapping between them, and a comment now says so and says to leave `ports` empty. BREAKING CHANGE: OtnService.service_profile is replaced by service_type, whose values are unrelated to the old ones.
The demo data validated a forty-kind model with one straight-line service: one wavelength, one span, one path. Most of what the model can express went unexercised, including everything added on this branch. It now carries a second scenario built from the same two sites. A far-end ROADM at SJC1, so a wavelength has somewhere to be dropped and a section has two ends that can terminate it. Two conduits on separate routes and a second, longer span in the southern one, so diversity is a property of the plant rather than a label. Three multiplex sections, one of which runs between two passive coarse multiplexers with no ROADM at either end, which is the case OtnOmsEndpoint was added for. A two-stage amplifier chain on the north section, ordered by oms_sequence. A coarse pair carrying two CWDM wavelengths, whose bands derive from the wavelength. And the service now has a working path over the north route and a protect path over the south, both at segment position 1, distinguished only by path_role, which is what the third term of that uniqueness constraint is for. Each hop names its action and its port pair, so both routes read as cross-connect chains. Adds OtnSplitter and OtnSplitterPort. Optical line protection is built from a coupler, and the model had no way to express one: element_class carried a `splitter` value with no matching kind, and removing that attribute took the last trace of the concept with it. The split loss stays in insertion_loss_mdb, since a ratio alone does not give it. OtnAmplifier.oms_sequence becomes optional, matching OtnFiberSpan. Both oms_a2b and oms_b2a are optional, so an amplifier sitting in no chain should not have to claim a position in one. Records four omissions in .metadata.yml that a reader had to discover: protection mechanisms, the OTU and OPU layers, the absence of a record-of-design figure on a path, and that device types and rack elevations are reached through dcim_device rather than modelled natively.
Both ROADMs now carry a physical record through dcim_device: a DcimDevice at a rack unit on a LocationRack, with a DcimDeviceType. The extension documents that route as how device types and rack elevations are reached, and nothing in the sample data demonstrated it. LocationRack and DcimDeviceType are created here rather than added to this extension's dependencies, which is what nine other extensions' object files already do for LocationRack. The sample also labelled every optical device Cisco. Cisco does build ROADMs, in the NCS 2000 line, but an all-one-vendor network reads as placeholder data. The line system, transponders, amplifiers and dense multiplexer are Ciena, the passive coarse pair and the protection coupler are Adtran, and Cisco keeps the grey client pluggable, where a third-party optic is ordinary. Names stay at platform granularity rather than inventing card codes, and the dense multiplexer's channel_capacity now matches the CMD44 it names.
The ODU and container layer was the part of the model that nothing in the sample data touched, which left the deepest part of G.709 described but never loaded. The 400G wavelength now carries an ODUC4 offering 320 tributary slots, with one ODU4 taking a 100GbE client directly by GMP and a second ODU4 multiplexing a lower-order ODU2 that carries an STM-64 by BMP. Slot counts are the G.709 figures the schema descriptions cite: an ODU4 takes 80 slots in an ODUC4 and offers 80 to its own children, an ODU2 takes 8 of those. Parent and child edges are exercised two levels deep, which is what the directional self-relationship on OtnContainer is for. The service becomes `transport` and names its headline client signal. A service whose payload is groomed into containers is not a whole lambda handed over, so `wavelength` contradicted its own data. Also fills the last of the untouched relationships: the carrier names its optical mode and both sections it traverses, the north section gains its return-direction amplifier chain on `oms_b2a`, a distributed Raman pump sits on the long south span, an ODU cross-connect switches the carrier at the far end, and a coherent 400ZR pluggable joins the catalogue so a transceiver type has a mode to declare. Two optical modes carry the vendor figures for a transponder line side and for 400ZR. Sample data now exercises all 42 relationship identifiers this extension declares, up from 30. The client signal catalogue loads ahead of the service that references it, since object specs resolve in file order.
|
Not familiar enough with the use case to have a strong opinion, but that does seem pretty extensive. I do have two remarks:
The second point doesn’t need to be solved now; the first one might be more important. Curious to hear others’ opinions. |
|
Starting from the multiplexer kinds and following only inheritance and mandatory relationships, the closure is 10 kinds, and 4 of the 5 additional kinds are abstract generics (OtnGenericDevice, OtnGenericPort, OtnOpticalPort, OtnOpticalElement). So your instinct is right that this is separable; however, the blocker is that inherit_from is immutable once a node is defined. So whichever file defines OtnMuxDemux has to declare its full ancestry at that point. A standalone mux extension would therefore have to declare OtnOmsEndpoint and OtnOpticalElement itself, or OTN loses the ability to terminate a multiplex section on a passive mux, which is this PR's main structural fix. So maybe the approach should be: an otn_core of generics with otn_multiplexer (5 kinds), otn_plant (16) and otn_service (16) as peers on top, published as a marketplace collection (going to your second point). That is ok but I would rather do that as a follow-up (if we feel this is needed). One note on the consumption concern: OTN adds 43 kinds but only 3 top-level sidebar entries, so someone with a couple of muxes sees Devices, Fiber span and Service rather than a wall. |
…v2-2ecax # Conflicts: # .metadata.yml # docs/docs/home.mdx
Replaces
extensions/optical_multiplexerandexperimental/optical_transportwith a singleextensions/otn, ported fromopsmill/infrahub-demo-otnate98be9band reshaped to this library's conventions. 26 kinds out, 43 in: 6 generics and 37 nodes, namespaceOtn.The old two are removed rather than migrated. This is a new model of the domain.
Read this first
This is a starting point, not a production OTN model, in the sense the repo header means. It covers the physical plant, one fixed channel plan, the devices and their ports, carriers and end-to-end services. The omissions below are deliberate and recorded in
not_covered, but four of them would matter to an operator, so they are worth a decision rather than a skim.Two commits are breaking and cannot be loaded over an earlier version of this branch.
schema loadis additive: deleting an attribute from the YAML does not retire it from a live instance. TheDropdowntoTextchanges fail withCan only specify 'choices' for kind=Dropdownagainst a server holding the previous schema. Nothing here has ever been onmain, so no consumer is affected, but reviewers testing the branch need a fresh instance rather than an incremental load.Worth a look
LocationSiteis reused, extended through anextensions:block.facilityanddevicesbecomeotn_facilityandotn_devices, becauseLocationSitealready carries both, the second inherited fromLocationHosting.site_typeis optional with no default, so loading OTN does not label every site in an estate.DcimGenericTransceivergainsotn_portandotn_type.OtnTransceiverTypestays here because it references optical modes, so moving it would makeextensions/transceiverdepend on this extension.transceiver_typegains adr4choice: additive, and the only change to a stable extension.extensions/cable. All nine concrete port kinds inheritDcimEndpoint, so aDcimCableterminates on one and an intra-site jumper is a cable rather than a port attribute.OtnGenericPort.connected_tois gone with it: in the G.872 layering a section owns its adjacency and a port only terminates it, so the cable,OtnFiberSpan.terminating_portsandOtnOpticalPatheach answer that at their own layer. A cardinality-one symmetric edge could model neither a 1:N splitter nor a unidirectional element, and it flattened the panel out of a run that physically passes through one.dcim_device.OtnGenericDevice.dcim_devicereaches aDcimPhysicalDevicecarryingposition,rack_face, adevice_typeand alocationthat may be aLocationRack. The sample data racks both ROADMs, so the route is demonstrated rather than only described. Nothing keepsOtnGenericDevice.sitein agreement with the site above that rack, which is stated innot_covered.element_classduplicated the node kind and could contradict it, since anOtnMuxDemuxwas free to declare itself aroadm.OtnFrequencyGridstoredchannel_numberbesidecenter_frequency_mhzwith the formula living only in a description, and the demo data had already drifted, pairing channel 21 with 192.1 THz, which is channel 16 on the 50 GHz plan this extension models. The channel number andOtnCwdmChannel.bandare computed now and unwritable, so neither can disagree with what it derives from. Computed attributes areTextorURLonly, so the frequency stays the storedNumberand keeps its range filter, and the grid's identity moves to it.OtnOmsEndpointis implemented byOtnRoadmandOtnMuxDemux, so a fixed point-to-point system built from passive multiplexers is modellable, and with it the amplifier chain and the carrier sections that hang off a section. Before this,roadm_aandroadm_bpeeredOtnRoadmalone and that whole class of real system had no representation.actionof add, drop, express, through or terminate, plus an optional ingress and egress port. On a ROADM that pair is the cross-connect, which the model could not express: the path knew which elements the light crossed but not which degree or add/drop port it entered on and left by, and add and drop had no representation at all. The inverses sit onOtnGenericPort, so a ROADM's switching state reads from its own ports rather than only by walking every service.OtnMuxDemux.plannow says which plan a device is built for, andmux_rolegives a fixed OADM a home.OtnFiberSpan,OtnOpticalMultiplexSectionandOtnConduitcarrystatus;OtnOpticalPathcarriespath_role, with uniqueness widened to[[service, segment_sequence, path_role]]so a protect path sits beside its working one. Verified live: the second path is accepted, a duplicate is rejected by the constraint.OtnSplittermodels the coupler an optical protection scheme is built from.Deliberate omissions worth a decision
All are in
not_coveredand render on the reference page. These four are the ones an optical engineer would ask about.OtnFrequencyGridis one fixed 50 GHz plan across the C band, 191.35 to 196.10 THz, 96 channels. L band, C plus L, and then x 12.5 GHzslot model that 400ZR+ and 800G builds use are out of scope. Supporting them properly needs a plan node above the channels, which is why no per-channel spacing attribute was added.path_rolemarks a path working or protect andOtnDiversityGroupkeeps two services apart, but nothing states the scheme, so 1+1, 1:1, optical line protection, OMS protection and ODU SNCP are indistinguishable. Switching thresholds and hold-off timers go with it.OtnOpticalPathrecords which elements the light crosses, in what order and across which ports, but carries no loss, OSNR margin or latency for that route, so a turn-up figure has nowhere to live. Budgets are computed in a planning tool such as GNPy; the omission is that the result is not stored.OtnOpticalMode, so what an OTU would add is section monitoring and framing overhead.Also out of scope, and less likely to be contested: optical performance monitoring, since nothing measured belongs here; device types and platforms, reached through
dcim_device; and validation a schema cannot express, such as whether a mux client port binds a channel on the plan its multiplexer declares. This extension ships no checks, and the schema comments mark each such rule.Stacked on #92
This PR targets
ic/docs-usecases-and-stale-pages, the branch behind #92, notmain. #92 carries the CI housekeeping this branch depends on: it regenerates 15 reference pages that were already stale onmain, and it adds the optionaluse_casesandnot_coveredkeys todocs/_templates/schema_reference.j2andtasks/docs.py, which OTN's reference page is the only consumer of. Keeping them separate is what holds this diff to 20 files instead of 35. Review #92 first, or at least independently; GitHub retargets this PR tomainwhen #92 merges.Everything in this diff is the change:
extensions/otn, the two optical extensions removed with their objects and pages,.metadata.yml, the OTN sample objects, four stale comments in surviving files, and adr4choice inextensions/transceiver.Verification
Offline on every commit: SDK Pydantic models, peer and inherit resolution, identifier pairing,
schema format --check,yamllint,markdownlint,pytest,docs.generateidempotency.Live, on an instance rebuilt from scratch: all 38 extensions load, every object file loads, and the sample data exercises the new work rather than only describing it. A section runs between two passive multiplexers with no ROADM at either end; the service carries a working path over the north conduit and a protect path over the south, both at segment position 1 and distinguished only by
path_role; each hop resolves to its action and port pair from either the path or the ROADM's ports; a two-stage amplifier chain orders byoms_sequence; two CWDM wavelengths derive their band; 192.1 THz derives channel 16 at 1560.61 nm and 193.1 THz derives channel 36 at 1552.52 nm; aDcimCableterminates on anOtnLinePortat one end and anOtnRoadmAddDropPortat the other; each ROADM resolves throughdcim_deviceto a physical record at a rack unit on aLocationRack, carrying aDcimDeviceType; and the wavelength's payload grooms two levels deep, an ODUC4 offering 320 tributary slots into an ODU4 carrying a 100GbE client by GMP and a second ODU4 multiplexing an ODU2 that carries an STM-64 by BMP.A merged-inheritance collision check written for this branch found its only critical defect, a
devicesrelationship colliding with one inherited two levels up. No existing gate computes a node's merged namespace, so promoting it into CI is worth doing separately.Gaps
objects/in CI, so objects files ship unproven by automation. Pre-existing.schema format --check. None touched here; worth its own PR.Draft so the removal of the two extensions gets a decision first.