|
| 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