Skip to content

Commit 72b9cf9

Browse files
authoredNov 21, 2022
[psushow & psuutil] Support PSU power threshold checking (sonic-net#2326)
* Support PSU power exceed warning
1 parent dfdc92e commit 72b9cf9

File tree

6 files changed

+77
-8
lines changed

6 files changed

+77
-8
lines changed
 

‎doc/Command-Reference.md

+1
Original file line numberDiff line numberDiff line change
@@ -834,6 +834,7 @@ This command displays the status of the device's power supply units
834834
PSU Model Serial HW Rev Voltage (V) Current (A) Power (W) Status LED
835835
----- ------------- ------------ -------- ------------- ------------- ----------- -------- -----
836836
PSU 1 MTEF-PSF-AC-A MT1621X15246 A3 11.97 4.56 54.56 OK green
837+
PSU 2 MTEF-PSF-AC-A MT1621X15247 A3 11.97 4.56 54.56 WARNING green
837838
```
838839
839840
**show platform fan**

‎psuutil/main.py

+22-2
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ def numpsus():
8484
@click.option('-i', '--index', default=-1, type=int, help='Index of the PSU')
8585
def status(index):
8686
"""Display PSU status"""
87-
header = ['PSU', 'Model', 'Serial', 'Voltage (V)', 'Current (A)', 'Power (W)', 'Status', 'LED']
87+
header = ['PSU', 'Model', 'Serial', 'HW Rev', 'Voltage (V)', 'Current (A)', 'Power (W)', 'Power Warn-supp Thres (W)', 'Power Crit Thres (W)', 'Status', 'LED']
8888
status_table = []
8989

9090
psu_list = platform_chassis.get_all_psus()
@@ -94,14 +94,29 @@ def status(index):
9494
status = 'NOT PRESENT'
9595
model = 'N/A'
9696
serial = 'N/A'
97+
revision = 'N/A'
9798
voltage = 'N/A'
9899
current = 'N/A'
99100
power = 'N/A'
100101
led_color = 'N/A'
102+
power_critical_threshold = 'N/A'
103+
power_warning_suppress_threshold = 'N/A'
101104

102105
if psu.get_presence():
103106
try:
104107
status = 'OK' if psu.get_powergood_status() else 'NOT OK'
108+
if psu.get_powergood_status():
109+
power = psu.get_power()
110+
try:
111+
power_critical_threshold = psu.get_psu_power_critical_threshold()
112+
power_warning_suppress_threshold = psu.get_psu_power_warning_suppress_threshold()
113+
except NotImplementedError:
114+
pass
115+
if power_critical_threshold is None:
116+
power_critical_threshold = 'N/A'
117+
if power_warning_suppress_threshold is None:
118+
power_warning_suppress_threshold = 'N/A'
119+
status = 'OK'
105120
except NotImplementedError:
106121
status = 'UNKNOWN'
107122

@@ -115,6 +130,11 @@ def status(index):
115130
except NotImplementedError:
116131
pass
117132

133+
try:
134+
revision = psu.get_revision()
135+
except NotImplementedError:
136+
pass
137+
118138
try:
119139
voltage = psu.get_voltage()
120140
except NotImplementedError:
@@ -135,7 +155,7 @@ def status(index):
135155
except NotImplementedError:
136156
pass
137157

138-
status_table.append([psu_name, model, serial, voltage, current, power, status, led_color])
158+
status_table.append([psu_name, model, serial, revision, voltage, current, power, power_warning_suppress_threshold, power_critical_threshold, status, led_color])
139159

140160
if status_table:
141161
click.echo(tabulate(status_table, header, tablefmt='simple', floatfmt='.2f'))

‎scripts/psushow

+5-1
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,11 @@ def get_psu_status_list():
3838

3939
if presence == 'true':
4040
oper_status = db.get(db.STATE_DB, 'PSU_INFO|{}'.format(psu_name), 'status')
41-
status = 'OK' if oper_status == 'true' else "NOT OK"
41+
if oper_status == 'true':
42+
power_overload = db.get(db.STATE_DB, 'PSU_INFO|{}'.format(psu_name), 'power_overload')
43+
status = 'WARNING' if power_overload == 'True' else 'OK'
44+
else:
45+
status = "NOT OK"
4246
else:
4347
status = 'NOT PRESENT'
4448
psu_status['status'] = status

‎tests/mock_tables/state_db.json

+2
Original file line numberDiff line numberDiff line change
@@ -271,6 +271,7 @@
271271
"voltage_max_threshold": "None",
272272
"current": "8.37",
273273
"power": "102.7",
274+
"power_overload": "True",
274275
"is_replaceable": "False",
275276
"led_status": "green"
276277
},
@@ -287,6 +288,7 @@
287288
"voltage_max_threshold": "None",
288289
"current": "10.07",
289290
"power": "122.0",
291+
"power_overload": "False",
290292
"is_replaceable": "False",
291293
"led_status": "green"
292294
},

‎tests/psushow_test.py

+5-5
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ def test_get_psu_status_list(self):
3030
'index': '1',
3131
'name': 'PSU 1',
3232
'presence': 'true',
33-
'status': 'OK',
33+
'status': 'WARNING',
3434
'led_status': 'green',
3535
'model': '0J6J4K',
3636
'serial': 'CN-0J6J4K-17972-5AF-0086-A00',
@@ -61,7 +61,7 @@ def test_status_table(self, capsys):
6161
expected_output = '''\
6262
PSU Model Serial HW Rev Voltage (V) Current (A) Power (W) Status LED
6363
----- ------- ---------------------------- -------- ------------- ------------- ----------- -------- -----
64-
PSU 1 0J6J4K CN-0J6J4K-17972-5AF-0086-A00 1 12.19 8.37 102.70 OK green
64+
PSU 1 0J6J4K CN-0J6J4K-17972-5AF-0086-A00 1 12.19 8.37 102.70 WARNING green
6565
PSU 2 0J6J4K CN-0J6J4K-17972-5AF-008M-A00 A 12.18 10.07 122.00 OK green
6666
'''
6767
for arg in ['-s', '--status']:
@@ -74,7 +74,7 @@ def test_status_table(self, capsys):
7474
expected_output = '''\
7575
PSU Model Serial HW Rev Voltage (V) Current (A) Power (W) Status LED
7676
----- ------- ---------------------------- -------- ------------- ------------- ----------- -------- -----
77-
PSU 1 0J6J4K CN-0J6J4K-17972-5AF-0086-A00 1 12.19 8.37 102.70 OK green
77+
PSU 1 0J6J4K CN-0J6J4K-17972-5AF-0086-A00 1 12.19 8.37 102.70 WARNING green
7878
'''
7979
for arg in ['-s', '--status']:
8080
with mock.patch('sys.argv', ['psushow', arg, '-i', '1']):
@@ -114,7 +114,7 @@ def test_status_json(self, capsys):
114114
"index": "1",
115115
"name": "PSU 1",
116116
"presence": "true",
117-
"status": "OK",
117+
"status": "WARNING",
118118
"led_status": "green",
119119
"model": "0J6J4K",
120120
"serial": "CN-0J6J4K-17972-5AF-0086-A00",
@@ -151,7 +151,7 @@ def test_status_json(self, capsys):
151151
"index": "1",
152152
"name": "PSU 1",
153153
"presence": "true",
154-
"status": "OK",
154+
"status": "WARNING",
155155
"led_status": "green",
156156
"model": "0J6J4K",
157157
"serial": "CN-0J6J4K-17972-5AF-0086-A00",

‎tests/psuutil_test.py

+42
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import sys
22
import os
3+
from sonic_platform_base import device_base
34
from unittest import mock
45

56
import pytest
@@ -12,10 +13,51 @@
1213
sys.modules['sonic_platform'] = mock.MagicMock()
1314
import psuutil.main as psuutil
1415

16+
STATUS_OUTPUT = '''\
17+
PSU Model Serial HW Rev Voltage (V) Current (A) Power (W) Power Warn-supp Thres (W) Power Crit Thres (W) Status LED
18+
----- ----------- -------- -------- ------------- ------------- ----------- --------------------------- ---------------------- -------- -----
19+
PSU 1 SampleModel S001 Rev A 12.00 10.00 120.00 90.00 100.00 OK green
20+
'''
21+
22+
STATUS_OUTPUT_NOT_IMPLEMENT = '''\
23+
PSU Model Serial HW Rev Voltage (V) Current (A) Power (W) Power Warn-supp Thres (W) Power Crit Thres (W) Status LED
24+
----- ----------- -------- -------- ------------- ------------- ----------- --------------------------- ---------------------- -------- -----
25+
PSU 1 SampleModel S001 N/A 12.00 10.00 120.00 N/A N/A OK green
26+
'''
1527

1628
class TestPsuutil(object):
1729

1830
def test_version(self):
1931
runner = CliRunner()
2032
result = runner.invoke(psuutil.cli.commands['version'], [])
2133
assert result.output.rstrip() == 'psuutil version {}'.format(psuutil.VERSION)
34+
35+
@mock.patch('psuutil.main.load_platform_chassis', mock.MagicMock(return_value=True))
36+
@mock.patch('psuutil.main.platform_chassis')
37+
def test_psuutil_status(self, platform_chassis):
38+
psu = mock.MagicMock()
39+
psu.get_name = mock.MagicMock(return_value='PSU 1')
40+
psu.get_presence = mock.MagicMock(return_value=True)
41+
psu.get_powergood_status = mock.MagicMock(return_value=True)
42+
psu.get_psu_power_critical_threshold = mock.MagicMock(return_value=100.0)
43+
psu.get_psu_power_warning_suppress_threshold = mock.MagicMock(return_value=90.0)
44+
psu.get_model = mock.MagicMock(return_value='SampleModel')
45+
psu.get_serial = mock.MagicMock(return_value='S001')
46+
psu.get_revision = mock.MagicMock(return_value='Rev A')
47+
psu.get_voltage = mock.MagicMock(return_value=12.0)
48+
psu.get_current = mock.MagicMock(return_value=10.0)
49+
psu.get_power = mock.MagicMock(return_value=120.0)
50+
psu.get_status_led = mock.MagicMock(return_value='green')
51+
52+
psu_list = [psu]
53+
platform_chassis.get_all_psus = mock.MagicMock(return_value=psu_list)
54+
55+
runner = CliRunner()
56+
result = runner.invoke(psuutil.cli.commands['status'])
57+
assert result.output == STATUS_OUTPUT
58+
59+
psu.get_psu_power_critical_threshold = mock.MagicMock(side_effect=NotImplementedError(''))
60+
psu.get_revision = mock.MagicMock(side_effect=NotImplementedError(''))
61+
runner = CliRunner()
62+
result = runner.invoke(psuutil.cli.commands['status'])
63+
assert result.output == STATUS_OUTPUT_NOT_IMPLEMENT

0 commit comments

Comments
 (0)
Please sign in to comment.