-
Notifications
You must be signed in to change notification settings - Fork 669
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
Changes from 9 commits
ab66306
e33af6f
cd42d7b
c6d0c46
3161fc2
a38bcdb
867047c
04f747e
03521a5
dee1c31
8a33b82
2080fe8
b733b55
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,6 +5,7 @@ | |
import getpass | ||
import json | ||
import os | ||
import re | ||
import subprocess | ||
import sys | ||
from click_default_group import DefaultGroup | ||
|
@@ -38,6 +39,45 @@ def read_config(self, filename): | |
pass | ||
|
||
|
||
class InterfaceAliasConverter(object): | ||
"""Class which handles conversion between interface name and alias""" | ||
|
||
def __init__(self): | ||
self.vendor_name_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.vendor_name_max_length < len( | ||
self.port_dict[port_name]['alias']): | ||
self.vendor_name_max_length = len( | ||
self.port_dict[port_name]['alias']) | ||
|
||
def name_to_alias(self, interface_name): | ||
"""Return alias interface name if default | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Clarify comment: "Return vendor interface alias if SONiC interface name is given as argument" There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👍 |
||
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'] | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Remove blank line 67. Consider adding blank line between 65 and 66. There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 default interface name if alias name is given as argument | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Clarify comment: "Return SONiC interface name if vendor port alias given as argument" There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👍 |
||
""" | ||
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 | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Remove blank line 78. Consider adding blank line between 76 and 77. There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 | ||
|
||
|
@@ -116,6 +156,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"): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 There was a problem hiding this comment. Choose a reason for hiding this commentThe 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: | ||
|
@@ -129,6 +175,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.vendor_name_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.vendor_name_max_length: | ||
alias_name = alias_name.rjust( | ||
iface_alias_converter.vendor_name_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.vendor_name_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.vendor_name_max_length)) | ||
|
||
elif output.startswith("Port Rx"): | ||
output = output.replace("Port Rx", "Port Rx".rjust( | ||
iface_alias_converter.vendor_name_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.vendor_name_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.vendor_name_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.vendor_name_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', '-?']) | ||
|
||
# | ||
|
@@ -159,6 +349,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) | ||
|
@@ -207,6 +402,10 @@ def alias(interfacename): | |
body = [] | ||
|
||
if interfacename is not None: | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Remove blank line There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👍 |
||
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]: | ||
|
@@ -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) | ||
|
@@ -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) | ||
|
@@ -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) | ||
|
@@ -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: | ||
|
@@ -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) | ||
|
@@ -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") | ||
|
@@ -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') | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please rename to "alias_max_length"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Addressed in new commit!