Skip to content
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

Add 'alias mode' support for show commands #298

Merged
merged 13 commits into from
Sep 27, 2018
247 changes: 245 additions & 2 deletions show/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import getpass
import json
import os
import re
import subprocess
import sys
from click_default_group import DefaultGroup
Expand Down Expand Up @@ -38,6 +39,46 @@ def read_config(self, filename):
pass


class InterfaceAliasConverter(object):
"""Class which handles conversion between interface name and alias"""

def __init__(self):
self.alias_max_length = 0
cmd = 'sonic-cfggen -d --var-json "PORT"'
p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE)
self.port_dict = json.loads(p.stdout.read())

for port_name in self.port_dict.keys():
if self.alias_max_length < len(
self.port_dict[port_name]['alias']):
self.alias_max_length = len(
self.port_dict[port_name]['alias'])

def name_to_alias(self, interface_name):
"""Return vendor interface alias if SONiC
interface name is given as argument
"""
if interface_name is not None:
for port_name in self.port_dict.keys():
if interface_name == port_name:
return self.port_dict[port_name]['alias']

click.echo("Invalid interface {}".format(interface_name))
raise click.Abort()

def alias_to_name(self, interface_alias):
"""Return SONiC interface name if vendor
port alias is given as argument
"""
if interface_alias is not None:
for port_name in self.port_dict.keys():
if interface_alias == self.port_dict[port_name]['alias']:
return port_name

click.echo("Invalid interface {}".format(interface_alias))
raise click.Abort()


# Global Config object
_config = None

Expand Down Expand Up @@ -116,6 +157,12 @@ def run_command(command, display_cmd=False):
if display_cmd:
click.echo(click.style("Command: ", fg='cyan') + click.style(command, fg='green'))

# No conversion needed for intfutil commands as it already displays
# both SONiC interface name and alias name for all interfaces.
if get_interface_mode() == "alias" and not command.startswith("intfutil"):
run_command_in_alias_mode(command)
raise sys.exit(0)

proc = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE)

while True:
Expand All @@ -129,6 +176,156 @@ def run_command(command, display_cmd=False):
if rc != 0:
sys.exit(rc)


def get_interface_mode():
mode = os.getenv('SONIC_CLI_IFACE_MODE')
jleveque marked this conversation as resolved.
Show resolved Hide resolved
if mode is None:
mode = "default"
return mode


# Global class instance for SONiC interface name to alias conversion
iface_alias_converter = InterfaceAliasConverter()


def print_output_in_alias_mode(output, index):
"""Convert and print all instances of SONiC interface
name to vendor-sepecific interface aliases.
"""

alias_name = ""
interface_name = ""

# Adjust tabulation width to length of alias name
if output.startswith("---"):
word = output.split()
dword = word[index]
underline = dword.rjust(iface_alias_converter.alias_max_length,
'-')
word[index] = underline
output = ' ' .join(word)

# Replace SONiC interface name with vendor alias
word = output.split()
if word:
interface_name = word[index]
interface_name = interface_name.replace(':', '')
for port_name in natsorted(iface_alias_converter.port_dict.keys()):
if interface_name == port_name:
alias_name = iface_alias_converter.port_dict[port_name]['alias']
if alias_name:
if len(alias_name) < iface_alias_converter.alias_max_length:
alias_name = alias_name.rjust(
iface_alias_converter.alias_max_length)
output = output.replace(interface_name, alias_name, 1)

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


def run_command_in_alias_mode(command):
"""Run command and replace all instances of SONiC interface names
in output with vendor-sepecific interface aliases.
"""

process = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE)

while True:
output = process.stdout.readline()
if output == '' and process.poll() is not None:
break

if output:
index = 1
raw_output = output
output = output.lstrip()

if command.startswith("portstat"):
"""Show interface counters"""
index = 0
if output.startswith("IFACE"):
output = output.replace("IFACE", "IFACE".rjust(
iface_alias_converter.alias_max_length))
print_output_in_alias_mode(output, index)

elif command == "pfcstat":
"""Show pfc counters"""
index = 0
if output.startswith("Port Tx"):
output = output.replace("Port Tx", "Port Tx".rjust(
iface_alias_converter.alias_max_length))

elif output.startswith("Port Rx"):
output = output.replace("Port Rx", "Port Rx".rjust(
iface_alias_converter.alias_max_length))
print_output_in_alias_mode(output, index)

elif (command.startswith("sudo sfputil show eeprom")):
"""show interface transceiver eeprom"""
index = 0
print_output_in_alias_mode(raw_output, index)

elif (command.startswith("sudo sfputil show")):
"""show interface transceiver lpmode,
presence
"""
index = 0
if output.startswith("Port"):
output = output.replace("Port", "Port".rjust(
iface_alias_converter.alias_max_length))
print_output_in_alias_mode(output, index)

elif command == "sudo lldpshow":
"""show lldp table"""
index = 0
if output.startswith("LocalPort"):
output = output.replace("LocalPort", "LocalPort".rjust(
iface_alias_converter.alias_max_length))
print_output_in_alias_mode(output, index)

elif command.startswith("queuestat"):
"""show queue counters"""
index = 0
if output.startswith("Port"):
output = output.replace("Port", "Port".rjust(
iface_alias_converter.alias_max_length))
print_output_in_alias_mode(output, index)

elif command == "fdbshow":
"""show mac"""
index = 3
if output.startswith("No."):
output = " " + output
output = re.sub(
'Type', ' Type', output)
elif output[0].isdigit():
output = " " + output
print_output_in_alias_mode(output, index)
elif command.startswith("nbrshow"):
"""show arp"""
index = 2
if "Vlan" in output:
output = output.replace('Vlan', ' Vlan')
print_output_in_alias_mode(output, index)

else:
if index:
for port_name in iface_alias_converter.port_dict.keys():
regex = re.compile(r"\b{}\b".format(port_name))
result = re.findall(regex, raw_output)
if result:
interface_name = ''.join(result)
if not raw_output.startswith(" PortID:"):
raw_output = raw_output.replace(
interface_name,
iface_alias_converter.name_to_alias(
interface_name))
click.echo(raw_output.rstrip('\n'))

rc = process.poll()
if rc != 0:
sys.exit(rc)


CONTEXT_SETTINGS = dict(help_option_names=['-h', '--help', '-?'])

#
Expand Down Expand Up @@ -159,6 +356,11 @@ def arp(ipaddress, iface, verbose):
cmd += " -ip {}".format(ipaddress)

if iface is not None:
if get_interface_mode() == "alias":
if not ((iface.startswith("PortChannel")) or
(iface.startswith("eth"))):
iface = iface_alias_converter.alias_to_name(iface)

cmd += " -if {}".format(iface)

run_command(cmd, display_cmd=verbose)
Expand Down Expand Up @@ -207,6 +409,9 @@ def alias(interfacename):
body = []

if interfacename is not None:
if get_interface_mode() == "alias":
interfacename = iface_alias_converter.alias_to_name(interfacename)

# If we're given an interface name, output name and alias for that interface only
if interfacename in port_dict:
if 'alias' in port_dict[interfacename]:
Expand Down Expand Up @@ -284,6 +489,9 @@ def summary(interfacename, verbose):
cmd = "/sbin/ifconfig"

if interfacename is not None:
if get_interface_mode() == "alias":
interfacename = iface_alias_converter.alias_to_name(interfacename)

cmd += " {}".format(interfacename)

run_command(cmd, display_cmd=verbose)
Expand All @@ -308,6 +516,9 @@ def eeprom(interfacename, dump_dom, verbose):
cmd += " --dom"

if interfacename is not None:
if get_interface_mode() == "alias":
interfacename = iface_alias_converter.alias_to_name(interfacename)

cmd += " -p {}".format(interfacename)

run_command(cmd, display_cmd=verbose)
Expand All @@ -322,6 +533,9 @@ def lpmode(interfacename, verbose):
cmd = "sudo sfputil show lpmode"

if interfacename is not None:
if get_interface_mode() == "alias":
interfacename = iface_alias_converter.alias_to_name(interfacename)

cmd += " -p {}".format(interfacename)

run_command(cmd, display_cmd=verbose)
Expand All @@ -335,6 +549,9 @@ def presence(interfacename, verbose):
cmd = "sudo sfputil show presence"

if interfacename is not None:
if get_interface_mode() == "alias":
interfacename = iface_alias_converter.alias_to_name(interfacename)

cmd += " -p {}".format(interfacename)

run_command(cmd, display_cmd=verbose)
Expand All @@ -349,6 +566,9 @@ def description(interfacename, verbose):
cmd = "intfutil description"

if interfacename is not None:
if get_interface_mode() == "alias":
interfacename = iface_alias_converter.alias_to_name(interfacename)

cmd += " {}".format(interfacename)

run_command(cmd, display_cmd=verbose)
Expand All @@ -363,6 +583,9 @@ def status(interfacename, verbose):
cmd = "intfutil status"

if interfacename is not None:
if get_interface_mode() == "alias":
interfacename = iface_alias_converter.alias_to_name(interfacename)

cmd += " {}".format(interfacename)

run_command(cmd, display_cmd=verbose)
Expand Down Expand Up @@ -420,6 +643,15 @@ def counters(clear, verbose):

run_command(cmd, display_cmd=verbose)

# 'naming_mode' subcommand ("show interfaces naming_mode")
@interfaces.command()
@click.option('--verbose', is_flag=True, help="Enable verbose output")
def naming_mode(verbose):
"""Show interface naming_mode status"""

click.echo(get_interface_mode())


#
# 'queue' group ("show queue ...")
#
Expand All @@ -439,6 +671,10 @@ def counters(interfacename, clear, verbose):

cmd = "queuestat"

if interfacename is not None:
if get_interface_mode() == "alias":
interfacename = iface_alias_converter.alias_to_name(interfacename)

if clear:
cmd += " -c"
else:
Expand Down Expand Up @@ -585,6 +821,9 @@ def neighbors(interfacename, verbose):
cmd = "sudo lldpctl"

if interfacename is not None:
if get_interface_mode() == "alias":
interfacename = iface_alias_converter.alias_to_name(interfacename)

cmd += " {}".format(interfacename)

run_command(cmd, display_cmd=verbose)
Expand Down Expand Up @@ -752,7 +991,7 @@ def cpu(verbose):
# Run top in batch mode to prevent unexpected newline after each newline
cmd = "top -bn 1 -o %CPU"
run_command(cmd, display_cmd=verbose)

# 'memory' subcommand
@processes.command()
@click.option('--verbose', is_flag=True, help="Enable verbose output")
Expand Down Expand Up @@ -955,7 +1194,11 @@ def tablelize(keys, data):
r = []
r.append(k)
r.append(data[k]['vlanid'])
r.append(m)
if get_interface_mode() == "alias":
alias = iface_alias_converter.name_to_alias(m)
r.append(alias)
else:
r.append(m)

entry = config_db.get_entry('VLAN_MEMBER', (k, m))
mode = entry.get('tagging_mode')
Expand Down