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

Configure and show for platform chassis_modules #1145

Merged
merged 10 commits into from
Nov 11, 2020
44 changes: 44 additions & 0 deletions config/chassis_modules.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
#!/usr/sbin/env python

import click

import utilities_common.cli as clicommon

#
# 'chassis_modules' group ('config chassis_modules ...')
#
@click.group(cls=clicommon.AliasedGroup)
def chassis_modules():
"""Configure chassis-modules options"""
pass

#
# 'shutdown' subcommand ('config chassis_modules shutdown ...')
#
@chassis_modules.command('shutdown')
@clicommon.pass_db
@click.argument('chassis_module_name', metavar='<module_name>', required=True)
def shutdown_chassis_module(db, chassis_module_name):
"""Chassis-module shutdown of module"""
config_db = db.cfgdb
ctx = click.get_current_context()

if not chassis_module_name.startswith("SUPERVISOR") and \
not chassis_module_name.startswith("LINE-CARD") and \
not chassis_module_name.startswith("FABRIC-CARD"):
ctx.fail("'module_name' has to begin with 'SUPERVISOR', 'LINE-CARD' or 'FABRIC-CARD'")

fvs = {'admin_status': 'down'}
config_db.set_entry('CHASSIS_MODULE', chassis_module_name, fvs)

#
# 'startup' subcommand ('config chassis_modules startup ...')
#
@chassis_modules.command('startup')
@clicommon.pass_db
@click.argument('chassis_module_name', metavar='<module_name>', required=True)
def startup_chassis_module(db, chassis_module_name):
"""Chassis-module startup of module"""
config_db = db.cfgdb

config_db.set_entry('CHASSIS_MODULE', chassis_module_name, None)
3 changes: 2 additions & 1 deletion config/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
import nat
import vlan
from config_mgmt import ConfigMgmtDPB
import chassis_modules

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

Expand Down Expand Up @@ -887,7 +888,7 @@ def config(ctx):
config.add_command(kube.kubernetes)
config.add_command(nat.nat)
config.add_command(vlan.vlan)

config.add_command(chassis_modules.chassis_modules)

@config.command()
@click.option('-y', '--yes', is_flag=True, callback=_abort_if_false,
Expand Down
63 changes: 63 additions & 0 deletions show/chassis_modules.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import click
from natsort import natsorted
from tabulate import tabulate
from swsssdk import SonicV2Connector

import utilities_common.cli as clicommon

CHASSIS_MODULE_INFO_TABLE = 'CHASSIS_MODULE_TABLE'
CHASSIS_MODULE_INFO_KEY_TEMPLATE = 'CHASSIS_MODULE {}'
CHASSIS_MODULE_INFO_DESC_FIELD = 'desc'
CHASSIS_MODULE_INFO_SLOT_FIELD = 'slot'
CHASSIS_MODULE_INFO_OPERSTATUS_FIELD = 'oper_status'
CHASSIS_MODULE_INFO_ADMINSTATUS_FIELD = 'admin_status'

@click.group(cls=clicommon.AliasedGroup)
def chassis_modules():
"""Show chassis-modules information"""
pass

@chassis_modules.command()
@clicommon.pass_db
@click.argument('chassis_module_name', metavar='<module_name>', required=False)
def status(db, chassis_module_name):
"""Show chassis-modules status"""

header = ['Name', 'Description', 'Physical-Slot', 'Oper-Status', 'Admin-Status']
chassis_cfg_table = db.cfgdb.get_table('CHASSIS_MODULE')

state_db = SonicV2Connector(host="127.0.0.1")
state_db.connect(state_db.STATE_DB)

key_pattern = '*'
if chassis_module_name:
key_pattern = '|'+chassis_module_name

keys = state_db.keys(state_db.STATE_DB, CHASSIS_MODULE_INFO_TABLE + key_pattern)
if not keys:
print('Key {} not found in {} table'.format(key_pattern, CHASSIS_MODULE_INFO_TABLE))
return

table = []
for key in natsorted(keys):
key_list = key.split('|')
if len(key_list) != 2: # error data in DB, log it and ignore
print('Warn: Invalid Key {} in {} table'.format(key, CHASSIS_MODULE_INFO_TABLE))
continue

data_dict = state_db.get_all(state_db.STATE_DB, key)
desc = data_dict[CHASSIS_MODULE_INFO_DESC_FIELD]
slot = data_dict[CHASSIS_MODULE_INFO_SLOT_FIELD]
oper_status = data_dict[CHASSIS_MODULE_INFO_OPERSTATUS_FIELD]

admin_status = 'up'
config_data = chassis_cfg_table.get(key_list[1])
if config_data is not None:
admin_status = config_data.get(CHASSIS_MODULE_INFO_ADMINSTATUS_FIELD)

table.append((key_list[1], desc, slot, oper_status, admin_status))

if table:
click.echo(tabulate(table, header, tablefmt='simple', stralign='right'))
else:
click.echo('No data available in CHASSIS_MODULE_TABLE\n')
3 changes: 2 additions & 1 deletion show/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import vlan
import system_health
import fgnhg
import chassis_modules

from sonic_py_common import device_info, multi_asic
from swsssdk import ConfigDBConnector
Expand Down Expand Up @@ -133,6 +134,7 @@ def cli(ctx):
cli.add_command(vlan.vlan)
cli.add_command(system_health.system_health)
cli.add_command(fgnhg.fgnhg)
cli.add_command(chassis_modules.chassis_modules)

#
# 'vrf' command ("show vrf")
Expand Down Expand Up @@ -1780,7 +1782,6 @@ def counts(group, counter_type, verbose):

run_command(cmd, display_cmd=verbose)


#
# 'ecn' command ("show ecn")
#
Expand Down
118 changes: 118 additions & 0 deletions tests/chassis_modules_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
import sys
import os
from click.testing import CliRunner

test_path = os.path.dirname(os.path.abspath(__file__))
modules_path = os.path.dirname(test_path)
sys.path.insert(0, modules_path)

import show.main as show
import config.main as config
import tests.mock_tables.dbconnector
from utilities_common.db import Db

show_linecard0_shutdown_output="""\
LINE-CARD0 line-card 1 Empty down
"""

show_linecard0_startup_output="""\
LINE-CARD0 line-card 1 Empty up
"""
header_lines = 2
warning_lines = 0

class TestChassisModules(object):
@classmethod
def setup_class(cls):
print("SETUP")
os.environ["UTILITIES_UNIT_TESTING"] = "1"

def test_show_all_count_lines(self):
runner = CliRunner()
result = runner.invoke(show.cli.commands["chassis-modules"].commands["status"], [])
print(result.output)
result_lines = result.output.strip('\n').split('\n')
modules = ["FABRIC-CARD0", "FABRIC-CARD1", "LINE-CARD0", "LINE-CARD1", "SUPERVISOR0"]
for i, module in enumerate(modules):
assert module in result_lines[i + warning_lines + header_lines]
assert len(result_lines) == warning_lines + header_lines + len(modules)

def test_show_single_count_lines(self):
runner = CliRunner()
result = runner.invoke(show.cli.commands["chassis-modules"].commands["status"], ["LINE-CARD0"])
print(result.output)
result_lines = result.output.strip('\n').split('\n')
modules = ["LINE-CARD0"]
for i, module in enumerate(modules):
assert module in result_lines[i+header_lines]
assert len(result_lines) == header_lines + len(modules)

def test_show_module_down(self):
runner = CliRunner()
result = runner.invoke(show.cli.commands["chassis-modules"].commands["status"], ["LINE-CARD1"])
result_lines = result.output.strip('\n').split('\n')
assert result.exit_code == 0
result_out = (result_lines[header_lines]).split()
assert result_out[4] == 'down'

def test_show_incorrect_command(self):
runner = CliRunner()
result = runner.invoke(show.cli.commands["chassis-modules"], [])
print(result.output)
print(result.exit_code)
assert result.exit_code == 0

def test_show_incorrect_module(self):
runner = CliRunner()
result = runner.invoke(show.cli.commands["chassis-modules"].commands["status"], ["TEST-CARD1"])
print(result.output)
print(result.exit_code)
assert result.exit_code == 0

def test_config_shutdown_module(self):
runner = CliRunner()
db = Db()
result = runner.invoke(config.config.commands["chassis-modules"].commands["shutdown"], ["LINE-CARD0"], obj=db)
print(result.exit_code)
print(result.output)
assert result.exit_code == 0

result = runner.invoke(show.cli.commands["chassis-modules"].commands["status"], ["LINE-CARD0"], obj=db)
print(result.exit_code)
print(result.output)
result_lines = result.output.strip('\n').split('\n')
assert result.exit_code == 0
header_lines = 2
result_out = " ".join((result_lines[header_lines]).split())
assert result_out.strip('\n') == show_linecard0_shutdown_output.strip('\n')
#db.cfgdb.set_entry("CHASSIS_MODULE", "LINE-CARD0", { "admin_status" : "down" })
#db.get_data("CHASSIS_MODULE", "LINE-CARD0")

def test_config_startup_module(self):
runner = CliRunner()
db = Db()
result = runner.invoke(config.config.commands["chassis-modules"].commands["startup"], ["LINE-CARD0"], obj=db)
print(result.exit_code)
print(result.output)
assert result.exit_code == 0

result = runner.invoke(show.cli.commands["chassis-modules"].commands["status"], ["LINE-CARD0"], obj=db)
print(result.exit_code)
print(result.output)
result_lines = result.output.strip('\n').split('\n')
assert result.exit_code == 0
result_out = " ".join((result_lines[header_lines]).split())
assert result_out.strip('\n') == show_linecard0_startup_output.strip('\n')

def test_config_incorrect_module(self):
runner = CliRunner()
db = Db()
result = runner.invoke(config.config.commands["chassis-modules"].commands["shutdown"], ["TEST-CARD0"], obj=db)
print(result.exit_code)
print(result.output)
assert result.exit_code != 0

@classmethod
def teardown_class(cls):
print("TEARDOWN")
os.environ["UTILITIES_UNIT_TESTING"] = "0"
3 changes: 3 additions & 0 deletions tests/mock_tables/config_db.json
Original file line number Diff line number Diff line change
Expand Up @@ -1299,5 +1299,8 @@
"acl_entry_high_threshold": "85",
"fdb_entry_low_threshold": "70",
"ipv6_nexthop_high_threshold": "85"
},
"CHASSIS_MODULE|LINE-CARD1": {
"admin_status": "down"
}
}
28 changes: 28 additions & 0 deletions tests/mock_tables/state_db.json
Original file line number Diff line number Diff line change
Expand Up @@ -272,5 +272,33 @@
"29" : "200.200.200.5@Vlan1000",
"30" : "200.200.200.5@Vlan1000",
"31" : "200.200.200.5@Vlan1000"
},
"CHASSIS_TABLE|CHASSIS 1": {
"module_num": "5"
},
"CHASSIS_MODULE_TABLE|SUPERVISOR0": {
"desc": "supervisor-card",
"oper_status": "Online",
"slot": "16"
},
"CHASSIS_MODULE_TABLE|LINE-CARD0": {
"desc": "line-card",
"oper_status": "Empty",
"slot": "1"
},
"CHASSIS_MODULE_TABLE|LINE-CARD1": {
"desc": "line-card",
"oper_status": "Online",
"slot": "2"
},
"CHASSIS_MODULE_TABLE|FABRIC-CARD0": {
"desc": "fabric-card",
"oper_status": "Online",
"slot": "17"
},
"CHASSIS_MODULE_TABLE|FABRIC-CARD1": {
"desc": "fabric-card",
"oper_status": "Offline",
"slot": "18"
}
}