Skip to content

Commit a3d15bc

Browse files
Add multi-asic support for dropconfig (sonic-net#3735)
Added support for iterating over all namespaces (ns) when none specified Added a test cases to verify multi-asic behaviour Introduced a wrapper class to handle the mutli-asic functionality This script was missed during the initial efforts to add multi-asic support.
1 parent 5ce06b2 commit a3d15bc

File tree

7 files changed

+329
-62
lines changed

7 files changed

+329
-62
lines changed

config/main.py

+44-4
Original file line numberDiff line numberDiff line change
@@ -7401,7 +7401,15 @@ def dropcounters():
74017401
@click.option("-g", "--group", type=str, help="Group for this counter")
74027402
@click.option("-d", "--desc", type=str, help="Description for this counter")
74037403
@click.option('-v', '--verbose', is_flag=True, help="Enable verbose output")
7404-
def install(counter_name, alias, group, counter_type, desc, reasons, verbose):
7404+
@click.option('--namespace',
7405+
'-n',
7406+
'namespace',
7407+
default=None,
7408+
type=str,
7409+
show_default=True,
7410+
help='Namespace name or all',
7411+
callback=multi_asic_util.multi_asic_namespace_validation_callback)
7412+
def install(counter_name, alias, group, counter_type, desc, reasons, verbose, namespace):
74057413
"""Install a new drop counter"""
74067414
command = ['dropconfig', '-c', 'install', '-n', str(counter_name), '-t', str(counter_type), '-r', str(reasons)]
74077415
if alias:
@@ -7410,6 +7418,8 @@ def install(counter_name, alias, group, counter_type, desc, reasons, verbose):
74107418
command += ['-g', str(group)]
74117419
if desc:
74127420
command += ['-d', str(desc)]
7421+
if namespace:
7422+
command += ['-ns', str(namespace)]
74137423

74147424
clicommon.run_command(command, display_cmd=verbose)
74157425

@@ -7420,9 +7430,19 @@ def install(counter_name, alias, group, counter_type, desc, reasons, verbose):
74207430
@dropcounters.command()
74217431
@click.argument("counter_name", type=str, required=True)
74227432
@click.option('-v', '--verbose', is_flag=True, help="Enable verbose output")
7423-
def delete(counter_name, verbose):
7433+
@click.option('--namespace',
7434+
'-n',
7435+
'namespace',
7436+
default=None,
7437+
type=str,
7438+
show_default=True,
7439+
help='Namespace name or all',
7440+
callback=multi_asic_util.multi_asic_namespace_validation_callback)
7441+
def delete(counter_name, verbose, namespace):
74247442
"""Delete an existing drop counter"""
74257443
command = ['dropconfig', '-c', 'uninstall', '-n', str(counter_name)]
7444+
if namespace:
7445+
command += ['-ns', str(namespace)]
74267446
clicommon.run_command(command, display_cmd=verbose)
74277447

74287448

@@ -7433,9 +7453,19 @@ def delete(counter_name, verbose):
74337453
@click.argument("counter_name", type=str, required=True)
74347454
@click.argument("reasons", type=str, required=True)
74357455
@click.option('-v', '--verbose', is_flag=True, help="Enable verbose output")
7436-
def add_reasons(counter_name, reasons, verbose):
7456+
@click.option('--namespace',
7457+
'-n',
7458+
'namespace',
7459+
default=None,
7460+
type=str,
7461+
show_default=True,
7462+
help='Namespace name or all',
7463+
callback=multi_asic_util.multi_asic_namespace_validation_callback)
7464+
def add_reasons(counter_name, reasons, verbose, namespace):
74377465
"""Add reasons to an existing drop counter"""
74387466
command = ['dropconfig', '-c', 'add', '-n', str(counter_name), '-r', str(reasons)]
7467+
if namespace:
7468+
command += ['-ns', str(namespace)]
74397469
clicommon.run_command(command, display_cmd=verbose)
74407470

74417471

@@ -7446,9 +7476,19 @@ def add_reasons(counter_name, reasons, verbose):
74467476
@click.argument("counter_name", type=str, required=True)
74477477
@click.argument("reasons", type=str, required=True)
74487478
@click.option('-v', '--verbose', is_flag=True, help="Enable verbose output")
7449-
def remove_reasons(counter_name, reasons, verbose):
7479+
@click.option('--namespace',
7480+
'-n',
7481+
'namespace',
7482+
default=None,
7483+
type=str,
7484+
show_default=True,
7485+
help='Namespace name or all',
7486+
callback=multi_asic_util.multi_asic_namespace_validation_callback)
7487+
def remove_reasons(counter_name, reasons, verbose, namespace):
74507488
"""Remove reasons from an existing drop counter"""
74517489
command = ['dropconfig', '-c', 'remove', '-n', str(counter_name), '-r', str(reasons)]
7490+
if namespace:
7491+
command += ['-ns', str(namespace)]
74527492
clicommon.run_command(command, display_cmd=verbose)
74537493

74547494

scripts/dropconfig

+96-49
Original file line numberDiff line numberDiff line change
@@ -13,17 +13,24 @@
1313
import argparse
1414
import os
1515
import sys
16+
from utilities_common import constants
17+
from sonic_py_common import multi_asic
18+
from utilities_common import multi_asic as multi_asic_util
1619

1720
from tabulate import tabulate
1821

1922
# mock the redis for unit test purposes #
2023
try:
21-
if os.environ["UTILITIES_UNIT_TESTING"] == "1":
24+
if os.getenv("UTILITIES_UNIT_TESTING") == "1":
2225
modules_path = os.path.join(os.path.dirname(__file__), "..")
2326
test_path = os.path.join(modules_path, "tests")
2427
sys.path.insert(0, modules_path)
2528
sys.path.insert(0, test_path)
2629
import mock_tables.dbconnector
30+
if os.getenv("UTILITIES_UNIT_TESTING_TOPOLOGY") == "multi_asic":
31+
import tests.mock_tables.mock_multi_asic
32+
mock_tables.dbconnector.load_namespace_config()
33+
2734
except KeyError:
2835
pass
2936

@@ -51,14 +58,11 @@ class InvalidArgumentError(RuntimeError):
5158
def __init__(self, msg):
5259
self.message = msg
5360

54-
5561
class DropConfig(object):
56-
def __init__(self):
57-
self.config_db = ConfigDBConnector()
58-
self.config_db.connect()
59-
60-
self.state_db = SonicV2Connector(use_unix_socket_path=False)
61-
self.state_db.connect(self.state_db.STATE_DB)
62+
def __init__(self, namespace, db, config_db):
63+
self.db = db
64+
self.config_db = config_db
65+
self.namespace = namespace
6266

6367
# -c show_config
6468
def print_counter_config(self, group):
@@ -76,6 +80,9 @@ class DropConfig(object):
7680
counter.get('reason', ''),
7781
counter.get('description', '')))
7882

83+
if multi_asic.is_multi_asic():
84+
print("For namespace:", self.namespace)
85+
7986
print(tabulate(table,
8087
drop_counter_config_header,
8188
tablefmt='simple',
@@ -95,6 +102,10 @@ class DropConfig(object):
95102
table = []
96103
for counter, capabilities in device_caps.items():
97104
table.append((counter, capabilities.get('count', 'N/A')))
105+
106+
if multi_asic.is_multi_asic():
107+
print("For namespace:", self.namespace)
108+
98109
print(tabulate(table,
99110
drop_counter_capability_header,
100111
tablefmt='simple',
@@ -266,15 +277,15 @@ class DropConfig(object):
266277
Get the device capabilities from STATE_DB
267278
"""
268279

269-
capability_query = self.state_db.keys(self.state_db.STATE_DB, '{}|*'.format(DEBUG_COUNTER_CAPABILITY_TABLE))
280+
capability_query = self.db.keys(self.db.STATE_DB, '{}|*'.format(DEBUG_COUNTER_CAPABILITY_TABLE))
270281

271282
if not capability_query:
272283
return None
273284

274285
counter_caps = {}
275286
for counter_type in capability_query:
276287
# Because keys returns the whole key, we trim off the DEBUG_COUNTER_CAPABILITY prefix here
277-
counter_caps[counter_type[len(DEBUG_COUNTER_CAPABILITY_TABLE) + 1:]] = self.state_db.get_all(self.state_db.STATE_DB, counter_type)
288+
counter_caps[counter_type[len(DEBUG_COUNTER_CAPABILITY_TABLE) + 1:]] = self.db.get_all(self.db.STATE_DB, counter_type)
278289
return counter_caps
279290

280291
def counter_name_in_use(self, counter_name):
@@ -287,7 +298,7 @@ class DropConfig(object):
287298
if counter_type is None:
288299
return None
289300

290-
cap_query = self.state_db.get_all(self.state_db.STATE_DB, '{}|{}'.format(DEBUG_COUNTER_CAPABILITY_TABLE, counter_type))
301+
cap_query = self.db.get_all(self.db.STATE_DB, '{}|{}'.format(DEBUG_COUNTER_CAPABILITY_TABLE, counter_type))
291302

292303
if not cap_query:
293304
return None
@@ -298,7 +309,7 @@ class DropConfig(object):
298309
if counter_type is None:
299310
return None
300311

301-
cap_query = self.state_db.get_all(self.state_db.STATE_DB, '{}|{}'.format(DEBUG_COUNTER_CAPABILITY_TABLE, counter_type))
312+
cap_query = self.db.get_all(self.db.STATE_DB, '{}|{}'.format(DEBUG_COUNTER_CAPABILITY_TABLE, counter_type))
302313

303314
if not cap_query:
304315
return None
@@ -310,6 +321,67 @@ class DropConfig(object):
310321
# get_keys will normalize the table name to uppercase.
311322
return [key for key in self.config_db.get_keys(DROP_REASON_CONFIG_TABLE) if key[0] == counter_name]
312323

324+
class DropConfigWrapper(object):
325+
"""A wrapper to execute dropconfig cmd over the correct namespaces"""
326+
def __init__(self, namespace):
327+
self.namespace = namespace
328+
if namespace is not None and namespace not in multi_asic.get_namespace_list():
329+
print('Encountered error, namespace not recognized: {}. Valid namespaces {}'.format(namespace,
330+
multi_asic.get_namespace_list()))
331+
sys.exit(1)
332+
333+
# Initialize the multi-asic namespace
334+
self.multi_asic = multi_asic_util.MultiAsic(constants.DISPLAY_ALL, namespace_option=namespace)
335+
self.db = None
336+
self.config_db = None
337+
338+
@multi_asic_util.run_on_multi_asic
339+
def run(self,
340+
command,
341+
name,
342+
alias,
343+
group,
344+
counter_type,
345+
description,
346+
reasons):
347+
348+
dconfig = DropConfig(self.multi_asic.current_namespace, self.db, self.config_db)
349+
350+
if command == 'install':
351+
try:
352+
dconfig.create_counter(name,
353+
alias,
354+
group,
355+
counter_type,
356+
description,
357+
reasons)
358+
except InvalidArgumentError as err:
359+
print('Encountered error trying to install counter: {}'.format(err.message))
360+
sys.exit(1)
361+
elif command == 'uninstall':
362+
try:
363+
dconfig.delete_counter(name)
364+
except InvalidArgumentError as err:
365+
print('Encountered error trying to uninstall counter: {}'.format(err.message))
366+
sys.exit(1)
367+
elif command == 'add':
368+
try:
369+
dconfig.add_reasons(name, reasons)
370+
except InvalidArgumentError as err:
371+
print('Encountered error trying to add reasons: {}'.format(err.message))
372+
sys.exit(1)
373+
elif command == 'remove':
374+
try:
375+
dconfig.remove_reasons(name, reasons)
376+
except InvalidArgumentError as err:
377+
print('Encountered error trying to remove reasons: {}'.format(err.message))
378+
sys.exit(1)
379+
elif command == 'show_config':
380+
dconfig.print_counter_config(group)
381+
elif command == 'show_capabilities':
382+
dconfig.print_device_capabilities()
383+
else:
384+
print("Command not recognized")
313385

314386
def deserialize_reason_list(list_str):
315387
if list_str is None:
@@ -334,6 +406,7 @@ def main():
334406
epilog="""
335407
Examples:
336408
dropconfig
409+
dropconfig -ns asic0
337410
""")
338411

339412
# Version
@@ -349,6 +422,7 @@ Examples:
349422
parser.add_argument('-t', '--type', type=str, help='The type of the target drop counter', default=None)
350423
parser.add_argument('-d', '--desc', type=str, help='The description for the target drop counter', default=None)
351424
parser.add_argument('-r', '--reasons', type=str, help='The list of drop reasons for the target drop counter', default=None)
425+
parser.add_argument('-ns', '--namespace', type=str, help='Perform operation on a specific namespace or skip for all', default=None)
352426

353427
args = parser.parse_args()
354428

@@ -360,46 +434,19 @@ Examples:
360434
counter_type = args.type
361435
description = args.desc
362436
drop_reasons = args.reasons
437+
namespace = args.namespace
363438

364439
reasons = deserialize_reason_list(drop_reasons)
365440

366-
dconfig = DropConfig()
367-
368-
if command == 'install':
369-
try:
370-
dconfig.create_counter(name,
371-
alias,
372-
group,
373-
counter_type,
374-
description,
375-
reasons)
376-
except InvalidArgumentError as err:
377-
print('Encountered error trying to install counter: {}'.format(err.message))
378-
sys.exit(1)
379-
elif command == 'uninstall':
380-
try:
381-
dconfig.delete_counter(name)
382-
except InvalidArgumentError as err:
383-
print('Encountered error trying to uninstall counter: {}'.format(err.message))
384-
sys.exit(1)
385-
elif command == 'add':
386-
try:
387-
dconfig.add_reasons(name, reasons)
388-
except InvalidArgumentError as err:
389-
print('Encountered error trying to add reasons: {}'.format(err.message))
390-
sys.exit(1)
391-
elif command == 'remove':
392-
try:
393-
dconfig.remove_reasons(name, reasons)
394-
except InvalidArgumentError as err:
395-
print('Encountered error trying to remove reasons: {}'.format(err.message))
396-
sys.exit(1)
397-
elif command == 'show_config':
398-
dconfig.print_counter_config(group)
399-
elif command == 'show_capabilities':
400-
dconfig.print_device_capabilities()
401-
else:
402-
print("Command not recognized")
441+
dropconfig_wrapper = DropConfigWrapper(namespace)
442+
dropconfig_wrapper.run(command,
443+
name,
444+
alias,
445+
group,
446+
counter_type,
447+
description,
448+
reasons)
449+
403450

404451
if __name__ == '__main__':
405452
main()

show/dropcounters.py

+24-2
Original file line numberDiff line numberDiff line change
@@ -17,23 +17,45 @@ def dropcounters():
1717
@dropcounters.command()
1818
@click.option('-g', '--group', required=False)
1919
@click.option('--verbose', is_flag=True, help="Enable verbose output")
20-
def configuration(group, verbose):
20+
@click.option('--namespace',
21+
'-n',
22+
'namespace',
23+
default=None,
24+
type=str,
25+
show_default=True,
26+
help='Namespace name or all',
27+
callback=multi_asic_util.multi_asic_namespace_validation_callback)
28+
def configuration(group, verbose, namespace):
2129
"""Show current drop counter configuration"""
2230
cmd = ['dropconfig', '-c', 'show_config']
2331

2432
if group:
2533
cmd += ['-g', str(group)]
2634

35+
if namespace:
36+
cmd += ['-ns', str(namespace)]
37+
2738
clicommon.run_command(cmd, display_cmd=verbose)
2839

2940

3041
# 'capabilities' subcommand ("show dropcounters capabilities")
3142
@dropcounters.command()
3243
@click.option('--verbose', is_flag=True, help="Enable verbose output")
33-
def capabilities(verbose):
44+
@click.option('--namespace',
45+
'-n',
46+
'namespace',
47+
default=None,
48+
type=str,
49+
show_default=True,
50+
help='Namespace name or all',
51+
callback=multi_asic_util.multi_asic_namespace_validation_callback)
52+
def capabilities(verbose, namespace):
3453
"""Show device drop counter capabilities"""
3554
cmd = ['dropconfig', '-c', 'show_capabilities']
3655

56+
if namespace:
57+
cmd += ['-ns', str(namespace)]
58+
3759
clicommon.run_command(cmd, display_cmd=verbose)
3860

3961

0 commit comments

Comments
 (0)