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
224 changes: 222 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']

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove blank line 67. Consider adding blank line between 65 and 66.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

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

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove blank line 78. Consider adding blank line between 76 and 77.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

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"):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggest to add a comment explaining that we don't translate the output of intfutil because it already displays both the name and alias for each interface.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed as above

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,150 @@ 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()


paavaanan marked this conversation as resolved.
Show resolved Hide resolved
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]
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")):
"""show interface transceiver lpmode,
presence, eeprom
"""
paavaanan marked this conversation as resolved.
Show resolved Hide resolved
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 +350,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 +403,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 +483,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 Down Expand Up @@ -349,6 +551,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 +568,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 @@ -439,6 +647,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 +797,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 +967,8 @@ 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 +1171,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