Skip to content

[DRAFT] sonic-utilities: Create SONiC ISIS show commands #2685

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 10 commits into
base: master
Choose a base branch
from
150 changes: 150 additions & 0 deletions show/isis_frr.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
import click

import utilities_common.bgp_util as bgp_util
import utilities_common.cli as clicommon
from natsort import natsorted
from swsscommon.swsscommon import ConfigDBConnector


###############################################################################
#
# 'show isis' cli stanza
#
############################################################################### 

def get_interfaces():
"""Get list of interfaces
"""
tables = ['LOOPBACK_INTERFACE', 'PORT', 'PORTCHANNEL']
data = []

config_db = ConfigDBConnector()
config_db.connect()

for table_name in tables:
interface_list = list(config_db.get_table(table_name).keys())
interface_list = [x for x in interface_list if isinstance(x, str)]
data += natsorted(interface_list)
return data

INTERFACE_LIST = get_interfaces()

def invalid_arg(input:str):
if input == '?':
ctx = click.get_current_context()
ctx.fail('The argument: "{}" is invalid. Try "-?".'.format(input))

@click.group(cls=clicommon.AliasedGroup, name="isis")
def isis():
"""Show ISIS (Intermediate System to Intermediate System) information"""
pass


# 'neighbors' subcommand ("show isis neighbors")
@isis.command()
@click.argument('system_id', required=False)
@click.option('--verbose', is_flag=True, help="Enable verbose output")
def neighbors(system_id, verbose):
"""Show ISIS neighbors"""

command = 'show isis neighbor'
if system_id is not None:
invalid_arg(system_id)
command += ' {}'.format(system_id)
elif verbose:
command += ' detail'

output = ""
output += bgp_util.run_bgp_show_command(command)

click.echo(output.rstrip('\n'))

# 'database' subcommand ("show isis database")
@isis.command()
@click.argument('lsp_id', required=False)
@click.option('--verbose', is_flag=True, help="Enable verbose output")
def database(lsp_id, verbose):
"""Show ISIS database"""

command = 'show isis database'
if verbose:
command += ' detail'
if lsp_id is not None:
invalid_arg(lsp_id)
command += ' {0}'.format(lsp_id)

output = ""
output += bgp_util.run_bgp_show_command(command)

click.echo(output.rstrip('\n'))

# 'hostname' subcommand ("show isis hostname")
@isis.command()
def hostname():
"""Show ISIS hostname"""

command = 'show isis hostname'

output = ""
output += bgp_util.run_bgp_show_command(command)

click.echo(output.rstrip('\n'))

# 'interface' subcommand ("show isis interface")
@isis.command()
@click.argument('interface',
metavar='[INTERFACE]',
type=click.Choice(
INTERFACE_LIST),
required=False)
@click.option('--verbose', is_flag=True, help="Enable verbose output")
@click.option('--display', is_flag=True, help=f"Display available [INTERFACE] options:\n{INTERFACE_LIST}")
def interface(interface, verbose, display):
"""Show ISIS interface"""

if display:
d = f"[INTERFACE] options: {INTERFACE_LIST}"
click.echo(d.rstrip('\n'))

command = 'show isis interface'

if interface is not None:
command += ' {0}'.format(interface)
elif verbose:
command += ' detail'

output = ""
output += bgp_util.run_bgp_show_command(command)

click.echo(output.rstrip('\n'))

# 'topology' subcommand ("show isis topology")
@isis.command()
@click.option('--level-1', is_flag=True, help="Show IS-IS level-1 information")
@click.option('--level-2', is_flag=True, help="Show IS-IS level-2 information")
def topology(level_1, level_2):
"""Show ISIS topology"""

command = 'show isis topology'

if level_1:
command += ' level-1'
elif level_2:
command += ' level-2'

output = ""
output += bgp_util.run_bgp_show_command(command)

click.echo(output.rstrip('\n'))

# 'summary' subcommand ("show isis summary")
@isis.command()
def summary():
"""Show ISIS summary"""

command = 'show isis summary'

output = ""
output += bgp_util.run_bgp_show_command(command)

click.echo(output.rstrip('\n'))
60 changes: 60 additions & 0 deletions show/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
from . import flow_counters
from . import gearbox
from . import interfaces
from . import isis_frr
from . import kdump
from . import kube
from . import muxcable
Expand Down Expand Up @@ -276,6 +277,7 @@ def cli(ctx):
cli.add_command(flow_counters.flowcnt_trap)
cli.add_command(kdump.kdump)
cli.add_command(interfaces.interfaces)
cli.add_command(isis_frr.isis)
cli.add_command(kdump.kdump)
cli.add_command(kube.kubernetes)
cli.add_command(muxcable.muxcable)
Expand Down Expand Up @@ -1479,6 +1481,64 @@ def bgp(namespace, verbose):
print(output)


# 'isis' subcommand ("show runningconfiguration isis")
@runningconfiguration.command()
@click.option('--verbose', is_flag=True, help="Enable verbose output")
@click.option('--config_db', is_flag=True, help="Enable config DB output")
@click.option('--namespace', '-n', 'namespace', required=False, default=None, type=str, show_default=False,
help='Option needed for multi-asic only: provide namespace name',
callback=multi_asic_util.multi_asic_namespace_validation_callback)
def isis(namespace, config_db, verbose):
"""
Show ISIS running configuration
Note:
multi-asic can run 'show run isis' and show from all asics, or 'show run isis -n <ns>'
single-asic only run 'show run isis', '-n' is not available
"""

if multi_asic.is_multi_asic():
if namespace and namespace not in multi_asic.get_namespace_list():
ctx = click.get_current_context()
ctx.fail("invalid value for -n/--namespace option. provide namespace from list {}".format(multi_asic.get_namespace_list()))
if not multi_asic.is_multi_asic() and namespace:
ctx = click.get_current_context()
ctx.fail("-n/--namespace is not available for single asic")

if (config_db):
full_isis_conf = {}

cmd = "sonic-cfggen -d --var-json ISIS_GLOBAL"
global_output = run_command(cmd, return_cmd=True)

cmd = "sonic-cfggen -d --var-json ISIS_LEVEL"
level_output = run_command(cmd, return_cmd=True)

cmd = "sonic-cfggen -d --var-json ISIS_INTERFACE"
interface_output = run_command(cmd, return_cmd=True)

full_isis_conf["ISIS_GLOBAL"] = json.loads(global_output)
full_isis_conf["ISIS_LEVEL"] = json.loads(level_output)
full_isis_conf["ISIS_INTERFACE"] = json.loads(interface_output)

click.echo(json.dumps(full_isis_conf, indent=4))
else:
output = ""
cmd = "show running-config isis"
import utilities_common.bgp_util as bgp_util
if multi_asic.is_multi_asic():
if not namespace:
ns_list = multi_asic.get_namespace_list()
for ns in ns_list:
output += "\n------------Showing running config isis on {}------------\n".format(ns)
output += bgp_util.run_bgp_show_command(cmd, ns)
else:
output += "\n------------Showing running config isis on {}------------\n".format(namespace)
output += bgp_util.run_bgp_show_command(cmd, namespace)
else:
output += bgp_util.run_bgp_show_command(cmd)
click.echo(output.rstrip('\n'))


# 'interfaces' subcommand ("show runningconfiguration interfaces")
@runningconfiguration.command()
@click.argument('interfacename', required=False)
Expand Down
52 changes: 52 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,15 @@
mock_show_bgp_network_single_asic,
mock_show_bgp_network_multi_asic
)
from .isis_frr_input.isis_frr_test_vector import(
mock_show_isis_neighbors,
mock_show_isis_database,
mock_show_isis_hostname,
mock_show_isis_interface,
mock_show_isis_topology,
mock_show_isis_summary,
mock_show_run_isis
)
from . import config_int_ip_common
import utilities_common.constants as constants
import config.main as config
Expand Down Expand Up @@ -371,3 +380,46 @@ def mock_restart_dhcp_relay_service():

config.vlan.dhcp_relay_util.restart_dhcp_relay_service = origin_funcs[0]
config.vlan.is_dhcp_relay_running = origin_funcs[1]

@pytest.fixture
def setup_single_isis_instance(request):
import utilities_common.bgp_util as bgp_util

_old_run_bgp_command = bgp_util.run_bgp_command

if request.param.startswith('isis_neighbor') or \
request.param.startswith('isis_neighbor'):
bgp_util.run_bgp_command = mock.MagicMock(
return_value=mock_show_isis_neighbors(request))
elif request.param.startswith('isis_database') or \
request.param.startswith('isis_database'):
bgp_util.run_bgp_command = mock.MagicMock(
return_value=mock_show_isis_database(request))
elif request.param.startswith('isis_hostname') or \
request.param.startswith('isis_hostname'):
bgp_util.run_bgp_command = mock.MagicMock(
return_value=mock_show_isis_hostname(request))
elif request.param.startswith('isis_interface') or \
request.param.startswith('isis_interface'):
bgp_util.run_bgp_command = mock.MagicMock(
return_value=mock_show_isis_interface(request))
elif request.param.startswith('isis_topology') or \
request.param.startswith('isis_topology'):
bgp_util.run_bgp_command = mock.MagicMock(
return_value=mock_show_isis_topology(request))
elif request.param.startswith('isis_summary'):
bgp_util.run_bgp_command = mock.MagicMock(
return_value=mock_show_isis_summary(request))
elif request.param.startswith('show_run_isis'):
bgp_util.run_bgp_command = mock.MagicMock(
return_value=mock_show_run_isis(request))

yield

bgp_util.run_bgp_command = _old_run_bgp_command


@pytest.fixture
def setup_isis_commands():
import show.main as show
return show
Empty file.
Loading