Skip to content

Commit

Permalink
[chassis]: Configure and show for platform chassis_modules (sonic-net…
Browse files Browse the repository at this point in the history
…#1145)

* Configure and show for platform chassis_modules

Adding support for below CLI commands
$config plaform chassis_modules admin_down <chassis_module_name>
<instance> <module_type>
$show platform chassis_modules

```
admin@sonic:~$ show chassis-modules status
         Name        Description    Slot    Oper-Status    Admin-Status
-------------  -----------------  ------  -------------  --------------
CONTROL-CARD1           cpm2-ixr      16         Online              up
 FABRIC-CARD1               SFM1      17          Empty              up
 FABRIC-CARD2               SFM2      18          Empty              up
 FABRIC-CARD3               SFM3      19          Empty              up
 FABRIC-CARD4               SFM4      20          Empty              up
 FABRIC-CARD5               SFM5      21         Online              up
 FABRIC-CARD6               SFM6      22          Empty              up
   LINE-CARD1  imm36-400g-qsfpdd       1         Online            down
   LINE-CARD2  imm36-400g-qsfpdd       2         Online              up
   LINE-CARD3          line-card       3          Empty              up
   LINE-CARD4          line-card       4          Empty              up

admin@sonic:~$ show chassis-modules status LINE-CARD1 
         Name        Description    Slot    Oper-Status    Admin-Status
-------------  -----------------  ------  -------------  --------------
  LINE-CARD1  imm36-400g-qsfpdd       1         Online            down
```
  • Loading branch information
mprabhu-nokia authored Nov 11, 2020
1 parent d5eb2f8 commit 40377d3
Show file tree
Hide file tree
Showing 7 changed files with 260 additions and 2 deletions.
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"
}
}

0 comments on commit 40377d3

Please sign in to comment.