Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 62e44d9

Browse files
authoredAug 27, 2020
[CLI][PFC] Add multi ASIC options for pfcstat and 'show pfc counters' (sonic-net#1057)
* Add multi ASIC options for pfcstat and 'show pfc counters' Options: -d, --display [all|frontend] Show internal interfaces [default:frontend] -n, --namespace [asic0|asic1|asic2|asic3|asic4|asic5] * Added unit tests for 'pfcstat' show commands.
1 parent 58c2961 commit 62e44d9

File tree

7 files changed

+455
-68
lines changed

7 files changed

+455
-68
lines changed
 

‎scripts/pfcstat

+80-22
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,10 @@
22

33
#####################################################################
44
#
5-
# pfcstat is a tool for summarizing Priority-based Flow Control (PFC) statistics.
5+
# pfcstat is a tool for summarizing Priority-based Flow Control (PFC) statistics.
66
#
77
#####################################################################
88

9-
import swsssdk
109
import sys
1110
import argparse
1211
import cPickle as pickle
@@ -17,6 +16,24 @@ from collections import namedtuple, OrderedDict
1716
from natsort import natsorted
1817
from tabulate import tabulate
1918

19+
from sonic_py_common.multi_asic import get_external_ports
20+
from utilities_common import multi_asic as multi_asic_util
21+
from utilities_common import constants
22+
23+
# mock the redis for unit test purposes #
24+
try:
25+
if os.environ["UTILITIES_UNIT_TESTING"] == "2":
26+
modules_path = os.path.join(os.path.dirname(__file__), "..")
27+
tests_path = os.path.join(modules_path, "tests")
28+
sys.path.insert(0, modules_path)
29+
sys.path.insert(0, tests_path)
30+
import mock_tables.dbconnector
31+
if os.environ["UTILITIES_UNIT_TESTING_TOPOLOGY"] == "multi_asic":
32+
import mock_tables.mock_multi_asic
33+
mock_tables.dbconnector.load_namespace_config()
34+
35+
except KeyError:
36+
pass
2037

2138
PStats = namedtuple("PStats", "pfc0, pfc1, pfc2, pfc3, pfc4, pfc5, pfc6, pfc7")
2239
header_Rx = ['Port Rx', 'PFC0', 'PFC1', 'PFC2', 'PFC3', 'PFC4', 'PFC5', 'PFC6', 'PFC7']
@@ -51,11 +68,14 @@ COUNTER_TABLE_PREFIX = "COUNTERS:"
5168
COUNTERS_PORT_NAME_MAP = "COUNTERS_PORT_NAME_MAP"
5269

5370
class Pfcstat(object):
54-
def __init__(self):
55-
self.db = swsssdk.SonicV2Connector(host='127.0.0.1')
56-
self.db.connect(self.db.COUNTERS_DB)
57-
58-
def get_cnstat(self, rx):
71+
def __init__(self, namespace, display):
72+
self.multi_asic = multi_asic_util.MultiAsic(display, namespace)
73+
self.db = None
74+
self.config_db = None
75+
self.cnstat_dict = OrderedDict()
76+
77+
@multi_asic_util.run_on_multi_asic
78+
def collect_cnstat(self, rx):
5979
"""
6080
Get the counters info from database.
6181
"""
@@ -70,7 +90,9 @@ class Pfcstat(object):
7090
bucket_dict = counter_bucket_tx_dict
7191
for counter_name, pos in bucket_dict.iteritems():
7292
full_table_id = COUNTER_TABLE_PREFIX + table_id
73-
counter_data = self.db.get(self.db.COUNTERS_DB, full_table_id, counter_name)
93+
counter_data = self.db.get(
94+
self.db.COUNTERS_DB, full_table_id, counter_name
95+
)
7496
if counter_data is None:
7597
fields[pos] = STATUS_NA
7698
else:
@@ -79,15 +101,34 @@ class Pfcstat(object):
79101
return cntr
80102

81103
# Get the info from database
82-
counter_port_name_map = self.db.get_all(self.db.COUNTERS_DB, COUNTERS_PORT_NAME_MAP)
104+
counter_port_name_map = self.db.get_all(
105+
self.db.COUNTERS_DB, COUNTERS_PORT_NAME_MAP
106+
)
107+
if counter_port_name_map is None:
108+
return
109+
display_ports_set = set(counter_port_name_map.keys())
110+
if self.multi_asic.display_option == constants.DISPLAY_EXTERNAL:
111+
display_ports_set = get_external_ports(
112+
display_ports_set, self.multi_asic.current_namespace
113+
)
83114
# Build a dictionary of the stats
84115
cnstat_dict = OrderedDict()
85116
cnstat_dict['time'] = datetime.datetime.now()
86-
if counter_port_name_map is None:
87-
return cnstat_dict
88-
for port in natsorted(counter_port_name_map):
89-
cnstat_dict[port] = get_counters(counter_port_name_map[port])
90-
return cnstat_dict
117+
if counter_port_name_map is not None:
118+
for port in natsorted(counter_port_name_map):
119+
if port in display_ports_set:
120+
cnstat_dict[port] = get_counters(
121+
counter_port_name_map[port]
122+
)
123+
self.cnstat_dict.update(cnstat_dict)
124+
125+
def get_cnstat(self, rx):
126+
"""
127+
Get the counters info from database.
128+
"""
129+
self.cnstat_dict.clear()
130+
self.collect_cnstat(rx)
131+
return self.cnstat_dict
91132

92133
def cnstat_print(self, cnstat_dict, rx):
93134
"""
@@ -163,10 +204,22 @@ Examples:
163204
pfcstat
164205
pfcstat -c
165206
pfcstat -d
207+
pfcstat -n asic1
208+
pfcstat -s all -n asic0
166209
""")
167210

168-
parser.add_argument('-c', '--clear', action='store_true', help='Clear previous stats and save new ones')
169-
parser.add_argument('-d', '--delete', action='store_true', help='Delete saved stats')
211+
parser.add_argument( '-c', '--clear', action='store_true',
212+
help='Clear previous stats and save new ones'
213+
)
214+
parser.add_argument(
215+
'-d', '--delete', action='store_true', help='Delete saved stats'
216+
)
217+
parser.add_argument('-s', '--show', default=constants.DISPLAY_EXTERNAL,
218+
help='Display all interfaces or only external interfaces'
219+
)
220+
parser.add_argument('-n', '--namespace', default=None,
221+
help='Display interfaces for specific namespace'
222+
)
170223
args = parser.parse_args()
171224

172225
save_fresh_stats = args.clear
@@ -175,15 +228,20 @@ Examples:
175228
uid = str(os.getuid())
176229
cnstat_file = uid
177230

178-
cnstat_dir = "/tmp/pfcstat-" + uid
179-
cnstat_fqn_file_rx = cnstat_dir + "/" + cnstat_file + "rx"
180-
cnstat_fqn_file_tx = cnstat_dir + "/" + cnstat_file + "tx"
231+
cnstat_dir = os.path.join(os.sep, "tmp", "pfcstat-{}".format(uid))
232+
cnstat_fqn_file_rx = os.path.join(cnstat_dir, "{}rx".format(cnstat_file))
233+
cnstat_fqn_file_tx = os.path.join(cnstat_dir, "{}tx".format(cnstat_file))
234+
235+
# if '-c' option is provided get stats from all (frontend and backend) ports
236+
if save_fresh_stats:
237+
args.namespace = None
238+
args.show = constants.DISPLAY_ALL
181239

182-
pfcstat = Pfcstat()
240+
pfcstat = Pfcstat(args.namespace, args.show)
183241

184242
if delete_all_stats:
185243
for file in os.listdir(cnstat_dir):
186-
os.remove(cnstat_dir + "/" + file)
244+
os.remove(os.path.join(cnstat_dir, file))
187245

188246
try:
189247
os.rmdir(cnstat_dir)
@@ -235,7 +293,7 @@ Examples:
235293
else:
236294
pfcstat.cnstat_print(cnstat_dict_rx, True)
237295

238-
print()
296+
print("")
239297

240298
"""
241299
Print the counters of pfc tx counter

‎show/main.py

+8-3
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,10 @@
1616
from swsssdk import ConfigDBConnector
1717
from swsssdk import SonicV2Connector
1818
from tabulate import tabulate
19-
from utilities_common.db import Db
19+
2020
import utilities_common.cli as clicommon
21+
from utilities_common.db import Db
22+
from utilities_common.multi_asic import multi_asic_click_options
2123

2224
import mlnx
2325
import feature
@@ -366,11 +368,14 @@ def pfc():
366368

367369
# 'counters' subcommand ("show interfaces pfccounters")
368370
@pfc.command()
371+
@multi_asic_click_options
369372
@click.option('--verbose', is_flag=True, help="Enable verbose output")
370-
def counters(verbose):
373+
def counters(namespace, display, verbose):
371374
"""Show pfc counters"""
372375

373-
cmd = "pfcstat"
376+
cmd = "pfcstat -s {}".format(display)
377+
if namespace is not None:
378+
cmd += " -n {}".format(namespace)
374379

375380
run_command(cmd, display_cmd=verbose)
376381

‎tests/mock_tables/asic0/counters_db.json

+78-7
Original file line numberDiff line numberDiff line change
@@ -123,27 +123,98 @@
123123
"SAI_PORT_STAT_IF_IN_ERRORS": "10",
124124
"SAI_PORT_STAT_IF_IN_DISCARDS": "100",
125125
"SAI_PORT_STAT_IN_DROP_REASON_RANGE_BASE": "80",
126-
"SAI_PORT_STAT_OUT_CONFIGURED_DROP_REASONS_1_DROPPED_PKTS": "20"
126+
"SAI_PORT_STAT_OUT_CONFIGURED_DROP_REASONS_1_DROPPED_PKTS": "20",
127+
"SAI_PORT_STAT_PFC_0_RX_PKTS": "20",
128+
"SAI_PORT_STAT_PFC_1_RX_PKTS": "21",
129+
"SAI_PORT_STAT_PFC_2_RX_PKTS": "22",
130+
"SAI_PORT_STAT_PFC_3_RX_PKTS": "23",
131+
"SAI_PORT_STAT_PFC_4_RX_PKTS": "24",
132+
"SAI_PORT_STAT_PFC_5_RX_PKTS": "25",
133+
"SAI_PORT_STAT_PFC_6_RX_PKTS": "26",
134+
"SAI_PORT_STAT_PFC_7_RX_PKTS": "27",
135+
"SAI_PORT_STAT_PFC_0_TX_PKTS": "400",
136+
"SAI_PORT_STAT_PFC_1_TX_PKTS": "201",
137+
"SAI_PORT_STAT_PFC_2_TX_PKTS": "202",
138+
"SAI_PORT_STAT_PFC_3_TX_PKTS": "203",
139+
"SAI_PORT_STAT_PFC_4_TX_PKTS": "204",
140+
"SAI_PORT_STAT_PFC_5_TX_PKTS": "205",
141+
"SAI_PORT_STAT_PFC_6_TX_PKTS": "206",
142+
"SAI_PORT_STAT_PFC_7_TX_PKTS": "207"
127143
},
128144
"COUNTERS:oid:0x1000000000004": {
129145
"SAI_PORT_STAT_IF_IN_ERRORS": "0",
130146
"SAI_PORT_STAT_IF_IN_DISCARDS": "1000",
131147
"SAI_PORT_STAT_IN_DROP_REASON_RANGE_BASE": "800",
132-
"SAI_PORT_STAT_OUT_CONFIGURED_DROP_REASONS_1_DROPPED_PKTS": "100"
148+
"SAI_PORT_STAT_OUT_CONFIGURED_DROP_REASONS_1_DROPPED_PKTS": "100",
149+
"SAI_PORT_STAT_PFC_0_RX_PKTS": "40",
150+
"SAI_PORT_STAT_PFC_1_RX_PKTS": "41",
151+
"SAI_PORT_STAT_PFC_2_RX_PKTS": "42",
152+
"SAI_PORT_STAT_PFC_3_RX_PKTS": "43",
153+
"SAI_PORT_STAT_PFC_4_RX_PKTS": "44",
154+
"SAI_PORT_STAT_PFC_5_RX_PKTS": "45",
155+
"SAI_PORT_STAT_PFC_6_RX_PKTS": "46",
156+
"SAI_PORT_STAT_PFC_7_RX_PKTS": "47",
157+
"SAI_PORT_STAT_PFC_0_TX_PKTS": "400",
158+
"SAI_PORT_STAT_PFC_1_TX_PKTS": "401",
159+
"SAI_PORT_STAT_PFC_2_TX_PKTS": "402",
160+
"SAI_PORT_STAT_PFC_3_TX_PKTS": "403",
161+
"SAI_PORT_STAT_PFC_4_TX_PKTS": "404",
162+
"SAI_PORT_STAT_PFC_5_TX_PKTS": "405",
163+
"SAI_PORT_STAT_PFC_6_TX_PKTS": "406",
164+
"SAI_PORT_STAT_PFC_7_TX_PKTS": "407"
133165
},
134166
"COUNTERS:oid:0x1000000000006": {
135-
"SAI_PORT_STAT_IF_IN_ERRORS": "100",
136-
"SAI_PORT_STAT_IF_IN_DISCARDS": "10",
137-
"SAI_PORT_STAT_IN_DROP_REASON_RANGE_BASE": "10",
138-
"SAI_PORT_STAT_OUT_CONFIGURED_DROP_REASONS_1_DROPPED_PKTS": "0"
167+
"SAI_PORT_STAT_IF_IN_ERRORS": "0",
168+
"SAI_PORT_STAT_IF_IN_DISCARDS": "1000",
169+
"SAI_PORT_STAT_IN_DROP_REASON_RANGE_BASE": "800",
170+
"SAI_PORT_STAT_OUT_CONFIGURED_DROP_REASONS_1_DROPPED_PKTS": "100",
171+
"SAI_PORT_STAT_PFC_0_RX_PKTS": "60",
172+
"SAI_PORT_STAT_PFC_1_RX_PKTS": "61",
173+
"SAI_PORT_STAT_PFC_2_RX_PKTS": "62",
174+
"SAI_PORT_STAT_PFC_3_RX_PKTS": "63",
175+
"SAI_PORT_STAT_PFC_4_RX_PKTS": "64",
176+
"SAI_PORT_STAT_PFC_5_RX_PKTS": "65",
177+
"SAI_PORT_STAT_PFC_6_RX_PKTS": "66",
178+
"SAI_PORT_STAT_PFC_7_RX_PKTS": "67",
179+
"SAI_PORT_STAT_PFC_0_TX_PKTS": "600",
180+
"SAI_PORT_STAT_PFC_1_TX_PKTS": "601",
181+
"SAI_PORT_STAT_PFC_2_TX_PKTS": "602",
182+
"SAI_PORT_STAT_PFC_3_TX_PKTS": "603",
183+
"SAI_PORT_STAT_PFC_4_TX_PKTS": "604",
184+
"SAI_PORT_STAT_PFC_5_TX_PKTS": "605",
185+
"SAI_PORT_STAT_PFC_6_TX_PKTS": "606",
186+
"SAI_PORT_STAT_PFC_7_TX_PKTS": "607"
187+
},
188+
"COUNTERS:oid:0x1000000000008": {
189+
"SAI_PORT_STAT_IF_IN_ERRORS": "0",
190+
"SAI_PORT_STAT_IF_IN_DISCARDS": "1000",
191+
"SAI_PORT_STAT_IN_DROP_REASON_RANGE_BASE": "800",
192+
"SAI_PORT_STAT_OUT_CONFIGURED_DROP_REASONS_1_DROPPED_PKTS": "100",
193+
"SAI_PORT_STAT_PFC_0_RX_PKTS": "80",
194+
"SAI_PORT_STAT_PFC_1_RX_PKTS": "81",
195+
"SAI_PORT_STAT_PFC_2_RX_PKTS": "82",
196+
"SAI_PORT_STAT_PFC_3_RX_PKTS": "83",
197+
"SAI_PORT_STAT_PFC_4_RX_PKTS": "84",
198+
"SAI_PORT_STAT_PFC_5_RX_PKTS": "85",
199+
"SAI_PORT_STAT_PFC_6_RX_PKTS": "86",
200+
"SAI_PORT_STAT_PFC_7_RX_PKTS": "87",
201+
"SAI_PORT_STAT_PFC_0_TX_PKTS": "800",
202+
"SAI_PORT_STAT_PFC_1_TX_PKTS": "801",
203+
"SAI_PORT_STAT_PFC_2_TX_PKTS": "802",
204+
"SAI_PORT_STAT_PFC_3_TX_PKTS": "803",
205+
"SAI_PORT_STAT_PFC_4_TX_PKTS": "804",
206+
"SAI_PORT_STAT_PFC_5_TX_PKTS": "805",
207+
"SAI_PORT_STAT_PFC_6_TX_PKTS": "806",
208+
"SAI_PORT_STAT_PFC_7_TX_PKTS": "807"
139209
},
140210
"COUNTERS:oid:0x21000000000000": {
141211
"SAI_SWITCH_STAT_IN_DROP_REASON_RANGE_BASE": "1000"
142212
},
143213
"COUNTERS_PORT_NAME_MAP": {
144214
"Ethernet0": "oid:0x1000000000002",
145215
"Ethernet4": "oid:0x1000000000004",
146-
"Ethernet8": "oid:0x1000000000006"
216+
"Ethernet-BP0": "oid:0x1000000000006",
217+
"Ethernet-BP4": "oid:0x1000000000008"
147218
},
148219
"COUNTERS_LAG_NAME_MAP": {
149220
"PortChannel0001": "oid:0x60000000005a1",

‎tests/mock_tables/counters_db.json

+51-3
Original file line numberDiff line numberDiff line change
@@ -123,19 +123,67 @@
123123
"SAI_PORT_STAT_IF_IN_ERRORS": "10",
124124
"SAI_PORT_STAT_IF_IN_DISCARDS": "100",
125125
"SAI_PORT_STAT_IN_DROP_REASON_RANGE_BASE": "80",
126-
"SAI_PORT_STAT_OUT_CONFIGURED_DROP_REASONS_1_DROPPED_PKTS": "20"
126+
"SAI_PORT_STAT_OUT_CONFIGURED_DROP_REASONS_1_DROPPED_PKTS": "20",
127+
"SAI_PORT_STAT_PFC_0_RX_PKTS": "0",
128+
"SAI_PORT_STAT_PFC_1_RX_PKTS": "0",
129+
"SAI_PORT_STAT_PFC_2_RX_PKTS": "0",
130+
"SAI_PORT_STAT_PFC_3_RX_PKTS": "0",
131+
"SAI_PORT_STAT_PFC_4_RX_PKTS": "0",
132+
"SAI_PORT_STAT_PFC_5_RX_PKTS": "0",
133+
"SAI_PORT_STAT_PFC_6_RX_PKTS": "0",
134+
"SAI_PORT_STAT_PFC_7_RX_PKTS": "0",
135+
"SAI_PORT_STAT_PFC_0_TX_PKTS": "0",
136+
"SAI_PORT_STAT_PFC_1_TX_PKTS": "0",
137+
"SAI_PORT_STAT_PFC_2_TX_PKTS": "0",
138+
"SAI_PORT_STAT_PFC_3_TX_PKTS": "0",
139+
"SAI_PORT_STAT_PFC_4_TX_PKTS": "0",
140+
"SAI_PORT_STAT_PFC_5_TX_PKTS": "0",
141+
"SAI_PORT_STAT_PFC_6_TX_PKTS": "0",
142+
"SAI_PORT_STAT_PFC_7_TX_PKTS": "0"
127143
},
128144
"COUNTERS:oid:0x1000000000004": {
129145
"SAI_PORT_STAT_IF_IN_ERRORS": "0",
130146
"SAI_PORT_STAT_IF_IN_DISCARDS": "1000",
131147
"SAI_PORT_STAT_IN_DROP_REASON_RANGE_BASE": "800",
132-
"SAI_PORT_STAT_OUT_CONFIGURED_DROP_REASONS_1_DROPPED_PKTS": "100"
148+
"SAI_PORT_STAT_OUT_CONFIGURED_DROP_REASONS_1_DROPPED_PKTS": "100",
149+
"SAI_PORT_STAT_PFC_0_RX_PKTS": "40",
150+
"SAI_PORT_STAT_PFC_1_RX_PKTS": "41",
151+
"SAI_PORT_STAT_PFC_2_RX_PKTS": "42",
152+
"SAI_PORT_STAT_PFC_3_RX_PKTS": "43",
153+
"SAI_PORT_STAT_PFC_4_RX_PKTS": "44",
154+
"SAI_PORT_STAT_PFC_5_RX_PKTS": "45",
155+
"SAI_PORT_STAT_PFC_6_RX_PKTS": "46",
156+
"SAI_PORT_STAT_PFC_7_RX_PKTS": "47",
157+
"SAI_PORT_STAT_PFC_0_TX_PKTS": "400",
158+
"SAI_PORT_STAT_PFC_1_TX_PKTS": "401",
159+
"SAI_PORT_STAT_PFC_2_TX_PKTS": "402",
160+
"SAI_PORT_STAT_PFC_3_TX_PKTS": "403",
161+
"SAI_PORT_STAT_PFC_4_TX_PKTS": "404",
162+
"SAI_PORT_STAT_PFC_5_TX_PKTS": "405",
163+
"SAI_PORT_STAT_PFC_6_TX_PKTS": "406",
164+
"SAI_PORT_STAT_PFC_7_TX_PKTS": "407"
133165
},
134166
"COUNTERS:oid:0x1000000000006": {
135167
"SAI_PORT_STAT_IF_IN_ERRORS": "100",
136168
"SAI_PORT_STAT_IF_IN_DISCARDS": "10",
137169
"SAI_PORT_STAT_IN_DROP_REASON_RANGE_BASE": "10",
138-
"SAI_PORT_STAT_OUT_CONFIGURED_DROP_REASONS_1_DROPPED_PKTS": "0"
170+
"SAI_PORT_STAT_OUT_CONFIGURED_DROP_REASONS_1_DROPPED_PKTS": "0",
171+
"SAI_PORT_STAT_PFC_0_RX_PKTS": "80",
172+
"SAI_PORT_STAT_PFC_1_RX_PKTS": "81",
173+
"SAI_PORT_STAT_PFC_2_RX_PKTS": "82",
174+
"SAI_PORT_STAT_PFC_3_RX_PKTS": "83",
175+
"SAI_PORT_STAT_PFC_4_RX_PKTS": "84",
176+
"SAI_PORT_STAT_PFC_5_RX_PKTS": "85",
177+
"SAI_PORT_STAT_PFC_6_RX_PKTS": "86",
178+
"SAI_PORT_STAT_PFC_7_RX_PKTS": "87",
179+
"SAI_PORT_STAT_PFC_0_TX_PKTS": "800",
180+
"SAI_PORT_STAT_PFC_1_TX_PKTS": "801",
181+
"SAI_PORT_STAT_PFC_2_TX_PKTS": "802",
182+
"SAI_PORT_STAT_PFC_3_TX_PKTS": "803",
183+
"SAI_PORT_STAT_PFC_4_TX_PKTS": "804",
184+
"SAI_PORT_STAT_PFC_5_TX_PKTS": "805",
185+
"SAI_PORT_STAT_PFC_6_TX_PKTS": "806",
186+
"SAI_PORT_STAT_PFC_7_TX_PKTS": "807"
139187
},
140188
"COUNTERS:oid:0x21000000000000": {
141189
"SAI_SWITCH_STAT_IN_DROP_REASON_RANGE_BASE": "1000"

‎tests/multi_asic_intfutil_test.py

+23-33
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33

44
from click.testing import CliRunner
55

6+
from utils import get_result_and_return_code
7+
68
root_path = os.path.dirname(os.path.abspath(__file__))
79
modules_path = os.path.dirname(root_path)
810
scripts_path = os.path.join(modules_path, "scripts")
@@ -93,85 +95,73 @@ def setup_class(cls):
9395
def setUp(self):
9496
self.runner = CliRunner()
9597

96-
def get_result_and_return_code(self, cmd):
97-
return_code = 0
98-
try:
99-
output = subprocess.check_output(
100-
cmd, stderr=subprocess.STDOUT, shell=True)
101-
except subprocess.CalledProcessError as e:
102-
return_code = e.returncode
103-
#store only the error, no need for the traceback
104-
output = e.output.strip().split("\n")[-1]
105-
106-
return(return_code, output)
107-
10898
def test_multi_asic_interface_status_all(self):
109-
return_code, result = self.get_result_and_return_code( 'intfutil -c status -d all')
99+
return_code, result = get_result_and_return_code( 'intfutil -c status -d all')
110100
print("return_code: {}".format(return_code))
111-
print("result = {}".format(result))
101+
print("result = {}".format(result))
112102
assert return_code == 0
113103
assert result == intf_status_all
114104

115105
def test_multi_asic_interface_status(self):
116-
return_code, result = self.get_result_and_return_code('intfutil -c status')
106+
return_code, result = get_result_and_return_code('intfutil -c status')
117107
print("return_code: {}".format(return_code))
118-
print("result = {}".format(result))
108+
print("result = {}".format(result))
119109
assert return_code == 0
120110
assert result == intf_status
121111

122112
def test_multi_asic_interface_status_asic0_all(self):
123-
return_code, result = self.get_result_and_return_code('intfutil -c status -n asic0 -d all')
113+
return_code, result = get_result_and_return_code('intfutil -c status -n asic0 -d all')
124114
print("return_code: {}".format(return_code))
125-
print("result = {}".format(result))
115+
print("result = {}".format(result))
126116
assert return_code == 0
127117
assert result == intf_status_asic0_all
128118

129119
def test_multi_asic_interface_status_asic0(self):
130-
return_code, result = self.get_result_and_return_code('intfutil -c status -n asic0')
120+
return_code, result = get_result_and_return_code('intfutil -c status -n asic0')
131121
print("return_code: {}".format(return_code))
132-
print("result = {}".format(result))
122+
print("result = {}".format(result))
133123
assert return_code == 0
134124
assert result == intf_status_asic0
135125

136126
def test_multi_asic_interface_desc(self):
137-
return_code, result = self.get_result_and_return_code('intfutil -c description')
127+
return_code, result = get_result_and_return_code('intfutil -c description')
138128
print("return_code: {}".format(return_code))
139-
print("result = {}".format(result))
129+
print("result = {}".format(result))
140130
assert return_code == 0
141131
assert result == intf_description
142132

143133
def test_multi_asic_interface_desc_all(self):
144-
return_code, result = self.get_result_and_return_code( 'intfutil -c description -d all')
134+
return_code, result = get_result_and_return_code( 'intfutil -c description -d all')
145135
print("return_code: {}".format(return_code))
146-
print("result = {}".format(result))
136+
print("result = {}".format(result))
147137
assert return_code == 0
148138
assert result == intf_description_all
149139

150140
def test_multi_asic_interface_asic0(self):
151-
return_code, result = self.get_result_and_return_code( 'intfutil -c description -n asic0')
141+
return_code, result = get_result_and_return_code( 'intfutil -c description -n asic0')
152142
print("return_code: {}".format(return_code))
153-
print("result = {}".format(result))
143+
print("result = {}".format(result))
154144
assert return_code == 0
155145
assert result == intf_description_asic0
156146

157147
def test_multi_asic_interface_desc_asic0_all(self):
158-
return_code, result = self.get_result_and_return_code('intfutil -c description -n asic0 -d all')
148+
return_code, result = get_result_and_return_code('intfutil -c description -n asic0 -d all')
159149
print("return_code: {}".format(return_code))
160-
print("result = {}".format(result))
150+
print("result = {}".format(result))
161151
assert return_code == 0
162152
assert result == intf_description_asic0_all
163-
153+
164154
def test_invalid_asic_name(self):
165-
return_code, result = self.get_result_and_return_code('intfutil -c description -n asic99 -d all')
155+
return_code, result = get_result_and_return_code('intfutil -c description -n asic99 -d all')
166156
print("return_code: {}".format(return_code))
167-
print("result = {}".format(result))
157+
print("result = {}".format(result))
168158
assert return_code == 1
169159
assert result == intf_invalid_asic_error
170160

171161
def test_invalid_asic_name(self):
172-
return_code, result = self.get_result_and_return_code('intfutil -c status -n asic99')
162+
return_code, result = get_result_and_return_code('intfutil -c status -n asic99')
173163
print("return_code: {}".format(return_code))
174-
print("result = {}".format(result))
164+
print("result = {}".format(result))
175165
assert return_code == 1
176166
assert result == intf_invalid_asic_error
177167

‎tests/pfcstat_test.py

+197
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,197 @@
1+
import imp
2+
import os
3+
import shutil
4+
import sys
5+
6+
from click.testing import CliRunner
7+
8+
import show.main as show
9+
10+
from utils import get_result_and_return_code
11+
12+
test_path = os.path.dirname(os.path.abspath(__file__))
13+
modules_path = os.path.dirname(test_path)
14+
scripts_path = os.path.join(modules_path, "scripts")
15+
16+
show_pfc_counters_output = """\
17+
Port Rx PFC0 PFC1 PFC2 PFC3 PFC4 PFC5 PFC6 PFC7
18+
--------- ------ ------ ------ ------ ------ ------ ------ ------
19+
Ethernet0 0 0 0 0 0 0 0 0
20+
Ethernet4 400 401 402 403 404 405 406 407
21+
Ethernet8 800 801 802 803 804 805 806 807
22+
23+
Port Tx PFC0 PFC1 PFC2 PFC3 PFC4 PFC5 PFC6 PFC7
24+
--------- ------ ------ ------ ------ ------ ------ ------ ------
25+
Ethernet0 0 0 0 0 0 0 0 0
26+
Ethernet4 400 401 402 403 404 405 406 407
27+
Ethernet8 800 801 802 803 804 805 806 807
28+
"""
29+
30+
show_pfc_counters_output_diff = """\
31+
Port Rx PFC0 PFC1 PFC2 PFC3 PFC4 PFC5 PFC6 PFC7
32+
--------- ------ ------ ------ ------ ------ ------ ------ ------
33+
Ethernet0 0 0 0 0 0 0 0 0
34+
Ethernet4 0 0 0 0 0 0 0 0
35+
Ethernet8 0 0 0 0 0 0 0 0
36+
37+
Port Tx PFC0 PFC1 PFC2 PFC3 PFC4 PFC5 PFC6 PFC7
38+
--------- ------ ------ ------ ------ ------ ------ ------ ------
39+
Ethernet0 0 0 0 0 0 0 0 0
40+
Ethernet4 0 0 0 0 0 0 0 0
41+
Ethernet8 0 0 0 0 0 0 0 0
42+
"""
43+
44+
show_pfc_counters_all = """\
45+
Port Rx PFC0 PFC1 PFC2 PFC3 PFC4 PFC5 PFC6 PFC7
46+
------------ ------ ------ ------ ------ ------ ------ ------ ------
47+
Ethernet0 400 201 202 203 204 205 206 207
48+
Ethernet4 400 401 402 403 404 405 406 407
49+
Ethernet-BP0 600 601 602 603 604 605 606 607
50+
Ethernet-BP4 800 801 802 803 804 805 806 807
51+
52+
Port Tx PFC0 PFC1 PFC2 PFC3 PFC4 PFC5 PFC6 PFC7
53+
------------ ------ ------ ------ ------ ------ ------ ------ ------
54+
Ethernet0 400 201 202 203 204 205 206 207
55+
Ethernet4 400 401 402 403 404 405 406 407
56+
Ethernet-BP0 600 601 602 603 604 605 606 607
57+
Ethernet-BP4 800 801 802 803 804 805 806 807
58+
"""
59+
60+
show_pfc_counters_asic0_frontend = """\
61+
Port Rx PFC0 PFC1 PFC2 PFC3 PFC4 PFC5 PFC6 PFC7
62+
--------- ------ ------ ------ ------ ------ ------ ------ ------
63+
Ethernet0 400 201 202 203 204 205 206 207
64+
Ethernet4 400 401 402 403 404 405 406 407
65+
66+
Port Tx PFC0 PFC1 PFC2 PFC3 PFC4 PFC5 PFC6 PFC7
67+
--------- ------ ------ ------ ------ ------ ------ ------ ------
68+
Ethernet0 400 201 202 203 204 205 206 207
69+
Ethernet4 400 401 402 403 404 405 406 407
70+
"""
71+
72+
show_pfc_counters_msaic_output_diff = """\
73+
Port Rx PFC0 PFC1 PFC2 PFC3 PFC4 PFC5 PFC6 PFC7
74+
------------ ------ ------ ------ ------ ------ ------ ------ ------
75+
Ethernet0 0 0 0 0 0 0 0 0
76+
Ethernet4 0 0 0 0 0 0 0 0
77+
Ethernet-BP0 0 0 0 0 0 0 0 0
78+
Ethernet-BP4 0 0 0 0 0 0 0 0
79+
80+
Port Tx PFC0 PFC1 PFC2 PFC3 PFC4 PFC5 PFC6 PFC7
81+
------------ ------ ------ ------ ------ ------ ------ ------ ------
82+
Ethernet0 0 0 0 0 0 0 0 0
83+
Ethernet4 0 0 0 0 0 0 0 0
84+
Ethernet-BP0 0 0 0 0 0 0 0 0
85+
Ethernet-BP4 0 0 0 0 0 0 0 0
86+
"""
87+
88+
89+
def pfc_clear(expected_output):
90+
counters_file_list = ['0tx', '0rx']
91+
uid = str(os.getuid())
92+
cnstat_dir = os.path.join(os.sep, "tmp", "pfcstat-{}".format(uid))
93+
shutil.rmtree(cnstat_dir, ignore_errors=True, onerror=None)
94+
95+
return_code, result = get_result_and_return_code(
96+
'pfcstat -c'
97+
)
98+
99+
# verify that files are created with stats
100+
cnstat_fqn_file_rx = "{}rx".format(uid)
101+
cnstat_fqn_file_tx = "{}tx".format(uid)
102+
file_list = [cnstat_fqn_file_tx, cnstat_fqn_file_rx]
103+
file_list.sort()
104+
files = os.listdir(cnstat_dir)
105+
files.sort()
106+
assert files == file_list
107+
108+
return_code, result = get_result_and_return_code(
109+
'pfcstat -s all'
110+
)
111+
result_stat = [s for s in result.split("\n") if "Last cached" not in s]
112+
expected = expected_output.split("\n")
113+
# this will also verify the saved counters are correct since the
114+
# expected counters are all '0s'
115+
assert result_stat == expected
116+
shutil.rmtree(cnstat_dir, ignore_errors=True, onerror=None)
117+
118+
119+
class TestPfcstat(object):
120+
@classmethod
121+
def setup_class(cls):
122+
print("SETUP")
123+
os.environ["PATH"] += os.pathsep + scripts_path
124+
os.environ["UTILITIES_UNIT_TESTING"] = "2"
125+
126+
def test_pfc_counters(self):
127+
runner = CliRunner()
128+
result = runner.invoke(
129+
show.cli.commands["pfc"].commands["counters"],
130+
[]
131+
)
132+
print(result.output)
133+
assert result.exit_code == 0
134+
assert result.output == show_pfc_counters_output
135+
136+
def test_pfc_clear(self):
137+
pfc_clear(show_pfc_counters_output_diff)
138+
139+
@classmethod
140+
def teardown_class(cls):
141+
print("TEARDOWN")
142+
os.environ["PATH"] = os.pathsep.join(
143+
os.environ["PATH"].split(os.pathsep)[:-1]
144+
)
145+
os.environ["UTILITIES_UNIT_TESTING"] = "0"
146+
147+
148+
class TestMultiAsicPfcstat(object):
149+
@classmethod
150+
def setup_class(cls):
151+
print("SETUP")
152+
os.environ["PATH"] += os.pathsep + scripts_path
153+
os.environ["UTILITIES_UNIT_TESTING"] = "2"
154+
os.environ["UTILITIES_UNIT_TESTING_TOPOLOGY"] = "multi_asic"
155+
imp.reload(show)
156+
157+
def test_pfc_counters_all(self):
158+
runner = CliRunner()
159+
result = runner.invoke(
160+
show.cli.commands["pfc"].commands["counters"],
161+
)
162+
print(result.output)
163+
assert result.exit_code == 0
164+
assert result.output == show_pfc_counters_all
165+
166+
def test_pfc_counters_frontend(self):
167+
return_code, result = get_result_and_return_code(
168+
'pfcstat -s frontend'
169+
)
170+
assert return_code == 0
171+
assert result == show_pfc_counters_asic0_frontend
172+
173+
def test_pfc_counters_asic(self):
174+
return_code, result = get_result_and_return_code(
175+
'pfcstat -n asic0'
176+
)
177+
assert return_code == 0
178+
assert result == show_pfc_counters_asic0_frontend
179+
180+
def test_pfc_counters_asic_all(self):
181+
return_code, result = get_result_and_return_code(
182+
'pfcstat -n asic0 -s all'
183+
)
184+
assert return_code == 0
185+
assert result == show_pfc_counters_all
186+
187+
def test_pfc_clear(self):
188+
pfc_clear(show_pfc_counters_msaic_output_diff)
189+
190+
@classmethod
191+
def teardown_class(cls):
192+
print("TEARDOWN")
193+
os.environ["PATH"] = os.pathsep.join(
194+
os.environ["PATH"].split(os.pathsep)[:-1]
195+
)
196+
os.environ["UTILITIES_UNIT_TESTING"] = "0"
197+
os.environ["UTILITIES_UNIT_TESTING_TOPOLOGY"] = ""

‎tests/utils.py

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
2+
""" Common test utilities """
3+
4+
import subprocess
5+
6+
7+
def get_result_and_return_code(cmd):
8+
return_code = 0
9+
try:
10+
output = subprocess.check_output(
11+
cmd, stderr=subprocess.STDOUT, shell=True)
12+
except subprocess.CalledProcessError as e:
13+
return_code = e.returncode
14+
# store only the error, no need for the traceback
15+
output = e.output.strip().split("\n")[-1]
16+
17+
print(output)
18+
return(return_code, output)

0 commit comments

Comments
 (0)
Please sign in to comment.