Skip to content

Commit 1acab6d

Browse files
arlakshmabdosi
authored andcommitted
Common functions for show CLI support on multi ASIC (#999)
Common changes will be used to support SONiC CLIs for multi ASIC - New MultiAsic class to support not displaying of internal object - Common CLI options which needed for multi ASIC platforms - a new decorator to execute a function on all namespaces Signed-off-by: Arvindsrinivasan Lakshmi Narasimhan <[email protected]>
1 parent a01717e commit 1acab6d

File tree

2 files changed

+147
-0
lines changed

2 files changed

+147
-0
lines changed

utilities_common/constants.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
#All the constant used in sonic-utilities
2+
3+
DEFAULT_NAMESPACE = ''
4+
DISPLAY_ALL = 'all'
5+
DISPLAY_EXTERNAL = 'frontend'
6+
BGP_NEIGH_OBJ = 'BGP_NEIGH'
7+
PORT_CHANNEL_OBJ = 'PORT_CHANNEL'
8+
PORT_OBJ = 'PORT'
9+

utilities_common/multi_asic.py

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
import argparse
2+
import functools
3+
4+
import click
5+
from sonic_py_common import multi_asic
6+
from utilities_common import constants
7+
8+
9+
class MultiAsic(object):
10+
11+
def __init__(self, display_option=constants.DISPLAY_ALL,
12+
namespace_option=None):
13+
self.namespace_option = namespace_option
14+
self.display_option = display_option
15+
self.current_namespace = None
16+
self.is_multi_asic = multi_asic.is_multi_asic()
17+
18+
def is_object_internal(self, object_type, cli_object):
19+
'''
20+
The function checks if a CLI object is internal and returns true or false.
21+
Internal objects are port or portchannel which are connected to other
22+
ports or portchannels within a multi ASIC device.
23+
24+
For single asic, this function is not applicable
25+
'''
26+
if object_type == constants.PORT_OBJ:
27+
return multi_asic.is_port_internal(cli_object)
28+
elif object_type == constants.PORT_CHANNEL_OBJ:
29+
return multi_asic.is_port_channel_internal(cli_object)
30+
elif object_type == constants.BGP_NEIGH_OBJ:
31+
return multi_asic.is_bgp_session_internal(cli_object)
32+
33+
def skip_display(self, object_type, cli_object):
34+
'''
35+
The function determines if the passed cli_object has to be displayed or not.
36+
returns true if the display_option is external and the cli object is internal.
37+
returns false, if the cli option is all or if it the platform is single ASIC.
38+
39+
'''
40+
if not self.is_multi_asic:
41+
return False
42+
if self.display_option == constants.DISPLAY_ALL:
43+
return False
44+
return self.is_object_internal(object_type, cli_object)
45+
46+
def get_ns_list_based_on_options(self):
47+
ns_list = []
48+
if not self.is_multi_asic:
49+
return [constants.DEFAULT_NAMESPACE]
50+
else:
51+
namespaces = multi_asic.get_all_namespaces()
52+
if self.namespace_option is None:
53+
if self.display_option == constants.DISPLAY_ALL:
54+
ns_list = namespaces['front_ns'] + namespaces['back_ns']
55+
else:
56+
ns_list = namespaces['front_ns']
57+
else:
58+
if self.namespace_option not in namespaces['front_ns'] and \
59+
self.namespace_option not in namespaces['back_ns']:
60+
raise ValueError(
61+
'Unknown Namespace {}'.format(self.namespace_option))
62+
ns_list = [self.namespace_option]
63+
return ns_list
64+
65+
66+
def multi_asic_ns_choices():
67+
if not multi_asic.is_multi_asic():
68+
return [constants.DEFAULT_NAMESPACE]
69+
choices = multi_asic.get_namespace_list()
70+
return choices
71+
72+
73+
def multi_asic_display_choices():
74+
if not multi_asic.is_multi_asic():
75+
return [constants.DISPLAY_ALL]
76+
else:
77+
return [constants.DISPLAY_ALL, constants.DISPLAY_EXTERNAL]
78+
79+
80+
def multi_asic_display_default_option():
81+
if not multi_asic.is_multi_asic():
82+
return constants.DISPLAY_ALL
83+
else:
84+
return constants.DISPLAY_EXTERNAL
85+
86+
87+
_multi_asic_click_options = [
88+
click.option('--display',
89+
'-d', 'display',
90+
default=multi_asic_display_default_option(),
91+
show_default=True,
92+
type=click.Choice(multi_asic_display_choices()),
93+
help='Show internal interfaces'),
94+
click.option('--namespace',
95+
'-n', 'namespace',
96+
default=None,
97+
type=click.Choice(multi_asic_ns_choices()),
98+
show_default=True,
99+
help='Namespace name or all'),
100+
]
101+
102+
103+
def multi_asic_click_options(func):
104+
for option in reversed(_multi_asic_click_options):
105+
func = option(func)
106+
return func
107+
108+
109+
def run_on_multi_asic(func):
110+
'''
111+
This decorator is used on the CLI functions which needs to be
112+
run on all the namespaces in the multi ASIC platform
113+
The decorator loops through all the required namespaces,
114+
for every iteration, it connects to all the DBs and provides an handle
115+
to the wrapped function.
116+
117+
'''
118+
@functools.wraps(func)
119+
def wrapped_run_on_all_asics(self, *args, **kwargs):
120+
ns_list = self.multi_asic.get_ns_list_based_on_options()
121+
for ns in ns_list:
122+
self.multi_asic.current_namespace = ns
123+
self.db = multi_asic.connect_to_all_dbs_for_ns(ns)
124+
self.config_db = multi_asic.connect_config_db_for_ns(ns)
125+
func(self, *args, **kwargs)
126+
return wrapped_run_on_all_asics
127+
128+
129+
def multi_asic_args(parser=None):
130+
if parser is None:
131+
parser = argparse.ArgumentParser(
132+
formatter_class=argparse.RawTextHelpFormatter)
133+
134+
parser.add_argument('-d', '--display', default=constants.DISPLAY_EXTERNAL,
135+
help='Display all interfaces or only external interfaces')
136+
parser.add_argument('-n', '--namespace', default=None,
137+
help='Display interfaces for specific namespace')
138+
return parser

0 commit comments

Comments
 (0)