Skip to content

Commit 1fa4b94

Browse files
authored
[psushow] Add more output columns; Add option to output in JSON format (sonic-net#1416)
- Enhance `psushow -s` output, adding columns to display PSU Model, Serial, Voltage, Current and Power - Add `-j/--json` option to display output in JSON format - Update mock State DB PSU_INFO table to provide values which we can ensure floats are padded to two decimal places in tabular display mode - Add `--json` option to `show platform psustatus` which in turn adds the `-j` flag to the underlying `psushow` call - Add unit tests for `psushow` in psushow_test.py - Add more unit tests for `show platform psustatus` and move to show_platform_test.py
1 parent 79ccd03 commit 1fa4b94

File tree

6 files changed

+393
-124
lines changed

6 files changed

+393
-124
lines changed

scripts/psushow

+104-43
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,19 @@
11
#!/usr/bin/env python3
22

33
import argparse
4+
import json
45
import sys
5-
import os
6+
7+
from swsscommon.swsscommon import SonicV2Connector
68
from tabulate import tabulate
79

8-
# mock the redis for unit test purposes #
9-
try:
10-
if os.environ["UTILITIES_UNIT_TESTING"] == "1":
11-
modules_path = os.path.join(os.path.dirname(__file__), "..")
12-
test_path = os.path.join(modules_path, "tests")
13-
sys.path.insert(0, modules_path)
14-
sys.path.insert(0, test_path)
15-
import mock_tables.dbconnector
16-
except KeyError:
17-
pass
10+
VERSION = '1.0'
1811

19-
from swsscommon.swsscommon import SonicV2Connector
2012

21-
def psu_status_show(index):
13+
14+
def get_psu_status_list():
15+
psu_status_list = []
16+
2217
db = SonicV2Connector(host="127.0.0.1")
2318
db.connect(db.STATE_DB)
2419

@@ -27,59 +22,125 @@ def psu_status_show(index):
2722
chassis_name = "chassis {}".format(chassis_num)
2823
num_psus = db.get(db.STATE_DB, 'CHASSIS_INFO|{}'.format(chassis_name), 'psu_num')
2924
if not num_psus:
30-
print("Error! Failed to get the number of PSUs!")
31-
return -1
25+
print('Error: Failed to get the number of PSUs')
26+
return None
3227

33-
supported_psu = range(1, int(num_psus) + 1)
34-
if (index < 0):
35-
psu_ids = supported_psu
36-
else:
37-
psu_ids = [index]
28+
for psu_idx in range(1, int(num_psus) + 1):
29+
psu_status = {}
3830

39-
header = ['PSU', 'Status', 'LED']
40-
status_table = []
31+
psu_status['index'] = str(psu_idx)
32+
33+
psu_name = 'PSU {}'.format(psu_idx)
34+
psu_status['name'] = psu_name
4135

42-
for psu in psu_ids:
43-
msg = ""
44-
psu_name = "PSU {}".format(psu)
45-
if psu not in supported_psu:
46-
print("Error! The {} is not available on the platform.\n"
47-
"Number of supported PSU - {}.".format(psu_name, num_psus))
48-
continue
4936
presence = db.get(db.STATE_DB, 'PSU_INFO|{}'.format(psu_name), 'presence')
37+
psu_status['presence'] = presence
38+
5039
if presence == 'true':
5140
oper_status = db.get(db.STATE_DB, 'PSU_INFO|{}'.format(psu_name), 'status')
52-
msg = 'OK' if oper_status == 'true' else "NOT OK"
41+
status = 'OK' if oper_status == 'true' else "NOT OK"
5342
else:
54-
msg = 'NOT PRESENT'
55-
led_status = db.get(db.STATE_DB, 'PSU_INFO|{}'.format(psu_name), 'led_status')
56-
status_table.append([psu_name, msg, led_status])
43+
status = 'NOT PRESENT'
44+
psu_status['status'] = status
45+
46+
psu_status['led_status'] = db.get(db.STATE_DB, 'PSU_INFO|{}'.format(psu_name), 'led_status')
47+
48+
psu_status['model'] = db.get(db.STATE_DB, 'PSU_INFO|{}'.format(psu_name), 'model') if presence else 'N/A'
49+
psu_status['serial'] = db.get(db.STATE_DB, 'PSU_INFO|{}'.format(psu_name), 'serial') if presence else 'N/A'
50+
psu_status['voltage'] = db.get(db.STATE_DB, 'PSU_INFO|{}'.format(psu_name), 'voltage') if presence else 'N/A'
51+
psu_status['current'] = db.get(db.STATE_DB, 'PSU_INFO|{}'.format(psu_name), 'current') if presence else 'N/A'
52+
psu_status['power'] = db.get(db.STATE_DB, 'PSU_INFO|{}'.format(psu_name), 'power') if presence else 'N/A'
53+
54+
psu_status_list.append(psu_status)
55+
56+
return psu_status_list
57+
58+
59+
def psu_status_show_table(index):
60+
psu_status_list = get_psu_status_list()
61+
62+
if not psu_status_list:
63+
print('Error: Failed to get PSU status')
64+
return None
65+
66+
header = ['PSU', 'Model', 'Serial', 'Voltage (V)', 'Current (A)', 'Power (W)', 'Status', 'LED']
67+
status_table = []
68+
69+
if index > 0:
70+
if index > len(psu_status_list):
71+
print("Error: PSU {} is not available. Number of supported PSUs: {}".format(index, len(psu_status_list)))
72+
return -1
73+
74+
# Trim the list down to contain only the requested PSU
75+
psu_status_list = [psu_status_list[index-1]]
76+
77+
for psu_status in psu_status_list:
78+
status_table.append([psu_status['name'],
79+
psu_status['model'],
80+
psu_status['serial'],
81+
psu_status['voltage'],
82+
psu_status['current'],
83+
psu_status['power'],
84+
psu_status['status'],
85+
psu_status['led_status']])
5786

5887
if status_table:
59-
print(tabulate(status_table, header, tablefmt="simple"))
88+
print(tabulate(status_table, header, tablefmt="simple", floatfmt='.2f'))
89+
90+
return 0
91+
92+
93+
def psu_status_show_json(index):
94+
psu_status_list = get_psu_status_list()
95+
96+
if not psu_status_list:
97+
print('Error: Failed to get PSU status')
98+
return None
99+
100+
if index > 0:
101+
if index > len(psu_status_list):
102+
print("Error: PSU {} is not available. Number of supported PSUs: {}".format(index, len(psu_status_list)))
103+
return -1
104+
105+
# Trim the list down to contain only the requested PSU
106+
psu_status_list = [psu_status_list[index-1]]
107+
108+
print(json.dumps(psu_status_list, indent=4))
60109
return 0
61110

111+
62112
def main():
63113
parser = argparse.ArgumentParser(description='Display the psu status information',
64114
formatter_class=argparse.RawTextHelpFormatter,
65115
epilog="""
66116
Examples:
117+
psushow -s
118+
psushow -s -j
67119
psushow -s -i 1
68120
""")
69121

70-
parser.add_argument('-s', '--status', action='store_true', help='show the status information')
71-
parser.add_argument('-i', '--index', type=int, default=-1, help='the index of psu')
72-
parser.add_argument('-v', '--version', action='version', version='%(prog)s 1.0')
122+
parser.add_argument('-s', '--status', action='store_true', help='Show PSU status information')
123+
parser.add_argument('-i', '--index', type=int, default=-1, help='The index of PSU to display')
124+
parser.add_argument('-j', '--json', action='store_true', help='Display output in JSON format')
125+
parser.add_argument('-v', '--version', action='version', version='%(prog)s {}'.format(VERSION))
73126
args = parser.parse_args()
74127

75128
status_show = args.status
76129
psu_index = args.index
130+
output_json = args.json
131+
77132
if status_show:
78-
err = psu_status_show(psu_index)
79-
if err:
80-
print("Error: fail to get psu status from state DB")
81-
sys.exit(1)
133+
if output_json:
134+
ret = psu_status_show_json(psu_index)
135+
else:
136+
ret = psu_status_show_table(psu_index)
82137

83-
if __name__ == "__main__":
84-
main()
138+
if ret != 0:
139+
print("Error: failed to get PSU status from state DB")
140+
return 1
85141

142+
return 0
143+
144+
145+
if __name__ == "__main__":
146+
sys.exit(main())

show/platform.py

+6-2
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ def platform():
4141

4242
# 'summary' subcommand ("show platform summary")
4343
@platform.command()
44-
@click.option('--json', is_flag=True, help="JSON output")
44+
@click.option('--json', is_flag=True, help="Output in JSON format")
4545
def summary(json):
4646
"""Show hardware platform information"""
4747

@@ -69,14 +69,18 @@ def syseeprom(verbose):
6969
# 'psustatus' subcommand ("show platform psustatus")
7070
@platform.command()
7171
@click.option('-i', '--index', default=-1, type=int, help="the index of PSU")
72+
@click.option('--json', is_flag=True, help="Output in JSON format")
7273
@click.option('--verbose', is_flag=True, help="Enable verbose output")
73-
def psustatus(index, verbose):
74+
def psustatus(index, json, verbose):
7475
"""Show PSU status information"""
7576
cmd = "psushow -s"
7677

7778
if index >= 0:
7879
cmd += " -i {}".format(index)
7980

81+
if json:
82+
cmd += " -j"
83+
8084
clicommon.run_command(cmd, display_cmd=verbose)
8185

8286

tests/mock_tables/state_db.json

+20
Original file line numberDiff line numberDiff line change
@@ -121,11 +121,31 @@
121121
"PSU_INFO|PSU 1": {
122122
"presence": "true",
123123
"status": "true",
124+
"model": "0J6J4K",
125+
"serial": "CN-0J6J4K-17972-5AF-0086-A00",
126+
"temp": "None",
127+
"temp_threshold": "None",
128+
"voltage": "12.19",
129+
"voltage_min_threshold": "None",
130+
"voltage_max_threshold": "None",
131+
"current": "8.37",
132+
"power": "102.7",
133+
"is_replaceable": "False",
124134
"led_status": "green"
125135
},
126136
"PSU_INFO|PSU 2": {
127137
"presence": "true",
128138
"status": "true",
139+
"model": "0J6J4K",
140+
"serial": "CN-0J6J4K-17972-5AF-008M-A00",
141+
"temp": "None",
142+
"temp_threshold": "None",
143+
"voltage": "12.18",
144+
"voltage_min_threshold": "None",
145+
"voltage_max_threshold": "None",
146+
"current": "10.07",
147+
"power": "122.0",
148+
"is_replaceable": "False",
129149
"led_status": "green"
130150
},
131151
"EEPROM_INFO|TlvHeader": {

tests/psu_test.py

-51
This file was deleted.

0 commit comments

Comments
 (0)