From 84c14aadc7c9329a426e6598af55f6c61129b8e8 Mon Sep 17 00:00:00 2001 From: thatmattlove Date: Fri, 15 Oct 2021 17:07:54 -0700 Subject: [PATCH] Fixes #7300: Fix incorrect Device LLDP interface row coloring & improve related JS --- docs/release-notes/version-3.0.md | 1 + netbox/project-static/dist/lldp.js | Bin 109095 -> 109291 bytes netbox/project-static/dist/lldp.js.map | Bin 106320 -> 106584 bytes netbox/project-static/src/device/lldp.ts | 98 +++++++++++++++++------ 4 files changed, 74 insertions(+), 25 deletions(-) diff --git a/docs/release-notes/version-3.0.md b/docs/release-notes/version-3.0.md index 82770e856..70a9a0dac 100644 --- a/docs/release-notes/version-3.0.md +++ b/docs/release-notes/version-3.0.md @@ -4,6 +4,7 @@ ### Bug Fixes +* [#7300](https://github.com/netbox-community/netbox/issues/7300) - Fix incorrect Device LLDP interface row coloring * [#7495](https://github.com/netbox-community/netbox/issues/7495) - Fix navigation UI issue that caused improper element overlap * [#7529](https://github.com/netbox-community/netbox/issues/7529) - Restore horizontal scrolling for tables in narrow viewports * [#7534](https://github.com/netbox-community/netbox/issues/7534) - Avoid exception when utilizing "create and add another" twice in succession diff --git a/netbox/project-static/dist/lldp.js b/netbox/project-static/dist/lldp.js index 7fac1012a96c1fbfd21177b565f29c9a2cb3fe7c..2b3934742c7a3b9294c91b81efcf0817e51c021a 100644 GIT binary patch delta 6474 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 D^S{oE delta 6269 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 UW_gV0SFJ>mCfw`Fb25?q0Lz=q!~g&Q delta 426 zcmY+9!AiqW5Jha#oqn=2_9D7+LvV8K)CXT^ay) zmOQ|*#K`T1D|}+huV=H|PRR#ir6Jwg+8KlQSe2|?%}o0tcl9y+V|2uLU?s&XYBsSH zf^RGV2-KHQ0PgEekS2*&emQ3mm=gF?Phr$#hB|O1nWuCD>{?N|s2jwR+Z8xkGucDf zm}L*J4riJkQKW}dxYrFEGWtinynLFQ;~oESUGm4KO)=1@M5A*qKj&tv$32N_^h_N? iUFe$idZ``!{_otHdvK5H&H<%BsyLtw!K-~SZSxIf)Oc3_ diff --git a/netbox/project-static/src/device/lldp.ts b/netbox/project-static/src/device/lldp.ts index 6baaa9b38..ebf71138c 100644 --- a/netbox/project-static/src/device/lldp.ts +++ b/netbox/project-static/src/device/lldp.ts @@ -1,6 +1,17 @@ import { createToast } from '../bs'; import { getNetboxData, apiGetBase, hasError, isTruthy, toggleLoader } from '../util'; +// Match an interface name that begins with a capital letter and is followed by at least one other +// alphabetic character, and ends with a forward-slash-separated numeric sequence such as 0/1/2. +const CISCO_IOS_PATTERN = new RegExp(/^([A-Z][A-Za-z]+)[^0-9]*([0-9/]+)$/); + +// Mapping of overrides to default Cisco IOS interface alias behavior (default behavior is to use +// the first two characters). +const CISCO_IOS_OVERRIDES = new Map([ + // Cisco IOS abbreviates 25G (TwentyFiveGigE) interfaces as 'Twe'. + ['TwentyFiveGigE', 'Twe'], +]); + /** * Get an attribute from a row's cell. * @@ -12,6 +23,40 @@ function getData(row: HTMLTableRowElement, query: string, attr: string): string return row.querySelector(query)?.getAttribute(attr) ?? null; } +/** + * Get preconfigured alias for given interface. Primarily for matching long-form Cisco IOS + * interface names with short-form Cisco IOS interface names. For example, `GigabitEthernet0/1/2` + * would become `Gi0/1/2`. + * + * This should probably be replaced with something in the primary application (Django), such as + * a database field attached to given interface types. However, this is a temporary measure to + * replace the functionality of this one-liner: + * + * @see https://github.com/netbox-community/netbox/blob/9cc4992fad2fe04ef0211d998c517414e8871d8c/netbox/templates/dcim/device/lldp_neighbors.html#L69 + * + * @param name Long-form/original interface name. + */ +function getInterfaceAlias(name: string | null): string | null { + if (name === null) { + return name; + } + if (name.match(CISCO_IOS_PATTERN)) { + // Extract the base name and numeric portions of the interface. For example, an input interface + // of `GigabitEthernet0/0/1` would result in an array of `['GigabitEthernet', '0/0/1']`. + const [base, numeric] = (name.match(CISCO_IOS_PATTERN) ?? []).slice(1, 3); + + if (isTruthy(base) && isTruthy(numeric)) { + // Check the override map and use its value if the base name is present in the map. + // Otherwise, use the first two characters of the base name. For example, + // `GigabitEthernet0/0/1` would become `Gi0/0/1`, but `TwentyFiveGigE0/0/1` would become + // `Twe0/0/1`. + const aliasBase = CISCO_IOS_OVERRIDES.get(base) || base.slice(0, 2); + return `${aliasBase}${numeric}`; + } + } + return name; +} + /** * Update row styles based on LLDP neighbor data. */ @@ -23,38 +68,41 @@ function updateRowStyle(data: LLDPNeighborDetail) { if (row !== null) { for (const neighbor of neighbors) { - const cellDevice = row.querySelector('td.device'); - const cellInterface = row.querySelector('td.interface'); - const cDevice = getData(row, 'td.configured_device', 'data'); - const cChassis = getData(row, 'td.configured_chassis', 'data-chassis'); - const cInterface = getData(row, 'td.configured_interface', 'data'); + const deviceCell = row.querySelector('td.device'); + const interfaceCell = row.querySelector('td.interface'); + const configuredDevice = getData(row, 'td.configured_device', 'data'); + const configuredChassis = getData(row, 'td.configured_chassis', 'data-chassis'); + const configuredIface = getData(row, 'td.configured_interface', 'data'); - let cInterfaceShort = null; - if (isTruthy(cInterface)) { - cInterfaceShort = cInterface.replace(/^([A-Z][a-z])[^0-9]*([0-9/]+)$/, '$1$2'); + const interfaceAlias = getInterfaceAlias(configuredIface); + + const remoteName = neighbor.remote_system_name ?? ''; + const remotePort = neighbor.remote_port ?? ''; + const [neighborDevice] = remoteName.split('.'); + const [neighborIface] = remotePort.split('.'); + + if (deviceCell !== null) { + deviceCell.innerText = neighborDevice; } - const nHost = neighbor.remote_system_name ?? ''; - const nPort = neighbor.remote_port ?? ''; - const [nDevice] = nHost.split('.'); - const [nInterface] = nPort.split('.'); - - if (cellDevice !== null) { - cellDevice.innerText = nDevice; + if (interfaceCell !== null) { + interfaceCell.innerText = neighborIface; } - if (cellInterface !== null) { - cellInterface.innerText = nInterface; - } + // Interface has an LLDP neighbor, but the neighbor is not configured in NetBox. + const nonConfiguredDevice = !isTruthy(configuredDevice) && isTruthy(neighborDevice); - if (!isTruthy(cDevice) && isTruthy(nDevice)) { + // NetBox device or chassis matches LLDP neighbor. + const validNode = + configuredDevice === neighborDevice || configuredChassis === neighborDevice; + + // NetBox configured interface matches LLDP neighbor interface. + const validInterface = + configuredIface === neighborIface || interfaceAlias === neighborIface; + + if (nonConfiguredDevice) { row.classList.add('info'); - } else if ( - (cDevice === nDevice || cChassis === nDevice) && - cInterfaceShort === nInterface - ) { - row.classList.add('success'); - } else if (cDevice === nDevice || cChassis === nDevice) { + } else if (validNode && validInterface) { row.classList.add('success'); } else { row.classList.add('danger');