Skip to content

Commit

Permalink
[psushow] Get PSU status from DB directly (sonic-net#464)
Browse files Browse the repository at this point in the history
* Access DB directly to get the PSU status information
* Add test case for psu CLI

Signed-off-by: Kevin Wang <kevinw@mellanox.com>
  • Loading branch information
kevinwangsk authored and jleveque committed Mar 6, 2019
1 parent 3fc45d7 commit f452ec4
Show file tree
Hide file tree
Showing 6 changed files with 150 additions and 1 deletion.
83 changes: 83 additions & 0 deletions scripts/psushow
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
#! /usr/bin/python

import argparse
import sys
import os
from swsssdk import SonicV2Connector
from tabulate import tabulate

# mock the redis for unit test purposes #
try:
if os.environ["UTILITIES_UNIT_TESTING"] == "1":
modules_path = os.path.join(os.path.dirname(__file__), "..")
test_path = os.path.join(modules_path, "sonic-utilities-tests")
sys.path.insert(0, modules_path)
sys.path.insert(0, test_path)
import mock_tables.dbconnector
except KeyError:
pass

def psu_status_show(index):
db = SonicV2Connector(host="127.0.0.1")
db.connect(db.STATE_DB)

# Currently set chassis_num to 1, need to improve it once new platform API is implemented
chassis_num = 1
chassis_name = "chassis {}".format(chassis_num)
num_psus = db.get(db.STATE_DB, 'CHASSIS_INFO|{}'.format(chassis_name), 'num_psus')
if not num_psus:
print "Error! Failed to get the number of PSUs!"
return -1

supported_psu = range(1, int(num_psus) + 1)
if (index < 0):
psu_ids = supported_psu
else:
psu_ids = [index]

header = ['PSU', 'Status']
status_table = []

for psu in psu_ids:
msg = ""
psu_name = "PSU {}".format(psu)
if psu not in supported_psu:
print "Error! The {} is not available on the platform.\n" \
"Number of supported PSU - {}.".format(psu_name, num_psus)
continue
presence = db.get(db.STATE_DB, 'PSU_INFO|{}'.format(psu_name), 'presence')
if presence == 'true':
oper_status = db.get(db.STATE_DB, 'PSU_INFO|{}'.format(psu_name), 'status')
msg = 'OK' if oper_status == 'true' else "NOT OK"
else:
msg = 'NOT PRESENT'
status_table.append([psu_name, msg])

if status_table:
print tabulate(status_table, header, tablefmt="simple")
return 0

def main():
parser = argparse.ArgumentParser(description='Display the psu status information',
version='1.0.0',
formatter_class=argparse.RawTextHelpFormatter,
epilog="""
Examples:
psushow -s -i 1
""")

parser.add_argument('-s', '--status', action='store_true', help='show the status information')
parser.add_argument('-i', '--index', type=int, default=-1, help='the index of psu')
args = parser.parse_args()

status_show = args.status
psu_index = args.index
if status_show:
err = psu_status_show(psu_index)
if err:
print "Error: fail to get psu status from state DB"
sys.exit(1)

if __name__ == "__main__":
main()

1 change: 1 addition & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ def get_test_suite():
'scripts/portconfig',
'scripts/portstat',
'scripts/pfcstat',
'scripts/psushow',
'scripts/queuestat',
'scripts/reboot',
'scripts/teamshow',
Expand Down
2 changes: 1 addition & 1 deletion show/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -1133,7 +1133,7 @@ def syseeprom(verbose):
@click.option('--verbose', is_flag=True, help="Enable verbose output")
def psustatus(index, verbose):
"""Show PSU status information"""
cmd = "sudo psuutil status"
cmd = "psushow -s"

if index >= 0:
cmd += " -i {}".format(index)
Expand Down
2 changes: 2 additions & 0 deletions sonic-utilities-tests/mock_tables/dbconnector.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ def __init__(self, *args, **kwargs):
fname = 'counters_db.json'
elif db == 4:
fname = 'config_db.json'
elif db == 6:
fname = 'state_db.json'
else:
raise ValueError("Invalid db")
self.pubsub = MockPubSub()
Expand Down
14 changes: 14 additions & 0 deletions sonic-utilities-tests/mock_tables/state_db.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"CHASSIS_INFO|chassis 1": {
"num_psus": "2"
},
"PSU_INFO|PSU 1": {
"presence": "true",
"status": "true"
},
"PSU_INFO|PSU 2": {
"presence": "true",
"status": "true"
}
}

49 changes: 49 additions & 0 deletions sonic-utilities-tests/psu_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import sys
import os
from click.testing import CliRunner

test_path = os.path.dirname(os.path.abspath(__file__))
modules_path = os.path.dirname(test_path)
scripts_path = os.path.join(modules_path, "scripts")
sys.path.insert(0, modules_path)

import show.main as show

class TestPsu(object):
@classmethod
def setup_class(cls):
print("SETUP")
os.environ["PATH"] += os.pathsep + scripts_path
os.environ["UTILITIES_UNIT_TESTING"] = "1"

def test_no_param(self):
runner = CliRunner()
result = runner.invoke(show.cli.commands["platform"].commands["psustatus"], [])
print(result.output)
result_lines = result.output.strip('\n').split('\n')
psus = ["PSU 1", "PSU 2"]
for i, psu in enumerate(psus):
assert psu in result_lines[i+2]
header_lines = 2
assert len(result_lines) == header_lines + len(psus)

def test_verbose(self):
runner = CliRunner()
result = runner.invoke(show.cli.commands["platform"].commands["psustatus"], ["--verbose"])
print(result.output)
assert result.output.split('\n')[0] == "Command: psushow -s"

def test_single_psu(self):
runner = CliRunner()
result = runner.invoke(show.cli.commands["platform"].commands["psustatus"], ["--index=1"])
expected = """PSU Status
----- --------
PSU 1 OK
"""
assert result.output == expected

def teardown_class(cls):
print("TEARDOWN")
os.environ["PATH"] = os.pathsep.join(os.environ["PATH"].split(os.pathsep)[:-1])
os.environ["UTILITIES_UNIT_TESTING"] = "0"

0 comments on commit f452ec4

Please sign in to comment.