A customer noticed that some SFPs installed in a Cisco Nexus were particularly 🔥hot🔥 and asked for a command to be able to see the temperature of all the transceivers. Sounds like a good opportunity to write some code!

One of the things I love most about my job is when customers call me with odd requests. These unique challenges are not just a break from the routine; they are fantastic opportunities to learn something new and expand my horizons. Each unusual request is a chance to dive into uncharted territory, solve intriguing problems, and ultimately grow both personally and professionally.

I advised the client to get a monitoring tool that would read all the temperatures by saving them to a database (like LibreNMS ), but that did not stop me from fulfilling the request as well.

Table of Contents

Python

NXOS includes a Python interpreter to help us working with commands output.

Even better we can use also grep, tr and awk.

Putting it all together, a short script can collect the list of switch interfaces and for each print the current temperature:

from cli import *
ilist = cli('sh inte status | grep Eth.*connected | grep -v "base-T" | grep -v \. | tr -s " " | awk \'{print $1, $NF}\'')
for i in list(filter(None,ilist.split("\n"))):
    interface,transceiver = i.split(" ")
    command=f"show interface {interface} transceiver details | grep Temperature | sort | uniq"
    temperature = cli(command)
    if temperature:
        t = temperature.split()
        print(f"{interface}\t{t[1].rstrip()}\t{transceiver}")
    else:
	    print(f"{interface}\t{0.0}\t{transceiver}")

Sample output:

Eth1/1  43.73   10Gbase-SR
Eth1/2  41.83   10Gbase-SR
Eth1/5  43.74   10/25Gbase-CSR
Eth1/6  44.24   10/25Gbase-CSR
Eth1/7  42.25   10Gbase-SR
Eth1/8  43.24   10/25Gbase-CSR
Eth1/9  0.0     1000base-SX
Eth1/10 0.0     1000base-SX
Eth1/11 43.19   10/25Gbase-CSR
Eth1/12 43.58   10/25Gbase-CSR
Eth1/14 43.08   10/25Gbase-CSR
Eth1/15 48.69   10Gbase-ER
Eth1/16 47.57   10Gbase-ER
Eth1/17 47.74   10Gbase-ER
Eth1/18 46.90   10Gbase-ER
Eth1/19 46.48   10Gbase-ER
Eth1/20 45.55   10Gbase-ER
Eth1/21 44.68   10Gbase-ER
Eth1/22 46.55   10Gbase-ER
Eth1/23 40.28   10/25Gbase-CSR
Eth1/24 39.89   10/25Gbase-CSR
Eth1/25 39.75   10/25Gbase-CSR
Eth1/26 40.30   10/25Gbase-CSR
Eth1/27 39.26   10/25Gbase-CSR
Eth1/28 38.82   10/25Gbase-CSR
Eth1/29 39.49   10Gbase-SR
Eth1/30 37.12   10Gbase-SR
Eth1/31 37.75   10/25Gbase-CSR
Eth1/32 37.77   10/25Gbase-CSR
Eth1/33 39.18   10Gbase-LR
Eth1/34 43.75   10Gbase-LR
Eth1/35 35.86   10Gbase-LR
Eth1/36 36.57   1000base-SX
Eth1/37 34.71   1000base-SX
Eth1/39 34.83   10/25Gbase-CSR
Eth1/41 35.20   10Gbase-SR
Eth1/42 35.54   10Gbase-SR
Eth1/43 36.27   10/25Gbase-CSR
Eth1/44 37.82   10/25Gbase-CSR
Eth1/45 37.07   10/25Gbase-CSR
Eth1/46 38.51   10/25Gbase-CSR
Eth1/47 34.12   10Gbase-SR
Eth1/48 36.71   10Gbase-SR
Eth1/49 37.56   QSFP-100G-SR4
Eth1/50 39.49   QSFP-100G-SR4
Eth1/51 64.66   QSFP-100G-DWDM-2
Eth1/52 68.07   QSFP-100G-DWDM-2
Eth1/53 46.33   QSFP-100G40G-BIDI
Eth1/54 48.03   QSFP-100G40G-BIDI

Not all transceivers are equal

Notice that some SFP don't provide the temperature, so the script writes 0.0 instead. Let’s try to understand a little more about it

This is fine:

sh inte e1/36 transceiver 

Ethernet1/36
    transceiver is present
    type is 1000base-SX
    name is CISCO-OPLINK
    part number is 1837022038
    revision is 01
    serial number is OPM24xxxxxx
    nominal bitrate is 1300 MBit/sec
    cisco id is 3
    cisco extended id number is 4
    cisco part number is 10-2626-03
    cisco product id is GLC-SX-MMD
    cisco version id is V03

This doesn’t show the temperature:

sh inte e1/9 transceiver 
Ethernet1/9
    transceiver is present
    type is 1000base-SX
    name is CISCO-FINISAR
    part number is FTLF8519P2BCL-C5
    revision is A
    serial number is FNS15xxxxxx
    nominal bitrate is 1300 MBit/sec
    cisco id is 3
    cisco extended id number is 4
    cisco part number is 30-1301-04
    cisco product id is GLC-SX-MM
    cisco version id is V04

Notice that the transceivers are both GLC-SX-MMD but are manufactured by different vendors, CISCO-OPLINK and CISCO-FINISAR.

In this switch we can see six different manufacturers of optical interfaces, all procured via an official Cisco distributor:

show interface transceiver | grep CISCO- | sort | uniq
    name is CISCO-ACCELINK
    name is CISCO-AVAGO
    name is CISCO-FINISAR
    name is CISCO-FOIT
    name is CISCO-INNOLIGHT
    name is CISCO-OPLINK

Probably not all SFPs have the same functionality, in our case FINISARs do not show the temperature in the output of the command.

What if we use Json?

As an exercise I tried to redo the same script by taking advantage of NXOS’s feature of producing output in JSON format. This way you can avoid using awk, grep,sed, which can be an advantage for those who are not familiar with these commands.

Here’s the code:

from cli import *
ilist = json.loads(cli('sh inte status | json'))
interfaces = ilist['TABLE_interface']['ROW_interface']
# filter only connected interfaces
data = [interface for interface in interfaces if interface['state'] == 'connected']
data = [interface for interface in interfaces if interface.get('type') and interface.get('type') != '--' and interface.get('type') != '1000base-T']
for interface in data:
    command=f"show interface {interface.get('interface')} transceiver details | json"
    transceiverDetails = json.loads(cli(command))['TABLE_interface']['ROW_interface']
    if transceiverDetails.get('TABLE_lane'):
        if isinstance(transceiverDetails.get('TABLE_lane').get('ROW_lane'),list):
            temperature = transceiverDetails.get('TABLE_lane').get('ROW_lane')[0].get('temperature')
        else:
            temperature = transceiverDetails.get('TABLE_lane').get('ROW_lane').get('temperature')
    else:
        temperature = 0
    pid = transceiverDetails.get("cisco_product_id",transceiverDetails.get("type"))
    print(f"{interface.get('interface')}\t{temperature}\t{pid}")

You can see that the obtained JSON sometimes returns a list, and sometimes does not, some intefaces do not contain the temperature so I print the value 0, others do not contain the product ID, which I replaced with the “type” of the interface.

This clearly shows that the output in JSON is far from optimal for programmability. It would have been more useful and consistent to always return lists, even for a single element, and return Null in the absence of the value, but still creating the key in the dictionary.

In the end the first script is shorter and also more readable, but this is subjective, YMMW .

Wrap up

I really like having GNU and Python scriptig tools on NXOS. It saves me a lot of copying/pasting or exporting command outputs and then processing them on my laptop. The use of JSON has proven useful but requires attention, I prefer it as an approach but it still seems a bit immature, there is room for improvement. The version of NXOS in use is 10.2(5)

Ultimately, the bottom line of this post is that all network engineers should seriously consider supplementing their training with at least the basics of Linux and Python to be more efficient and autonomous.

Feedback

I’m always looking to improve and would love your feedback. If you spot any errors, have suggestions, or just want to share your thoughts, reach out to me directly on X.

Your input helps me make this blog better for everyone!

Support Ifconfig.it

If you enjoy the technical content I share and find it valuable, consider supporting the blog.

PAYPAL.ME