From 7ebb2f7d83ec0e2412c692ee7d6583b47f7f23e2 Mon Sep 17 00:00:00 2001 From: vganesan-nokia <67648637+vganesan-nokia@users.noreply.github.com> Date: Wed, 25 Aug 2021 09:28:43 -0400 Subject: [PATCH] [voq][chassis] VOQ cli show commands implementation (#1689) Changes in this commit - Implementation of the following show commands for VOQ chassis. show chassis system-ports [] {-n }, if multi-asic voq chassis show chassis system-ports [] , if single asic voq chassis show chassis system-neighbors [] [-n ] show chassis system-lags [] [-n ] [-l ] - The existing chassis commands under "show chassis_modules" and "config chassis_modules" have been renamed (moved) under "show chassis modules" and "config chassis modules" respectively Signed-off-by: vedganes --- config/chassis_modules.py | 13 +- config/main.py | 2 +- scripts/voqutil | 373 +++++++++++++++++++++++++ setup.py | 1 + show/chassis_modules.py | 68 ++++- show/main.py | 2 +- tests/chassis_modules_test.py | 179 ++++++++++-- tests/mock_tables/asic0/appl_db.json | 37 ++- tests/mock_tables/asic1/appl_db.json | 35 +++ tests/mock_tables/asic2/appl_db.json | 35 +++ tests/mock_tables/chassis_app_db.json | 54 ++++ tests/mock_tables/database_config.json | 5 + 12 files changed, 778 insertions(+), 26 deletions(-) create mode 100755 scripts/voqutil create mode 100644 tests/mock_tables/chassis_app_db.json diff --git a/config/chassis_modules.py b/config/chassis_modules.py index 6e783ed85676..e640779d160b 100644 --- a/config/chassis_modules.py +++ b/config/chassis_modules.py @@ -8,14 +8,19 @@ # 'chassis_modules' group ('config chassis_modules ...') # @click.group(cls=clicommon.AliasedGroup) -def chassis_modules(): - """Configure chassis-modules options""" +def chassis(): + """Configure chassis commands group""" + pass + +@chassis.group() +def modules(): + """Configure chassis modules""" pass # # 'shutdown' subcommand ('config chassis_modules shutdown ...') # -@chassis_modules.command('shutdown') +@modules.command('shutdown') @clicommon.pass_db @click.argument('chassis_module_name', metavar='', required=True) def shutdown_chassis_module(db, chassis_module_name): @@ -34,7 +39,7 @@ def shutdown_chassis_module(db, chassis_module_name): # # 'startup' subcommand ('config chassis_modules startup ...') # -@chassis_modules.command('startup') +@modules.command('startup') @clicommon.pass_db @click.argument('chassis_module_name', metavar='', required=True) def startup_chassis_module(db, chassis_module_name): diff --git a/config/main.py b/config/main.py index 786ae67d403d..540710e99662 100644 --- a/config/main.py +++ b/config/main.py @@ -981,7 +981,7 @@ def config(ctx): config.add_command(aaa.aaa) config.add_command(aaa.tacacs) config.add_command(aaa.radius) -config.add_command(chassis_modules.chassis_modules) +config.add_command(chassis_modules.chassis) config.add_command(console.console) config.add_command(feature.feature) config.add_command(kdump.kdump) diff --git a/scripts/voqutil b/scripts/voqutil new file mode 100755 index 000000000000..0a34b566adf9 --- /dev/null +++ b/scripts/voqutil @@ -0,0 +1,373 @@ +#!/usr/bin/env python3 + +import argparse +import os +import re +import sys +import ipaddress + +from natsort import natsorted +from tabulate import tabulate +from utilities_common import multi_asic as multi_asic_util +from swsscommon import swsscommon + +# mock the redis for unit test purposes # +try: + if os.environ["UTILITIES_UNIT_TESTING"] == "1": + modules_path = os.path.join(os.path.dirname(__file__), "..") + tests_path = os.path.join(modules_path, "tests") + sys.path.insert(0, modules_path) + sys.path.insert(0, tests_path) + import mock_tables.dbconnector + if os.environ["UTILITIES_UNIT_TESTING_TOPOLOGY"] == "multi_asic": + import mock_tables.mock_multi_asic + mock_tables.dbconnector.load_namespace_config() + else: + mock_tables.dbconnector.load_database_config() + +except KeyError: + pass + + +# ========================== Common VOQ util logic ========================== + +SYSTEM_PORT_TABLE_PREFIX = swsscommon.APP_SYSTEM_PORT_TABLE_NAME + ":" +SYSTEM_PORT_ID = "system_port_id" +SYSTEM_PORT_CORE = "core_index" +SYSTEM_PORT_CORE_PORT = "core_port_index" +SYSTEM_PORT_SPEED = "speed" +SYSTEM_PORT_SWITCH_ID = "switch_id" + +SYSTEM_NEIGH_TABLE_PREFIX = swsscommon.CHASSIS_APP_SYSTEM_NEIGH_TABLE_NAME + "|" +SYSTEM_NEIGH_MAC = "neigh" +SYSTEM_NEIGH_ENCAP_INDEX = "encap_index" + +SYSTEM_LAG_TABLE_PREFIX = swsscommon.CHASSIS_APP_LAG_TABLE_NAME + "|" +SYSTEM_LAG_MEMBER_TABLE_PREFIX = swsscommon.CHASSIS_APP_LAG_MEMBER_TABLE_NAME + "|" +SYSTEM_LAG_ID = "lag_id" +SYSTEM_LAG_SWITCH_ID = "switch_id" + +def parse_systemintf_in_filter(intf_filter): + intf_fs = [] + + if intf_filter is None: + return intf_fs + + fs = intf_filter.split(',') + for x in fs: + intf_fs.append(x.strip()) + + return intf_fs + +def is_ipv4_address(ip_address): + """ + Checks if given ip is ipv4 + :param ip_address: str ipv4 + :return: bool + """ + try: + ipaddress.IPv4Address(ip_address) + return True + except ipaddress.AddressValueError as err: + return False + + +def is_ipv6_address(ip_address): + """ + Checks if given ip is ipv6 + :param ip_address: str ipv6 + :return: bool + """ + try: + ipaddress.IPv6Address(ip_address) + return True + except ipaddress.AddressValueError as err: + return False + +def appl_db_keys_get_system_port(appl_db, system_port_name): + """ + Get APPL_DB SYSTEM_PORT_TABLE Keys + """ + if system_port_name is None or system_port_name == "": + appl_db_keys = appl_db.keys(appl_db.APPL_DB, SYSTEM_PORT_TABLE_PREFIX+"*") + else: + appl_db_keys = appl_db.keys(appl_db.APPL_DB, SYSTEM_PORT_TABLE_PREFIX+"%s" % system_port_name) + + return appl_db_keys + +def appl_db_system_port_status_get(appl_db, system_port_name, status_type): + """ + Get the system port status + """ + full_table_id = SYSTEM_PORT_TABLE_PREFIX + system_port_name + status = appl_db.get(appl_db.APPL_DB, full_table_id, status_type) + if status is None: + return "N/A" + if status_type == SYSTEM_PORT_SPEED and status != "N/A": + status = '{}G'.format(status[:-3]) + return status + +def chassis_app_db_keys_get_system_neigh(chassis_app_db): + """ + Get CHASSIS_APP_DB SYSTEM_NEIGH table Keys + """ + system_neigh_keys = chassis_app_db.keys(chassis_app_db.CHASSIS_APP_DB, SYSTEM_NEIGH_TABLE_PREFIX+"*") + + return system_neigh_keys + +def chassis_app_db_system_neigh_status_get(chassis_app_db, system_neigh_name, status_type): + """ + Get the system neigh status + """ + full_table_id = SYSTEM_NEIGH_TABLE_PREFIX + system_neigh_name + status = chassis_app_db.get(chassis_app_db.CHASSIS_APP_DB, full_table_id, status_type) + if status is None: + return "N/A" + return status + +def chassis_app_db_keys_get_system_lag(chassis_app_db, system_lag_name): + """ + Get CHASSIS_APP_DB SYSTEM_LAG_TABLE Keys + """ + if system_lag_name is None or system_lag_name == "": + chassis_app_db_keys = chassis_app_db.keys(chassis_app_db.CHASSIS_APP_DB, SYSTEM_LAG_TABLE_PREFIX+"*") + else: + chassis_app_db_keys = chassis_app_db.keys(chassis_app_db.CHASSIS_APP_DB, SYSTEM_LAG_TABLE_PREFIX+"%s" % system_lag_name) + + return chassis_app_db_keys + +def chassis_app_db_system_lag_status_get(chassis_app_db, system_lag_name, status_type): + """ + Get the system lag status + """ + full_table_id = SYSTEM_LAG_TABLE_PREFIX + system_lag_name + status = chassis_app_db.get(chassis_app_db.CHASSIS_APP_DB, full_table_id, status_type) + if status is None: + return "N/A" + return status + +def chassis_app_db_keys_get_system_lag_member(chassis_app_db, system_lag_name, system_lag_member_name): + """ + Get CHASSIS_APP_DB SYSTEM_LAG_MEMBER_TABLE Keys for a given system lag + """ + if system_lag_name is None or system_lag_name == "": + chassis_app_db_keys = chassis_app_db.keys(chassis_app_db.CHASSIS_APP_DB, SYSTEM_LAG_MEMBER_TABLE_PREFIX+"*") + elif system_lag_member_name is None or system_lag_member_name == "": + chassis_app_db_keys = chassis_app_db.keys(chassis_app_db.CHASSIS_APP_DB, SYSTEM_LAG_MEMBER_TABLE_PREFIX+"%s*" % system_lag_name) + else: + chassis_app_db_keys = chassis_app_db.keys(chassis_app_db.CHASSIS_APP_DB, SYSTEM_LAG_MEMBER_TABLE_PREFIX+"%s:%s" % system_lag_name, system_lag_member_name) + + return chassis_app_db_keys + +# ========================== VOQ system port status logic ========================== + +header_system_port = ['System Port Name', 'Port Id', 'Switch Id', 'Core', 'Core Port', 'Speed'] + +class SystemPortStatus(object): + + def __init__(self, system_port_name, namespace_option): + """ + Class constructor method + :param self: + :param intf_name: string of system port name + :return: + """ + self.db = None + self.config_db = None + self.system_port_name = system_port_name + self.table = [] + self.multi_asic = multi_asic_util.MultiAsic(namespace_option=namespace_option) + + def display_systemport_status(self): + self.get_systemport_status() + sorted_table = natsorted(self.table) + print(tabulate(sorted_table, + header_system_port, + tablefmt="simple", + stralign='right')) + + def generate_systemport_status(self): + """ + Generate system port status output + """ + + i = {} + table = [] + key = [] + + intf_fs = parse_systemintf_in_filter(self.system_port_name) + # + # Iterate through all the keys and append system port's associated info to + # the result table. + # + for i in self.appl_db_keys_system_port: + key = re.split(':', i, maxsplit=1)[-1].strip() + if self.system_port_name is None or key in intf_fs: + table.append((key, + appl_db_system_port_status_get(self.db, key, SYSTEM_PORT_ID), + appl_db_system_port_status_get(self.db, key, SYSTEM_PORT_SWITCH_ID), + appl_db_system_port_status_get(self.db, key, SYSTEM_PORT_CORE), + appl_db_system_port_status_get(self.db, key, SYSTEM_PORT_CORE_PORT), + appl_db_system_port_status_get(self.db, key, SYSTEM_PORT_SPEED))) + + return table + + @multi_asic_util.run_on_multi_asic + def get_systemport_status(self): + self.appl_db_keys_system_port = appl_db_keys_get_system_port(self.db, None) + if self.appl_db_keys_system_port: + self.table += self.generate_systemport_status() + +# ========================== voq system neigh status logic ========================== + +header_system_neigh = ['System Port Interface', 'Neighbor', 'MAC', 'Encap Index'] + +class SystemNeighStatus(object): + + def __init__(self, ipaddress, asicname): + self.db = None + self.config_db = None + self.ipaddress = ipaddress + self.asicname = asicname + self.table = [] + + def display_systemneigh_status(self): + + self.get_systemneigh_status() + + # Sorting and tabulating the result table. + sorted_table = natsorted(self.table) + print(tabulate(sorted_table, header_system_neigh, tablefmt="simple", stralign='right')) + + def generate_systemneigh_status(self): + """ + Generate system neigh status output + """ + + i = {} + table = [] + key = [] + + if self.ipaddress is not None: + if not is_ipv4_address(self.ipaddress) and not is_ipv6_address(self.ipaddress): + print("{} is not valid ip address\n".format(self.ipaddress)) + return table + + # + # Iterate through all the keys and append system neigh's associated info to + # the result table. + # + for i in self.chassis_app_db_keys_system_neigh: + key_tokens = re.split('\|', i) + nbr = key_tokens[-1].strip() + intf = '|'.join(key_tokens[1:-1]) + key = '|'.join(key_tokens[1:]) + if ((self.ipaddress is None or nbr in self.ipaddress) and + (self.asicname is None or self.asicname in intf)): + table.append((intf, nbr, + chassis_app_db_system_neigh_status_get(self.db, key, SYSTEM_NEIGH_MAC), + chassis_app_db_system_neigh_status_get(self.db, key, SYSTEM_NEIGH_ENCAP_INDEX))) + return table + + def get_systemneigh_status(self): + self.db = swsscommon.SonicV2Connector(use_unix_socket_path=False) + self.db.connect(self.db.CHASSIS_APP_DB, False) + self.chassis_app_db_keys_system_neigh = chassis_app_db_keys_get_system_neigh(self.db) + if self.chassis_app_db_keys_system_neigh: + self.table += self.generate_systemneigh_status() + +# ========================== VOQ system lag status logic ========================== + +header_system_lag = ['System Lag Name', 'Lag Id', 'Switch Id', 'Member System Ports'] + +class SystemLagStatus(object): + + def __init__(self, system_lag_name, asicname, hostname): + """ + Class constructor method + :param self: + :param intf_name: string of system lag name + :return: + """ + self.db = None + self.config_db = None + self.system_lag_name = system_lag_name + self.asicname = asicname + self.hostname = hostname + self.table = [] + + def display_systemlag_status(self): + self.get_systemlag_status() + sorted_table = natsorted(self.table) + print(tabulate(sorted_table, + header_system_lag, + tablefmt="simple", + stralign='right')) + + def generate_systemlag_status(self): + """ + Generate system lag status output + """ + + i = {} + table = [] + key = [] + members = [] + + intf_fs = parse_systemintf_in_filter(self.system_lag_name) + # + # Iterate through all the keys and append system lag's associated info to + # the result table. + # + for i in self.chassis_app_db_keys_system_lag: + key_tokens = re.split('\|', i) + key = '|'.join(key_tokens[1:]) + if ((self.system_lag_name is None or key in intf_fs) and + (self.asicname is None or self.asicname in key) and + (self.hostname is None or self.hostname in key)): + mkeys = chassis_app_db_keys_get_system_lag_member(self.db, key, '') + members.clear() + for mk in mkeys: + members.append(mk.split(':')[-1].strip()) + memstr = ', '.join(members) + table.append((key, + chassis_app_db_system_lag_status_get(self.db, key, SYSTEM_LAG_ID), + chassis_app_db_system_lag_status_get(self.db, key, SYSTEM_LAG_SWITCH_ID), + memstr)) + + return table + + def get_systemlag_status(self): + self.db = swsscommon.SonicV2Connector(use_unix_socket_path=False) + self.db.connect(self.db.CHASSIS_APP_DB, False) + self.chassis_app_db_keys_system_lag = chassis_app_db_keys_get_system_lag(self.db, None) + if self.chassis_app_db_keys_system_lag: + self.table += self.generate_systemlag_status() + +# ========================== VOQ util logic main ========================== + +def main(): + parser = argparse.ArgumentParser(description='Display VOQ information', + formatter_class=argparse.RawTextHelpFormatter) + parser.add_argument('-c', '--command', type=str, help='get system ports or system neighbors or system lags', default=None) + parser.add_argument('-a', '--ipaddress', type=str, help='information for specific neighbor', default=None) + parser.add_argument('-i', '--interface', type=str, help='information for specific system port', default=None) + parser.add_argument('-s', '--systemlag', type=str, help='information for specific system lag', default=None) + parser.add_argument('-n', '--namespace', type=str, help='information from specific namespace or asicname', default=None) + parser.add_argument('-l', '--linecardname', type=str, help='information for specific linecard or host', default=None) + args = parser.parse_args() + + if args.command == "system_ports": + system_port_status = SystemPortStatus(args.interface, args.namespace) + system_port_status.display_systemport_status() + elif args.command == "system_neighbors": + system_neigh_status = SystemNeighStatus(args.ipaddress, args.namespace) + system_neigh_status.display_systemneigh_status() + elif args.command == "system_lags": + system_lag_status = SystemLagStatus(args.systemlag, args.namespace, args.linecardname) + system_lag_status.display_systemlag_status() + + sys.exit(0) + +if __name__ == "__main__": + main() diff --git a/setup.py b/setup.py index e4b5e36fa3d1..96c438dbff49 100644 --- a/setup.py +++ b/setup.py @@ -126,6 +126,7 @@ 'scripts/syseeprom-to-json', 'scripts/tempershow', 'scripts/update_json.py', + 'scripts/voqutil', 'scripts/warm-reboot', 'scripts/watermarkstat', 'scripts/watermarkcfg', diff --git a/show/chassis_modules.py b/show/chassis_modules.py index 8a9d22ae359a..acc0263b6f3b 100644 --- a/show/chassis_modules.py +++ b/show/chassis_modules.py @@ -4,6 +4,7 @@ from swsscommon.swsscommon import SonicV2Connector import utilities_common.cli as clicommon +from sonic_py_common import multi_asic CHASSIS_MODULE_INFO_TABLE = 'CHASSIS_MODULE_TABLE' CHASSIS_MODULE_INFO_KEY_TEMPLATE = 'CHASSIS_MODULE {}' @@ -17,11 +18,16 @@ CHASSIS_MIDPLANE_INFO_ACCESS_FIELD = 'access' @click.group(cls=clicommon.AliasedGroup) -def chassis_modules(): +def chassis(): + """Chassis commands group""" + pass + +@chassis.group() +def modules(): """Show chassis-modules information""" pass -@chassis_modules.command() +@modules.command() @clicommon.pass_db @click.argument('chassis_module_name', metavar='', required=False) def status(db, chassis_module_name): @@ -66,7 +72,7 @@ def status(db, chassis_module_name): else: click.echo('No data available in CHASSIS_MODULE_TABLE\n') -@chassis_modules.command() +@modules.command() @click.argument('chassis_module_name', metavar='', required=False) def midplane_status(chassis_module_name): """Show chassis-modules midplane-status""" @@ -102,3 +108,59 @@ def midplane_status(chassis_module_name): click.echo(tabulate(table, header, tablefmt='simple', stralign='right')) else: click.echo('No data available in CHASSIS_MIDPLANE_TABLE\n') + +@chassis.command() +@click.argument('systemportname', required=False) +@click.option('--namespace', '-n', 'namespace', required=True if multi_asic.is_multi_asic() else False, + default=None, type=str, show_default=False, help='Namespace name or all') +@click.option('--verbose', is_flag=True, help="Enable verbose output") +def system_ports(systemportname, namespace, verbose): + """Show VOQ system ports information""" + + cmd = "voqutil -c system_ports" + + if systemportname is not None: + cmd += " -i \"{}\"".format(systemportname) + + if namespace is not None: + cmd += " -n {}".format(namespace) + + clicommon.run_command(cmd, display_cmd=verbose) + +@chassis.command() +@click.argument('ipaddress', required=False) +@click.option('--asicname', '-n', 'asicname', default=None, type=str, show_default=False, help='Asic name') +@click.option('--verbose', is_flag=True, help="Enable verbose output") +def system_neighbors(asicname, ipaddress, verbose): + """Show VOQ system neighbors information""" + + cmd = "voqutil -c system_neighbors" + + if ipaddress is not None: + cmd += " -a {}".format(ipaddress) + + if asicname is not None: + cmd += " -n {}".format(asicname) + + clicommon.run_command(cmd, display_cmd=verbose) + +@chassis.command() +@click.argument('systemlagname', required=False) +@click.option('--asicname', '-n', 'asicname', default=None, type=str, show_default=False, help='Asic name') +@click.option('--linecardname', '-l', 'linecardname', default=None, type=str, show_default=False, help='Linecard or Host name') +@click.option('--verbose', is_flag=True, help="Enable verbose output") +def system_lags(systemlagname, asicname, linecardname, verbose): + """Show VOQ system lags information""" + + cmd = "voqutil -c system_lags" + + if systemlagname is not None: + cmd += " -s \"{}\"".format(systemlagname) + + if asicname is not None: + cmd += " -n {}".format(asicname) + + if linecardname is not None: + cmd += " -l \"{}\"".format(linecardname) + + clicommon.run_command(cmd, display_cmd=verbose) diff --git a/show/main.py b/show/main.py index 7840e9c83c40..2a6bf73692b4 100755 --- a/show/main.py +++ b/show/main.py @@ -175,7 +175,7 @@ def cli(ctx): # Add groups from other modules cli.add_command(acl.acl) -cli.add_command(chassis_modules.chassis_modules) +cli.add_command(chassis_modules.chassis) cli.add_command(dropcounters.dropcounters) cli.add_command(feature.feature) cli.add_command(fgnhg.fgnhg) diff --git a/tests/chassis_modules_test.py b/tests/chassis_modules_test.py index fb63488ecd00..e6dbe569d2cd 100644 --- a/tests/chassis_modules_test.py +++ b/tests/chassis_modules_test.py @@ -10,6 +10,7 @@ import config.main as config import tests.mock_tables.dbconnector from utilities_common.db import Db +from .utils import get_result_and_return_code show_linecard0_shutdown_output="""\ LINE-CARD0 line-card 1 Empty down @@ -39,6 +40,83 @@ SUPERVISOR0 192.168.1.100 True """ +show_chassis_system_ports_output_asic0="""\ + System Port Name Port Id Switch Id Core Core Port Speed +---------------------------- --------- ----------- ------ ----------- ------- + Linecard1|Asic0|Ethernet0 1 0 0 1 100G +Linecard1|Asic0|Ethernet-IB0 13 0 1 6 10G + Linecard1|Asic1|Ethernet12 65 2 0 1 100G + Linecard1|Asic2|Ethernet24 129 4 0 1 100G + Linecard2|Asic0|Ethernet0 193 6 0 1 100G +""" + +show_chassis_system_ports_output_1_asic0="""\ + System Port Name Port Id Switch Id Core Core Port Speed +------------------------- --------- ----------- ------ ----------- ------- +Linecard1|Asic0|Ethernet0 1 0 0 1 100G +""" + +show_chassis_system_neighbors_output_all="""\ + System Port Interface Neighbor MAC Encap Index +------------------------------- ---------- ----------------- ------------- + Linecard2|Asic0|Ethernet4 10.0.0.5 b6:8c:4f:18:67:ff 1074790406 + Linecard2|Asic0|Ethernet4 fc00::a b6:8c:4f:18:67:ff 1074790407 + Linecard2|Asic0|Ethernet-IB0 3.3.3.4 24:21:24:05:81:f7 1074790404 + Linecard2|Asic0|Ethernet-IB0 3333::3:4 24:21:24:05:81:f7 1074790405 +Linecard2|Asic1|PortChannel0002 10.0.0.1 26:8b:37:fa:8e:67 1074790406 +Linecard2|Asic1|PortChannel0002 fc00::2 26:8b:37:fa:8e:67 1074790407 + Linecard4|Asic0|Ethernet5 10.0.0.11 46:c3:71:8c:dd:2d 1074790406 + Linecard4|Asic0|Ethernet5 fc00::16 46:c3:71:8c:dd:2d 1074790407 +""" + +show_chassis_system_neighbors_output_ipv4="""\ + System Port Interface Neighbor MAC Encap Index +------------------------- ---------- ----------------- ------------- +Linecard2|Asic0|Ethernet4 10.0.0.5 b6:8c:4f:18:67:ff 1074790406 +""" + +show_chassis_system_neighbors_output_ipv6="""\ + System Port Interface Neighbor MAC Encap Index +------------------------- ---------- ----------------- ------------- +Linecard4|Asic0|Ethernet5 fc00::16 46:c3:71:8c:dd:2d 1074790407 +""" + +show_chassis_system_neighbors_output_asic0="""\ + System Port Interface Neighbor MAC Encap Index +---------------------------- ---------- ----------------- ------------- + Linecard2|Asic0|Ethernet4 10.0.0.5 b6:8c:4f:18:67:ff 1074790406 + Linecard2|Asic0|Ethernet4 fc00::a b6:8c:4f:18:67:ff 1074790407 +Linecard2|Asic0|Ethernet-IB0 3.3.3.4 24:21:24:05:81:f7 1074790404 +Linecard2|Asic0|Ethernet-IB0 3333::3:4 24:21:24:05:81:f7 1074790405 + Linecard4|Asic0|Ethernet5 10.0.0.11 46:c3:71:8c:dd:2d 1074790406 + Linecard4|Asic0|Ethernet5 fc00::16 46:c3:71:8c:dd:2d 1074790407 +""" + +show_chassis_system_lags_output="""\ + System Lag Name Lag Id Switch Id Member System Ports +------------------------------- -------- ----------- ------------------------------------------------------ +Linecard2|Asic1|PortChannel0002 1 8 Linecard2|Asic1|Ethernet16, Linecard2|Asic1|Ethernet17 +Linecard4|Asic2|PortChannel0001 2 22 Linecard4|Asic2|Ethernet29, Linecard4|Asic2|Ethernet30 +""" + +show_chassis_system_lags_output_1="""\ + System Lag Name Lag Id Switch Id Member System Ports +------------------------------- -------- ----------- ------------------------------------------------------ +Linecard4|Asic2|PortChannel0001 2 22 Linecard4|Asic2|Ethernet29, Linecard4|Asic2|Ethernet30 +""" + +show_chassis_system_lags_output_asic1="""\ + System Lag Name Lag Id Switch Id Member System Ports +------------------------------- -------- ----------- ------------------------------------------------------ +Linecard2|Asic1|PortChannel0002 1 8 Linecard2|Asic1|Ethernet16, Linecard2|Asic1|Ethernet17 +""" + +show_chassis_system_lags_output_lc4="""\ + System Lag Name Lag Id Switch Id Member System Ports +------------------------------- -------- ----------- ------------------------------------------------------ +Linecard4|Asic2|PortChannel0001 2 22 Linecard4|Asic2|Ethernet29, Linecard4|Asic2|Ethernet30 +""" + class TestChassisModules(object): @classmethod def setup_class(cls): @@ -47,13 +125,13 @@ def setup_class(cls): def test_show_and_verify_output(self): runner = CliRunner() - result = runner.invoke(show.cli.commands["chassis-modules"].commands["status"], []) + result = runner.invoke(show.cli.commands["chassis"].commands["modules"].commands["status"], []) print(result.output) assert(result.output == show_chassis_modules_output) def test_show_all_count_lines(self): runner = CliRunner() - result = runner.invoke(show.cli.commands["chassis-modules"].commands["status"], []) + result = runner.invoke(show.cli.commands["chassis"].commands["modules"].commands["status"], []) print(result.output) result_lines = result.output.strip('\n').split('\n') modules = ["FABRIC-CARD0", "FABRIC-CARD1", "LINE-CARD0", "LINE-CARD1", "SUPERVISOR0"] @@ -63,7 +141,7 @@ def test_show_all_count_lines(self): def test_show_single_count_lines(self): runner = CliRunner() - result = runner.invoke(show.cli.commands["chassis-modules"].commands["status"], ["LINE-CARD0"]) + result = runner.invoke(show.cli.commands["chassis"].commands["modules"].commands["status"], ["LINE-CARD0"]) print(result.output) result_lines = result.output.strip('\n').split('\n') modules = ["LINE-CARD0"] @@ -73,7 +151,7 @@ def test_show_single_count_lines(self): def test_show_module_down(self): runner = CliRunner() - result = runner.invoke(show.cli.commands["chassis-modules"].commands["status"], ["LINE-CARD1"]) + result = runner.invoke(show.cli.commands["chassis"].commands["modules"].commands["status"], ["LINE-CARD1"]) result_lines = result.output.strip('\n').split('\n') assert result.exit_code == 0 result_out = (result_lines[header_lines]).split() @@ -81,14 +159,14 @@ def test_show_module_down(self): def test_show_incorrect_command(self): runner = CliRunner() - result = runner.invoke(show.cli.commands["chassis-modules"], []) + result = runner.invoke(show.cli.commands["chassis"].commands["modules"], []) print(result.output) print(result.exit_code) assert result.exit_code == 0 def test_show_incorrect_module(self): runner = CliRunner() - result = runner.invoke(show.cli.commands["chassis-modules"].commands["status"], ["TEST-CARD1"]) + result = runner.invoke(show.cli.commands["chassis"].commands["modules"].commands["status"], ["TEST-CARD1"]) print(result.output) print(result.exit_code) assert result.exit_code == 0 @@ -96,12 +174,12 @@ def test_show_incorrect_module(self): def test_config_shutdown_module(self): runner = CliRunner() db = Db() - result = runner.invoke(config.config.commands["chassis-modules"].commands["shutdown"], ["LINE-CARD0"], obj=db) + result = runner.invoke(config.config.commands["chassis"].commands["modules"].commands["shutdown"], ["LINE-CARD0"], obj=db) print(result.exit_code) print(result.output) assert result.exit_code == 0 - result = runner.invoke(show.cli.commands["chassis-modules"].commands["status"], ["LINE-CARD0"], obj=db) + result = runner.invoke(show.cli.commands["chassis"].commands["modules"].commands["status"], ["LINE-CARD0"], obj=db) print(result.exit_code) print(result.output) result_lines = result.output.strip('\n').split('\n') @@ -115,12 +193,12 @@ def test_config_shutdown_module(self): def test_config_startup_module(self): runner = CliRunner() db = Db() - result = runner.invoke(config.config.commands["chassis-modules"].commands["startup"], ["LINE-CARD0"], obj=db) + result = runner.invoke(config.config.commands["chassis"].commands["modules"].commands["startup"], ["LINE-CARD0"], obj=db) print(result.exit_code) print(result.output) assert result.exit_code == 0 - result = runner.invoke(show.cli.commands["chassis-modules"].commands["status"], ["LINE-CARD0"], obj=db) + result = runner.invoke(show.cli.commands["chassis"].commands["modules"].commands["status"], ["LINE-CARD0"], obj=db) print(result.exit_code) print(result.output) result_lines = result.output.strip('\n').split('\n') @@ -131,20 +209,20 @@ def test_config_startup_module(self): def test_config_incorrect_module(self): runner = CliRunner() db = Db() - result = runner.invoke(config.config.commands["chassis-modules"].commands["shutdown"], ["TEST-CARD0"], obj=db) + result = runner.invoke(config.config.commands["chassis"].commands["modules"].commands["shutdown"], ["TEST-CARD0"], obj=db) print(result.exit_code) print(result.output) assert result.exit_code != 0 def test_show_and_verify_midplane_output(self): runner = CliRunner() - result = runner.invoke(show.cli.commands["chassis-modules"].commands["midplane-status"], []) + result = runner.invoke(show.cli.commands["chassis"].commands["modules"].commands["midplane-status"], []) print(result.output) assert(result.output == show_chassis_midplane_output) def test_midplane_show_all_count_lines(self): runner = CliRunner() - result = runner.invoke(show.cli.commands["chassis-modules"].commands["midplane-status"], []) + result = runner.invoke(show.cli.commands["chassis"].commands["modules"].commands["midplane-status"], []) print(result.output) result_lines = result.output.strip('\n').split('\n') modules = ["LINE-CARD0", "LINE-CARD1", "SUPERVISOR0"] @@ -154,7 +232,7 @@ def test_midplane_show_all_count_lines(self): def test_midplane_show_single_count_lines(self): runner = CliRunner() - result = runner.invoke(show.cli.commands["chassis-modules"].commands["midplane-status"], ["LINE-CARD0"]) + result = runner.invoke(show.cli.commands["chassis"].commands["modules"].commands["midplane-status"], ["LINE-CARD0"]) print(result.output) result_lines = result.output.strip('\n').split('\n') modules = ["LINE-CARD0"] @@ -164,7 +242,7 @@ def test_midplane_show_single_count_lines(self): def test_midplane_show_module_down(self): runner = CliRunner() - result = runner.invoke(show.cli.commands["chassis-modules"].commands["midplane-status"], ["LINE-CARD1"]) + result = runner.invoke(show.cli.commands["chassis"].commands["modules"].commands["midplane-status"], ["LINE-CARD1"]) print(result.output) result_lines = result.output.strip('\n').split('\n') assert result.exit_code == 0 @@ -174,11 +252,80 @@ def test_midplane_show_module_down(self): def test_midplane_show_incorrect_module(self): runner = CliRunner() - result = runner.invoke(show.cli.commands["chassis-modules"].commands["midplane-status"], ["TEST-CARD1"]) + result = runner.invoke(show.cli.commands["chassis"].commands["modules"].commands["midplane-status"], ["TEST-CARD1"]) print(result.output) print(result.exit_code) assert result.exit_code == 0 + def test_show_and_verify_system_ports_output_asic0(self): + os.environ["UTILITIES_UNIT_TESTING_TOPOLOGY"] = "multi_asic" + return_code, result = get_result_and_return_code('voqutil -c system_ports -n asic0') + print("return_code: {}".format(return_code)) + print("result = {}".format(result)) + assert return_code == 0 + assert result == show_chassis_system_ports_output_asic0 + + def test_show_and_verify_system_ports_output_1_asic0(self): + return_code, result = get_result_and_return_code('voqutil -c system_ports -i "Linecard1|Asic0|Ethernet0" -n asic0') + print("return_code: {}".format(return_code)) + print("result = {}".format(result)) + assert return_code == 0 + assert result == show_chassis_system_ports_output_1_asic0 + os.environ["UTILITIES_UNIT_TESTING_TOPOLOGY"] = "" + + def test_show_and_verify_system_neighbors_output_all(self): + runner = CliRunner() + result = runner.invoke(show.cli.commands["chassis"].commands["system-neighbors"], []) + print(result.output) + assert(result.output == show_chassis_system_neighbors_output_all) + + def test_show_and_verify_system_neighbors_output_ipv4(self): + return_code, result = get_result_and_return_code('voqutil -c system_neighbors -a 10.0.0.5') + print("return_code: {}".format(return_code)) + print("result = {}".format(result)) + assert return_code == 0 + assert result == show_chassis_system_neighbors_output_ipv4 + + def test_show_and_verify_system_neighbors_output_ipv6(self): + return_code, result = get_result_and_return_code('voqutil -c system_neighbors -a fc00::16') + print("return_code: {}".format(return_code)) + print("result = {}".format(result)) + assert return_code == 0 + assert result == show_chassis_system_neighbors_output_ipv6 + + def test_show_and_verify_system_neighbors_output_asic0(self): + return_code, result = get_result_and_return_code('voqutil -c system_neighbors -n Asic0') + print("return_code: {}".format(return_code)) + print("result = {}".format(result)) + assert return_code == 0 + assert result == show_chassis_system_neighbors_output_asic0 + + def test_show_and_verify_system_lags_output(self): + runner = CliRunner() + result = runner.invoke(show.cli.commands["chassis"].commands["system-lags"], []) + print(result.output) + assert(result.output == show_chassis_system_lags_output) + + def test_show_and_verify_system_lags_output_1(self): + runner = CliRunner() + result = runner.invoke(show.cli.commands["chassis"].commands["system-lags"], ["""Linecard4|Asic2|PortChannel0001"""]) + print(result.output) + assert(result.output == show_chassis_system_lags_output_1) + + def test_show_and_verify_system_lags_output_asic1(self): + return_code, result = get_result_and_return_code('voqutil -c system_lags -n Asic1') + print("return_code: {}".format(return_code)) + print("result = {}".format(result)) + assert return_code == 0 + assert result == show_chassis_system_lags_output_asic1 + + def test_show_and_verify_system_lags_output_lc4(self): + return_code, result = get_result_and_return_code('voqutil -c system_lags -l Linecard4') + print("return_code: {}".format(return_code)) + print("result = {}".format(result)) + assert return_code == 0 + assert result == show_chassis_system_lags_output_lc4 + @classmethod def teardown_class(cls): print("TEARDOWN") diff --git a/tests/mock_tables/asic0/appl_db.json b/tests/mock_tables/asic0/appl_db.json index a708aa7fd69b..a70b0f89c968 100644 --- a/tests/mock_tables/asic0/appl_db.json +++ b/tests/mock_tables/asic0/appl_db.json @@ -59,6 +59,41 @@ "role": "Int", "speed": "100000" }, + "SYSTEM_PORT_TABLE:Linecard1|Asic0|Ethernet0": { + "core_index": "0", + "core_port_index": "1", + "speed": "100000", + "switch_id": "0", + "system_port_id": "1" + }, + "SYSTEM_PORT_TABLE:Linecard1|Asic0|Ethernet-IB0": { + "core_index": "1", + "core_port_index": "6", + "speed": "10000", + "switch_id": "0", + "system_port_id": "13" + }, + "SYSTEM_PORT_TABLE:Linecard1|Asic1|Ethernet12": { + "core_index": "0", + "core_port_index": "1", + "speed": "100000", + "switch_id": "2", + "system_port_id": "65" + }, + "SYSTEM_PORT_TABLE:Linecard1|Asic2|Ethernet24": { + "core_index": "0", + "core_port_index": "1", + "speed": "100000", + "switch_id": "4", + "system_port_id": "129" + }, + "SYSTEM_PORT_TABLE:Linecard2|Asic0|Ethernet0": { + "core_index": "0", + "core_port_index": "1", + "speed": "100000", + "switch_id": "6", + "system_port_id": "193" + }, "LAG_MEMBER_TABLE:PortChannel1002:Ethernet0": { "status": "disabled" }, @@ -93,4 +128,4 @@ "INTF_TABLE:Ethernet-BP4": { "mpls":"disable" } -} +} \ No newline at end of file diff --git a/tests/mock_tables/asic1/appl_db.json b/tests/mock_tables/asic1/appl_db.json index 37e992c415a2..d938f6b830d7 100644 --- a/tests/mock_tables/asic1/appl_db.json +++ b/tests/mock_tables/asic1/appl_db.json @@ -45,6 +45,41 @@ "role": "Int", "speed": "100000" }, + "SYSTEM_PORT_TABLE:Linecard1|Asic0|Ethernet0": { + "core_index": "0", + "core_port_index": "1", + "speed": "100000", + "switch_id": "0", + "system_port_id": "1" + }, + "SYSTEM_PORT_TABLE:Linecard1|Asic0|Ethernet-IB0": { + "core_index": "1", + "core_port_index": "6", + "speed": "10000", + "switch_id": "0", + "system_port_id": "13" + }, + "SYSTEM_PORT_TABLE:Linecard1|Asic1|Ethernet12": { + "core_index": "0", + "core_port_index": "1", + "speed": "100000", + "switch_id": "2", + "system_port_id": "65" + }, + "SYSTEM_PORT_TABLE:Linecard1|Asic2|Ethernet24": { + "core_index": "0", + "core_port_index": "1", + "speed": "100000", + "switch_id": "4", + "system_port_id": "129" + }, + "SYSTEM_PORT_TABLE:Linecard2|Asic0|Ethernet0": { + "core_index": "0", + "core_port_index": "1", + "speed": "100000", + "switch_id": "6", + "system_port_id": "193" + }, "LAG_TABLE:PortChannel4009": { "admin_status": "up", "oper_status": "up", diff --git a/tests/mock_tables/asic2/appl_db.json b/tests/mock_tables/asic2/appl_db.json index 56eaf377bbe8..7dd9c66515cb 100644 --- a/tests/mock_tables/asic2/appl_db.json +++ b/tests/mock_tables/asic2/appl_db.json @@ -59,6 +59,41 @@ "role": "Int", "speed": "100000" }, + "SYSTEM_PORT_TABLE:Linecard1|Asic0|Ethernet0": { + "core_index": "0", + "core_port_index": "1", + "speed": "100000", + "switch_id": "0", + "system_port_id": "1" + }, + "SYSTEM_PORT_TABLE:Linecard1|Asic0|Ethernet-IB0": { + "core_index": "1", + "core_port_index": "6", + "speed": "10000", + "switch_id": "0", + "system_port_id": "13" + }, + "SYSTEM_PORT_TABLE:Linecard1|Asic1|Ethernet12": { + "core_index": "0", + "core_port_index": "1", + "speed": "100000", + "switch_id": "2", + "system_port_id": "65" + }, + "SYSTEM_PORT_TABLE:Linecard1|Asic2|Ethernet24": { + "core_index": "0", + "core_port_index": "1", + "speed": "100000", + "switch_id": "4", + "system_port_id": "129" + }, + "SYSTEM_PORT_TABLE:Linecard2|Asic0|Ethernet0": { + "core_index": "0", + "core_port_index": "1", + "speed": "100000", + "switch_id": "6", + "system_port_id": "193" + }, "LAG_MEMBER_TABLE:PortChannel1015:Ethernet20": { "status": "enabled" }, diff --git a/tests/mock_tables/chassis_app_db.json b/tests/mock_tables/chassis_app_db.json new file mode 100644 index 000000000000..56e1c4de2e61 --- /dev/null +++ b/tests/mock_tables/chassis_app_db.json @@ -0,0 +1,54 @@ +{ + "SYSTEM_LAG_MEMBER_TABLE|Linecard2|Asic1|PortChannel0002:Linecard2|Asic1|Ethernet16": { + "NULL": "NULL" + }, + "SYSTEM_LAG_MEMBER_TABLE|Linecard2|Asic1|PortChannel0002:Linecard2|Asic1|Ethernet17": { + "NULL": "NULL" + }, + "SYSTEM_LAG_MEMBER_TABLE|Linecard4|Asic2|PortChannel0001:Linecard4|Asic2|Ethernet29": { + "NULL": "NULL" + }, + "SYSTEM_LAG_MEMBER_TABLE|Linecard4|Asic2|PortChannel0001:Linecard4|Asic2|Ethernet30": { + "NULL": "NULL" + }, + "SYSTEM_LAG_TABLE|Linecard2|Asic1|PortChannel0002": { + "lag_id": "1", + "switch_id": "8" + }, + "SYSTEM_LAG_TABLE|Linecard4|Asic2|PortChannel0001": { + "lag_id": "2", + "switch_id": "22" + }, + "SYSTEM_NEIGH|Linecard2|Asic0|Ethernet-IB0|3.3.3.4": { + "encap_index": "1074790404", + "neigh": "24:21:24:05:81:f7" + }, + "SYSTEM_NEIGH|Linecard2|Asic0|Ethernet-IB0|3333::3:4": { + "encap_index": "1074790405", + "neigh": "24:21:24:05:81:f7" + }, + "SYSTEM_NEIGH|Linecard2|Asic0|Ethernet4|10.0.0.5": { + "encap_index": "1074790406", + "neigh": "b6:8c:4f:18:67:ff" + }, + "SYSTEM_NEIGH|Linecard2|Asic0|Ethernet4|fc00::a": { + "encap_index": "1074790407", + "neigh": "b6:8c:4f:18:67:ff" + }, + "SYSTEM_NEIGH|Linecard2|Asic1|PortChannel0002|10.0.0.1": { + "encap_index": "1074790406", + "neigh": "26:8b:37:fa:8e:67" + }, + "SYSTEM_NEIGH|Linecard2|Asic1|PortChannel0002|fc00::2": { + "encap_index": "1074790407", + "neigh": "26:8b:37:fa:8e:67" + }, + "SYSTEM_NEIGH|Linecard4|Asic0|Ethernet5|10.0.0.11": { + "encap_index": "1074790406", + "neigh": "46:c3:71:8c:dd:2d" + }, + "SYSTEM_NEIGH|Linecard4|Asic0|Ethernet5|fc00::16": { + "encap_index": "1074790407", + "neigh": "46:c3:71:8c:dd:2d" + } +} \ No newline at end of file diff --git a/tests/mock_tables/database_config.json b/tests/mock_tables/database_config.json index 04c064abb35e..d12ba054146a 100644 --- a/tests/mock_tables/database_config.json +++ b/tests/mock_tables/database_config.json @@ -51,6 +51,11 @@ "id" : 7, "separator": "|", "instance" : "redis" + }, + "CHASSIS_APP_DB" : { + "id" : 12, + "separator": "|", + "instance" : "redis" } }, "VERSION" : "1.1"