Skip to content

Commit

Permalink
Enhancement of 'show' commands and addition of 'debug', and 'undebug'… (
Browse files Browse the repository at this point in the history
sonic-net#113)

- added script to get interface status.
- added few subcommands under "show interfaces" command.
- enhanced "show process" to get all processes sorted by CPU & memory.
- added "show services" command to get all the running process from all the dockers.
- added "show vlan" command.
- enhanced multiple subcommands under
- added debug', and 'undebug' CLI utilities.
  • Loading branch information
samaity authored and jleveque committed Oct 2, 2017
1 parent 206aabe commit 63f05ad
Show file tree
Hide file tree
Showing 10 changed files with 469 additions and 23 deletions.
8 changes: 8 additions & 0 deletions data/etc/bash_completion.d/debug
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
_debug_completion() {
COMPREPLY=( $( env COMP_WORDS="${COMP_WORDS[*]}" \
COMP_CWORD=$COMP_CWORD \
_DEBUG_COMPLETE=complete $1 ) )
return 0
}

complete -F _debug_completion -o default debug;
8 changes: 8 additions & 0 deletions data/etc/bash_completion.d/undebug
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
_undebug_completion() {
COMPREPLY=( $( env COMP_WORDS="${COMP_WORDS[*]}" \
COMP_CWORD=$COMP_CWORD \
_UNDEBUG_COMPLETE=complete $1 ) )
return 0
}

complete -F _undebug_completion -o default undebug;
Empty file added debug/__init__.py
Empty file.
5 changes: 5 additions & 0 deletions debug/aliases.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
[aliases]
running-configuration=runningconfiguration
running-config=runningconfiguration
startup-configuration=startupconfiguration
startup-config=startupconfiguration
132 changes: 132 additions & 0 deletions debug/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
#! /usr/bin/python -u
# date: 07/12/17

import click
import os
import subprocess
from click_default_group import DefaultGroup

try:
import ConfigParser as configparser
except ImportError:
import configparser


# This is from the aliases example:
# https://github.com/pallets/click/blob/57c6f09611fc47ca80db0bd010f05998b3c0aa95/examples/aliases/aliases.py
class Config(object):
"""Object to hold CLI config"""

def __init__(self):
self.path = os.getcwd()
self.aliases = {}

def read_config(self, filename):
parser = configparser.RawConfigParser()
parser.read([filename])
try:
self.aliases.update(parser.items('aliases'))
except configparser.NoSectionError:
pass


# Global Config object
_config = None


# This aliased group has been modified from click examples to inherit from DefaultGroup instead of click.Group.
# DefaultFroup is a superclass of click.Group which calls a default subcommand instead of showing
# a help message if no subcommand is passed
class AliasedGroup(DefaultGroup):
"""This subclass of a DefaultGroup supports looking up aliases in a config
file and with a bit of magic.
"""

def get_command(self, ctx, cmd_name):
global _config

# If we haven't instantiated our global config, do it now and load current config
if _config is None:
_config = Config()

# Load our config file
cfg_file = os.path.join(os.path.dirname(__file__), 'aliases.ini')
_config.read_config(cfg_file)

# Try to get builtin commands as normal
rv = click.Group.get_command(self, ctx, cmd_name)
if rv is not None:
return rv

# No builtin found. Look up an explicit command alias in the config
if cmd_name in _config.aliases:
actual_cmd = _config.aliases[cmd_name]
return click.Group.get_command(self, ctx, actual_cmd)

# Alternative option: if we did not find an explicit alias we
# allow automatic abbreviation of the command. "status" for
# instance will match "st". We only allow that however if
# there is only one command.
matches = [x for x in self.list_commands(ctx)
if x.lower().startswith(cmd_name.lower())]
if not matches:
# No command name matched. Issue Default command.
ctx.arg0 = cmd_name
cmd_name = self.default_cmd_name
return DefaultGroup.get_command(self, ctx, cmd_name)
elif len(matches) == 1:
return DefaultGroup.get_command(self, ctx, matches[0])
ctx.fail('Too many matches: %s' % ', '.join(sorted(matches)))


def run_command(command, pager=False):
if pager is True:
click.echo(click.style("Command: ", fg='cyan') + click.style(command, fg='green'))
p = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE)
click.echo_via_pager(p.stdout.read())
else:
click.echo(click.style("Command: ", fg='cyan') + click.style(command, fg='green'))
p = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE)
click.echo(p.stdout.read())


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


#
# 'cli' group (root group) ###
#

@click.group(cls=AliasedGroup, context_settings=CONTEXT_SETTINGS)
def cli():
"""SONiC command line - 'debug' command"""
pass

#
# 'bgp' group ###
#

@cli.group(cls=AliasedGroup, default_if_no_args=True)
def bgp():
"""debug bgp on """
pass

@bgp.command(default=True)
def default():
command = 'sudo vtysh -c "debug bgp"'
run_command(command)

@bgp.command()
def events():
"""debug bgp events on """
command = 'sudo vtysh -c "debug bgp events"'
run_command(command)

@bgp.command()
def updates():
"""debug bgp events on """
command = 'sudo vtysh -c "debug bgp updates"'
run_command(command)

if __name__ == '__main__':
cli()
54 changes: 54 additions & 0 deletions scripts/interface_stat
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
#!/usr/bin/env python
import swsssdk
import sys
import re
from tabulate import tabulate
header = ['Iface', 'LANES', 'ALIAS', 'OPER', 'ADMIN', 'MTU']


PORT_STATUS_TABLE_PREFIX = "PORT_TABLE:"
PORT_LANES_STATUS_FIELD = "lanes"
PORT_ALIAS_STATUS_FIELD = "alias"
PORT_OPER_STATUS_FIELD = "oper_status"
PORT_ADMIN_STATUS_FIELD = "admin_status"
PORT_MTU_STATUS_FIELD = "mtu"

class Intstat(object):
table = []

def get_port_status(self, port_name, status_type):
"""
Get the port status
"""
full_table_id = PORT_STATUS_TABLE_PREFIX + port_name
status = self.db.get(self.db.APPL_DB, full_table_id, status_type)
if status is None:
return "N/A"
else:
return status

def __init__(self):
self.db = swsssdk.SonicV2Connector(host='127.0.0.1')
self.db.connect(self.db.APPL_DB)
a = self.db.keys(self.db.APPL_DB)
#print(a)
tables = self.db.keys(self.db.APPL_DB, "PORT_TABLE:*")
i = {}
table = []
key = []
#print tabulate(header, tablefmt='simple', stralign='right')
for i in tables:
key = re.split(':', i, maxsplit=1)[-1].strip()
if key:
table.append((key, self.get_port_status(key, PORT_LANES_STATUS_FIELD), self.get_port_status(key, PORT_ALIAS_STATUS_FIELD), self.get_port_status(key, PORT_OPER_STATUS_FIELD), self.get_port_status(key, PORT_ADMIN_STATUS_FIELD), self.get_port_status(key, PORT_MTU_STATUS_FIELD)))
print tabulate(table, header, tablefmt="simple", stralign='right')


def main():
interface_stat = Intstat()

# Now decide what information to display
sys.exit(0)

if __name__ == "__main__":
main()
Loading

0 comments on commit 63f05ad

Please sign in to comment.