Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix exception when trying to get environmental data from certain Nexus devices #1133

Merged
merged 5 commits into from
Mar 4, 2020

Conversation

joshniec
Copy link
Contributor

Some Nexus devices postfix the names of the keys with the device's series information, ie _n3k in the case for Nexus 3k devices in the show environment output. This causes a KeyError exception to be thrown when trying to retrieve environmental data from the device using the get_environment() method.

The currently method assumes that the key in the resulting JSON structure is TABLE_psinfo and subsequently ROW_psinfo which is not true for all Nexus devices.

This fix uses the strategy deployed here to find the keys that start with TABLE_psinfo and ROW_psinfo and use those to index the JSON structure to find the environmental information.

Additionally, newer nxos releases have changed the information provided in the JSON output of show environment, along with this, the format of the ps_model is not standard, so that relying on the format of the power supply's model name to be consistent enough to parse to determine the max capacity of the PSU is no longer reliable. Instead, newer nxos releases provide a new key, tot_capa which specifies the total capacity of the PSU in Watts.

The second fix/change here is to use the tot_capa key to retrieve the PSU's total capacity if that key exists, otherwise we fall back to the old method.

I only have Nexus 3000 and Nexus 9000 devices in my environment to test these changes on, and they work there.

I tested this on Nexus 3k's running the following NX-OS versions:

  • 7.0(3)I3(1)
  • 6.0(2)U3(7)
  • 6.2(13)
    And on Nexus 9k's running the following NX-OS versions:
  • 7.0(3)I7(7)

On my Nexus 3k devices, they output is slightly different than the Nexus 9k (below), specifically the TABLE_psinfo and ROW_psinfo keys are postfixed with _n3k and causes a KeyError exception to be thrown when attempting to index the JSON structure for the key TABLE_psinfo (..and ROW_psinfo):

        "voltage_level": "12", 
        "TABLE_psinfo_n3k": {
            "ROW_psinfo_n3k": [
                {
                    "psnum": "1", 
                    "psmodel": "N2200-PAC-400W", 
                    "input_type": "AC", 
                    "watts": "396.00", 
                    "amps": "33.00", 
                    "ps_status": "ok"
                }, 
                {
                    "psnum": "2", 
                    "psmodel": "N2200-PAC-400W", 
                    "input_type": "AC", 
                    "watts": "396.00", 
                    "amps": "33.00", 
                    "ps_status": "ok"
                }
            ]
        }, 
        "TABLE_mod_pow_info_n3k": {
            "ROW_mod_pow_info_n3k": {
                "modnum": "1", 
                "mod_model": "N3K-C3132Q-XL", 
                "watts_requested": "348.00", 
                "amps_requested": "29.00", 
                "watts_alloced": "348.00", 
                "amps_alloced": "29.00", 
                "modstatus": "powered-up"
            }
        }, 
        "power_summary_n3k": {
            "ps_redun_mode": "Redundant", 
            "ps_redun_op_mode": "Redundant", 
            "tot_pow_capacity": "792.00 W", 
            "reserve_sup": "348.00 W", 
            "pow_used_by_mods": "0.00 W", 
            "available_pow": "444.00 W"
        }
    }, 

On my 9k Nexus device, get_environment() can parse the TABLE_psinfo and ROW_psinfo keys because they are not postfixed with the device's series number (_n9k) (but failed when attempting to parse the psmodel number to determine the capacity of the PSU):

    "powersup": {
        "voltage_level": "12", 
        "TABLE_psinfo": {
            "ROW_psinfo": [
                {
                    "psnum": "1", 
                    "psmodel": "NXA-PAC-650W-PE", 
                    "actual_out": "83 W", 
                    "actual_input": "94 W", 
                    "tot_capa": "650 W", 
                    "ps_status": "Ok"
                }, 
                {
                    "psnum": "2", 
                    "psmodel": "NXA-PAC-650W-PE", 
                    "actual_out": "86 W", 
                    "actual_input": "97 W", 
                    "tot_capa": "650 W", 
                    "ps_status": "Ok"
                }
            ]
        }, 
        "power_summary": {
            "ps_redun_mode": "PS-Redundant", 
            "ps_oper_mode": "PS-Redundant", 
            "tot_pow_capacity": "650.00 W", 
            "tot_gridA_capacity": "650.00 W", 
            "tot_gridB_capacity": "650.00 W", 
            "cumulative_power": "1300.00 W", 
            "tot_pow_out_actual_draw": "169.00 W", 
            "tot_pow_input_actual_draw": "191.00 W", 
            "tot_pow_alloc_budgeted": "N/A", 
            "available_pow": "N/A"
        }
    },

Here is some testing:

  • Before this PR on a Nexus 3k, get_environment():
d:\programs\python38\lib\site-packages\napalm\nxos\nxos.py in get_environment(self)
   1442         fan_key = [i for i in environment_raw.keys() if i.startswith("fandetails")][0]
   1443         return {
-> 1444             "power": _process_pdus(environment_raw["powersup"]),
   1445             "fans": _process_fans(environment_raw[fan_key]),
   1446             "temperature": _process_temperature(environment_raw["TABLE_tempinfo"]),

d:\programs\python38\lib\site-packages\napalm\nxos\nxos.py in _process_pdus(power_data)
   1373                     tmp_table.append(tmp)
   1374                 ps_info_table = {"ROW_psinfo": tmp_table}
-> 1375             for psinfo in ps_info_table["ROW_psinfo"]:
   1376                 normalized[psinfo["psnum"]]["status"] = (
   1377                     psinfo.get("ps_status", "ok") == "ok"

KeyError: 'ROW_psinfo'
  • After this PR on a Nexus 3k, get_environment():
Out[6]:
{'power': {'1': {'status': True, 'output': 396.0, 'capacity': 400.0},
  '2': {'status': True, 'output': 396.0, 'capacity': 400.0}},
 'fans': {'Fan1(sys_fan1)': {'status': True},
  'Fan2(sys_fan2)': {'status': True},
  'Fan3(sys_fan3)': {'status': True},
  'Fan4(sys_fan4)': {'status': True}},
 'temperature': {'1-1  ASIC': {'temperature': 43.0,
   'is_alert': False,
   'is_critical': False},
  '1-2  Front-Middle(D1)': {'temperature': 31.0,
   'is_alert': False,
   'is_critical': False},
  '1-3  Front-Left  (D2)': {'temperature': 29.0,
   'is_alert': False,
   'is_critical': False},
  '1-4  Back        (D3)': {'temperature': 25.0,
   'is_alert': False,
   'is_critical': False}},
 'cpu': {0: {'%usage': 9.17}},
 'memory': {'available_ram': 553000, 'used_ram': 45000}}
  • Before this PR on a Nexus 9k, get_environment():
ValueError                                Traceback (most recent call last)
<ipython-input-10-83d00915fd76> in <module>
----> 1 device.get_environment()

d:\programs\python38\lib\site-packages\napalm\nxos\nxos.py in get_environment(self)
   1448         fan_key = [i for i in environment_raw.keys() if i.startswith("fandetails")][0]
   1449         return {
-> 1450             "power": _process_pdus(environment_raw["powersup"]),
   1451             "fans": _process_fans(environment_raw[fan_key]),
   1452             "temperature": _process_temperature(environment_raw["TABLE_tempinfo"]),

d:\programs\python38\lib\site-packages\napalm\nxos\nxos.py in _process_pdus(power_data)
   1387                 # ie N2200-PAC-400W = 400 watts
   1388                 ps_model = psinfo.get("psmodel", "-1")
-> 1389                 normalized[psinfo["psnum"]]["capacity"] = float(
   1390                     ps_model.split("-")[-1][:-1]
   1391                 )

ValueError: could not convert string to float: 'P
  • After this PR on a Nexus 9k, get_environment():
Out[10]:
{'power': {'1': {'status': False, 'output': -1.0, 'capacity': 650.0},
  '2': {'status': False, 'output': -1.0, 'capacity': 650.0}},
 'fans': {'Fan1(sys_fan1)': {'status': True},
  'Fan2(sys_fan2)': {'status': True},
  'Fan3(sys_fan3)': {'status': True},
  'Fan4(sys_fan4)': {'status': True}},
 'temperature': {'1-1 FRONT': {'temperature': 22.0,
   'is_alert': False,
   'is_critical': False},
  '1-2 BACK': {'temperature': 27.0, 'is_alert': False, 'is_critical': False},
  '1-3 CPU': {'temperature': 34.0, 'is_alert': False, 'is_critical': False},
  '1-4 TAH': {'temperature': 45.0, 'is_alert': False, 'is_critical': False}},
 'cpu': {0: {'%usage': 1.51}},
 'memory': {'available_ram': 808000, 'used_ram': 56000}}

…es that postfix some json keys with the device series name (shorthand) in the show environment output, specifically under the powersup key.
…hat key is available, otherwise, fall back to the old method of getting the PSU's capacity by parsing the ps_model information.
@coveralls
Copy link

Coverage Status

Coverage remained the same at ?% when pulling 06916b3 on ironick09:develop into 08e41b8 on napalm-automation:develop.

@coveralls
Copy link

coveralls commented Feb 20, 2020

Coverage Status

Coverage remained the same at ?% when pulling f36ba0a on ironick09:develop into 08e41b8 on napalm-automation:develop.

Copy link
Member

@mirceaulinic mirceaulinic left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some Nexus devices postfix the names of the keys with the device's series information, ie _n3k in the case for Nexus 3k devices in the show environment output.

Ewwww 🤢

Thanks for this patch @ironick09, looks good! Would you please be able to add a test case for this, to ensure compatibility on the long term?

@mirceaulinic mirceaulinic added this to the 3.0.0 milestone Feb 29, 2020
@mirceaulinic
Copy link
Member

FYI: we are planning to release NAPALM 3.0.0 soon. If you'd like your patch to be included in this version, please address the comments above. Thanks!

@joshniec
Copy link
Contributor Author

joshniec commented Mar 3, 2020

I will get the tests added this morning. Thanks :)

@joshniec
Copy link
Contributor Author

joshniec commented Mar 3, 2020

Hi @mirceaulinic, I have added tests / mock data for my changes, here are the results:

(.venv)$ py.test test/nxos/test_getters.py::TestGetter::test_get_environment
========================================================================================================================================================================== test session starts ===========================================================================================================================================================================
platform darwin -- Python 3.7.6, pytest-5.3.5, py-1.8.1, pluggy-0.13.1
rootdir: /Users/jniec/source/repos/napalm, inifile: setup.cfg
plugins: pylama-7.7.1, json-0.4.0, pythonpath-0.7.3, cov-2.8.1
collected 3 items

test/nxos/test_getters.py ...                                                                                                                                                                                                                                                                                                                                      [100%]

-------------------------------------------------------------------------------------------------------------------------------------------------- generated json report: /Users/jniec/source/repos/napalm/report.json ---------------------------------------------------------------------------------------------------------------------------------------------------
=========================================================================================================================================================================== 3 passed in 0.05s ============================================================================================================================================================================
(.venv)$ cat report.json | jq
{
  "data": [
    {
      "type": "report",
      "id": 1,
      "attributes": {
        "environment": {
          "Python": "3.7.6",
          "Platform": "Darwin-19.3.0-x86_64-i386-64bit"
        },
        "summary": {
          "passed": 3,
          "num_tests": 3,
          "duration": 0.05885815620422363
        },
        "created_at": "2020-03-03 09:39:45.653403"
      },
      "relationships": {
        "tests": {
          "data": [
            {
              "id": 1,
              "type": "test"
            },
            {
              "id": 2,
              "type": "test"
            },
            {
              "id": 3,
              "type": "test"
            }
          ]
        }
      }
    }
  ],
  "included": [
    {
      "id": 1,
      "type": "test",
      "attributes": {
        "name": "test/nxos/test_getters.py::TestGetter::test_get_environment[pre_7.0]",
        "duration": 0.012677907943725586,
        "run_index": 0,
        "setup": {
          "name": "setup",
          "duration": 0.005444049835205078,
          "outcome": "passed"
        },
        "call": {
          "name": "call",
          "duration": 0.0015869140625,
          "outcome": "passed"
        },
        "teardown": {
          "name": "teardown",
          "duration": 0.0002028942108154297,
          "outcome": "passed"
        },
        "outcome": "passed"
      }
    },
    {
      "id": 2,
      "type": "test",
      "attributes": {
        "name": "test/nxos/test_getters.py::TestGetter::test_get_environment[nxos_3k]",
        "duration": 0.0018322467803955078,
        "run_index": 1,
        "setup": {
          "name": "setup",
          "duration": 0.00022721290588378906,
          "outcome": "passed"
        },
        "call": {
          "name": "call",
          "duration": 0.0012319087982177734,
          "outcome": "passed"
        },
        "teardown": {
          "name": "teardown",
          "duration": 0.00014591217041015625,
          "outcome": "passed"
        },
        "outcome": "passed"
      }
    },
    {
      "id": 3,
      "type": "test",
      "attributes": {
        "name": "test/nxos/test_getters.py::TestGetter::test_get_environment[normal]",
        "duration": 0.0019218921661376953,
        "run_index": 2,
        "setup": {
          "name": "setup",
          "duration": 0.00020694732666015625,
          "outcome": "passed"
        },
        "call": {
          "name": "call",
          "duration": 0.0012021064758300781,
          "outcome": "passed"
        },
        "teardown": {
          "name": "teardown",
          "duration": 0.0003058910369873047,
          "outcome": "passed"
        },
        "outcome": "passed"
      }
    }
  ]
}

@joshniec
Copy link
Contributor Author

joshniec commented Mar 3, 2020

Could you try re-running the job? It looks like it failed because of a connection error/timeout when installing the python packages. Thanks

@ktbyers
Copy link
Contributor

ktbyers commented Mar 3, 2020

@ironick09 Re-started test...

Copy link
Member

@mirceaulinic mirceaulinic left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @ironick09!

@mirceaulinic mirceaulinic merged commit fdf91d9 into napalm-automation:develop Mar 4, 2020
neelimapp pushed a commit to neelimapp/napalm that referenced this pull request Mar 20, 2020
…s devices (napalm-automation#1133)

* Fix bug when trying to get environmental information from Nexus devices that postfix some json keys with the device series name (shorthand) in the show environment output, specifically under the powersup key.

* Use 	ot_capa to get the PSU's capacity for newer versions of nxos if that key is available, otherwise, fall back to the old method of getting the PSU's capacity by parsing the ps_model information.

* Reformat line length

* Run black formatter to fix CI issues

* Add tests for nxos_3k (some software versions)
bharath-ravindranath pushed a commit to bharath-ravindranath/napalm that referenced this pull request Apr 19, 2020
…s devices (napalm-automation#1133)

* Fix bug when trying to get environmental information from Nexus devices that postfix some json keys with the device series name (shorthand) in the show environment output, specifically under the powersup key.

* Use 	ot_capa to get the PSU's capacity for newer versions of nxos if that key is available, otherwise, fall back to the old method of getting the PSU's capacity by parsing the ps_model information.

* Reformat line length

* Run black formatter to fix CI issues

* Add tests for nxos_3k (some software versions)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants