@@ -429,6 +429,17 @@ def __init__(self, hostname, username, password, timeout=60, optional_args=None)
429429 hostname , username , password , timeout = timeout , optional_args = optional_args
430430 )
431431 self .platform = "nxos_ssh"
432+ self .connector_type_map = {
433+ "1000base-LH" : "LC_CONNECTOR" ,
434+ "1000base-SX" : "LC_CONNECTOR" ,
435+ "1000base-T" : "Unknown" ,
436+ "10Gbase-LR" : "LC_CONNECTOR" ,
437+ "10Gbase-SR" : "LC_CONNECTOR" ,
438+ "SFP-H10GB-CU1M" : "DAC_CONNECTOR" ,
439+ "SFP-H10GB-CU1.45M" : "DAC_CONNECTOR" ,
440+ "SFP-H10GB-CU3M" : "DAC_CONNECTOR" ,
441+ "SFP-H10GB-CU3.45M" : "DAC_CONNECTOR" ,
442+ }
432443
433444 def open (self ):
434445 self .device = self ._netmiko_open (
@@ -1528,3 +1539,105 @@ def get_vlans(self):
15281539 "interfaces" : self ._parse_vlan_ports (vlan ["vlanshowplist-ifidx" ]),
15291540 }
15301541 return vlans
1542+
1543+ def get_optics (self ):
1544+ command = "show interface transceiver details"
1545+ output = self ._send_command (command )
1546+
1547+ # Formatting data into return data structure
1548+ optics_detail = {}
1549+
1550+ # Extraction Regexps
1551+ port_ts_re = re .compile (r"^Ether.*?(?=\nEther|\Z)" , re .M | re .DOTALL )
1552+ port_re = re .compile (r"^(Ether.*)[ ]*?$" , re .M )
1553+ vendor_re = re .compile ("name is (.*)$" , re .M )
1554+ vendor_part_re = re .compile ("part number is (.*)$" , re .M )
1555+ vendor_rev_re = re .compile ("revision is (.*)$" , re .M )
1556+ serial_no_re = re .compile ("serial number is (.*)$" , re .M )
1557+ type_no_re = re .compile ("type is (.*)$" , re .M )
1558+ rx_instant_re = re .compile (r"Rx Power[ ]+(?:(\S+?)[ ]+dBm|(N.A))" , re .M )
1559+ tx_instant_re = re .compile (r"Tx Power[ ]+(?:(\S+?)[ ]+dBm|(N.A))" , re .M )
1560+ current_instant_re = re .compile (r"Current[ ]+(?:(\S+?)[ ]+mA|(N.A))" , re .M )
1561+
1562+ port_ts_l = port_ts_re .findall (output )
1563+
1564+ for port_ts in port_ts_l :
1565+ port = port_re .search (port_ts ).group (1 )
1566+ # No transceiver is present in those case
1567+ if "transceiver is not present" in port_ts :
1568+ continue
1569+ if "transceiver is not applicable" in port_ts :
1570+ continue
1571+ port_detail = {"physical_channels" : {"channel" : []}}
1572+ # No metric present
1573+ vendor = vendor_re .search (port_ts ).group (1 )
1574+ vendor_part = vendor_part_re .search (port_ts ).group (1 )
1575+ vendor_rev = vendor_rev_re .search (port_ts ).group (1 )
1576+ serial_no = serial_no_re .search (port_ts ).group (1 )
1577+ type_s = type_no_re .search (port_ts ).group (1 )
1578+ state = {
1579+ "vendor" : vendor .strip (),
1580+ "vendor_part" : vendor_part .strip (),
1581+ "vendor_rev" : vendor_rev .strip (),
1582+ "serial_no" : serial_no .strip (),
1583+ "connector_type" : self .connector_type_map .get (type_s , "Unknown" ),
1584+ }
1585+ if "DOM is not supported" not in port_ts :
1586+ res = rx_instant_re .search (port_ts )
1587+ input_power = res .group (1 ) or res .group (2 )
1588+ res = tx_instant_re .search (port_ts )
1589+ output_power = res .group (1 ) or res .group (2 )
1590+ res = current_instant_re .search (port_ts )
1591+ current = res .group (1 ) or res .group (2 )
1592+
1593+ # If interface is shutdown it returns "N/A" as output power
1594+ # or "N/A" as input power
1595+ # Converting that to -100.0 float
1596+ try :
1597+ float (output_power )
1598+ except ValueError :
1599+ output_power = - 100.0
1600+ try :
1601+ float (input_power )
1602+ except ValueError :
1603+ input_power = - 100.0
1604+ try :
1605+ float (current )
1606+ except ValueError :
1607+ current = - 100.0
1608+
1609+ # Defaulting avg, min, max values to -100.0 since device does not
1610+ # return these values
1611+ optic_states = {
1612+ "index" : 0 ,
1613+ "state" : {
1614+ "input_power" : {
1615+ "instant" : (
1616+ float (input_power ) if "input_power" else - 100.0
1617+ ),
1618+ "avg" : - 100.0 ,
1619+ "min" : - 100.0 ,
1620+ "max" : - 100.0 ,
1621+ },
1622+ "output_power" : {
1623+ "instant" : (
1624+ float (output_power ) if "output_power" else - 100.0
1625+ ),
1626+ "avg" : - 100.0 ,
1627+ "min" : - 100.0 ,
1628+ "max" : - 100.0 ,
1629+ },
1630+ "laser_bias_current" : {
1631+ "instant" : (float (current ) if "current" else - 100.0 ),
1632+ "avg" : 0.0 ,
1633+ "min" : 0.0 ,
1634+ "max" : 0.0 ,
1635+ },
1636+ },
1637+ }
1638+ port_detail ["physical_channels" ]["channel" ].append (optic_states )
1639+
1640+ port_detail ["state" ] = state
1641+ optics_detail [port ] = port_detail
1642+
1643+ return optics_detail
0 commit comments