Skip to content

Commit

Permalink
Merge branch 'master' into feature/tacacs+
Browse files Browse the repository at this point in the history
  • Loading branch information
Liuqu committed Dec 7, 2017
2 parents c940633 + ea108f3 commit 4aafaa2
Show file tree
Hide file tree
Showing 7 changed files with 331 additions and 75 deletions.
3 changes: 2 additions & 1 deletion acl_loader/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import json
import argparse
import tabulate
from natsort import natsorted

import openconfig_acl
import pyangbind.lib.pybindJSON as pybindJSON
Expand Down Expand Up @@ -384,7 +385,7 @@ def show_table(self, table_name):
if not val["ports"]:
data.append([key, val["type"], "", val["policy_desc"]])
else:
ports = sorted(val["ports"], )
ports = natsorted(val["ports"])
data.append([key, val["type"], ports[0], val["policy_desc"]])

if len(ports) > 1:
Expand Down
88 changes: 88 additions & 0 deletions config/main.py
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,94 @@ def load_minigraph():
_restart_services()
print "Please note setting loaded from minigraph will be lost after system reboot. To preserve setting, run `config save`."

#
# 'vlan' group
#
@cli.group()
@click.pass_context
@click.option('-s', '--redis-unix-socket-path', help='unix socket path for redis connection')
def vlan(ctx, redis_unix_socket_path):
"""VLAN-related configuration tasks"""
kwargs = {}
if redis_unix_socket_path:
kwargs['unix_socket_path'] = redis_unix_socket_path
config_db = ConfigDBConnector(**kwargs)
config_db.connect(wait_for_init=False)
ctx.obj = {'db': config_db}
pass

@vlan.command('add')
@click.argument('vid', metavar='<vid>', required=True, type=int)
@click.pass_context
def add_vlan(ctx, vid):
db = ctx.obj['db']
vlan = 'Vlan{}'.format(vid)
if len(db.get_entry('VLAN', vlan)) != 0:
print "{} already exists".format(vlan)
raise click.Abort
db.set_entry('VLAN', vlan, {'vlanid': vid})

@vlan.command('del')
@click.argument('vid', metavar='<vid>', required=True, type=int)
@click.pass_context
def del_vlan(ctx, vid):
db = ctx.obj['db']
keys = [ (k, v) for k, v in db.get_table('VLAN_MEMBER') if k == 'Vlan{}'.format(vid) ]
for k in keys:
db.set_entry('VLAN_MEMBER', k, None)
db.set_entry('VLAN', 'Vlan{}'.format(vid), None)

@vlan.group('member')
@click.pass_context
def vlan_member(ctx):
pass

@vlan_member.command('add')
@click.argument('vid', metavar='<vid>', required=True, type=int)
@click.argument('interface_name', metavar='<interface_name>', required=True)
@click.option('-u', '--untagged', is_flag=True)
@click.pass_context
def add_vlan_member(ctx, vid, interface_name, untagged):
db = ctx.obj['db']
vlan_name = 'Vlan{}'.format(vid)
vlan = db.get_entry('VLAN', vlan_name)
if len(vlan) == 0:
print "{} doesn't exist".format(vlan_name)
raise click.Abort
members = vlan.get('members', [])
if interface_name in members:
print "{} is already a member of {}".format(interface_name, vlan_name)
raise click.Abort
members.append(interface_name)
vlan['members'] = members
db.set_entry('VLAN', vlan_name, vlan)
db.set_entry('VLAN_MEMBER', (vlan_name, interface_name), {'tagging_mode': "untagged" if untagged else "tagged" })


@vlan_member.command('del')
@click.argument('vid', metavar='<vid>', required=True, type=int)
@click.argument('interface_name', metavar='<interface_name>', required=True)
@click.pass_context
def del_vlan_member(ctx, vid, interface_name):
db = ctx.obj['db']
vlan_name = 'Vlan{}'.format(vid)
vlan = db.get_entry('VLAN', vlan_name)
if len(vlan) == 0:
print "{} doesn't exist".format(vlan_name)
raise click.Abort
members = vlan.get('members', [])
if interface_name not in members:
print "{} is not a member of {}".format(interface_name, vlan_name)
raise click.Abort
members.remove(interface_name)
if len(members) == 0:
del vlan['members']
else:
vlan['members'] = members
db.set_entry('VLAN', vlan_name, vlan)
db.set_entry('VLAN_MEMBER', (vlan_name, interface_name), None)


#
# 'bgp' group
#
Expand Down
58 changes: 0 additions & 58 deletions scripts/interface_stat

This file was deleted.

178 changes: 178 additions & 0 deletions scripts/intfutil
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
#! /usr/bin/python

import swsssdk
import sys
import re
from tabulate import tabulate
from natsort import natsorted



# ========================== Common interface-utils logic ==========================


PORT_STATUS_TABLE_PREFIX = "PORT_TABLE:"
PORT_LANES_STATUS = "lanes"
PORT_ALIAS = "alias"
PORT_OPER_STATUS = "oper_status"
PORT_ADMIN_STATUS = "admin_status"
PORT_SPEED = "speed"
PORT_MTU_STATUS = "mtu"
PORT_DESCRIPTION = "description"


def db_connect():
db = swsssdk.SonicV2Connector(host='127.0.0.1')
if db == None:
return None

db.connect(db.APPL_DB)

return db


def db_keys_get(db, intf_name):

if intf_name == None:
db_keys = db.keys(db.APPL_DB, "PORT_TABLE:*")
elif intf_name.startswith('Ethernet'):
db_keys = db.keys(db.APPL_DB, "PORT_TABLE:%s" % intf_name)
else:
return None

return db_keys


def db_port_status_get(db, intf_name, status_type):
"""
Get the port status
"""

full_table_id = PORT_STATUS_TABLE_PREFIX + intf_name
status = db.get(db.APPL_DB, full_table_id, status_type)
if status is None:
return "N/A"

if status_type == PORT_SPEED and status != "N/A":
status = '{}G'.format(status[:2] if int(status) < 100000 else status[:3])

return status


# ========================== interface-status logic ==========================

header_stat = ['Interface', 'Lanes', 'Speed', 'MTU', 'Alias', 'Oper', 'Admin']

class IntfStatus(object):

def display_intf_status(self, db_keys):
"""
Generate interface-status output
"""

i = {}
table = []
key = []

#
# Iterate through all the keys and append port's associated state to
# the result table.
#
for i in db_keys:
key = re.split(':', i, maxsplit=1)[-1].strip()
if key and key.startswith('Ethernet'):
table.append((key,
db_port_status_get(self.db, key, PORT_LANES_STATUS),
db_port_status_get(self.db, key, PORT_SPEED),
db_port_status_get(self.db, key, PORT_MTU_STATUS),
db_port_status_get(self.db, key, PORT_ALIAS),
db_port_status_get(self.db, key, PORT_OPER_STATUS),
db_port_status_get(self.db, key, PORT_ADMIN_STATUS)))

# Sorting and tabulating the result table.
sorted_table = natsorted(table)
print tabulate(sorted_table, header_stat, tablefmt="simple", stralign='right')


def __init__(self, intf_name):

self.db = db_connect()
if self.db == None:
return

db_keys = db_keys_get(self.db, intf_name)
if db_keys == None:
return

self.display_intf_status(db_keys)


# ========================== interface-description logic ==========================


header_desc = ['Interface', 'Oper', 'Admin', 'Alias', 'Description']


class IntfDescription(object):

def display_intf_description(self, db_keys):
"""
Generate interface-description output
"""

i = {}
table = []
key = []

#
# Iterate through all the keys and append port's associated state to
# the result table.
#
for i in db_keys:
key = re.split(':', i, maxsplit=1)[-1].strip()
if key and key.startswith('Ethernet'):
table.append((key,
db_port_status_get(self.db, key, PORT_OPER_STATUS),
db_port_status_get(self.db, key, PORT_ADMIN_STATUS),
db_port_status_get(self.db, key, PORT_ALIAS),
db_port_status_get(self.db, key, PORT_DESCRIPTION)))

# Sorting and tabulating the result table.
sorted_table = natsorted(table)
print tabulate(sorted_table, header_desc, tablefmt="simple", stralign='right')

def __init__(self, intf_name):

self.db = db_connect()
if self.db == None:
return

db_keys = db_keys_get(self.db, intf_name)
if db_keys == None:
return

self.display_intf_description(db_keys)



def main(args):
if len(args) == 0:
print "No valid arguments provided"
return

command = args[0]
if command != "status" and command != "description":
print "No valid command provided"
return

intf_name = args[1] if len(args) == 2 else None

if command == "status":
interface_stat = IntfStatus(intf_name)
elif command == "description":
interface_desc = IntfDescription(intf_name)

sys.exit(0)

if __name__ == "__main__":
main(sys.argv[1:])
15 changes: 11 additions & 4 deletions setup.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,17 @@
import glob
import sys
from setuptools import setup
import unittest

# For python3 wheel, we currently don't need test
# TODO: build python3 wheel of all the dependencies, and remove conditional test
def get_test_suite():
test_loader = unittest.TestLoader()
test_suite = test_loader.discover('sonic-utilities-tests', pattern='*.py')
return test_suite
if sys.version_info >= (3, 0):
return unittest.TestSuite()
else:
test_loader = unittest.TestLoader()
test_suite = test_loader.discover('sonic-utilities-tests', pattern='*.py')
return test_suite

setup(
name='sonic-utilities',
Expand Down Expand Up @@ -46,7 +52,7 @@ def get_test_suite():
'scripts/fast-reboot-dump.py',
'scripts/fdbshow',
'scripts/generate_dump',
'scripts/interface_stat',
'scripts/intfutil',
'scripts/lldpshow',
'scripts/port2alias',
'scripts/portstat',
Expand Down Expand Up @@ -85,6 +91,7 @@ def get_test_suite():
'Natural Language :: English',
'Operating System :: POSIX :: Linux',
'Programming Language :: Python :: 2.7',
'Programming Language :: Python :: 3.6',
'Topic :: Utilities',
],
keywords='sonic SONiC utilities command line cli CLI',
Expand Down
Loading

0 comments on commit 4aafaa2

Please sign in to comment.