Skip to content

Commit

Permalink
[chassisd] Add script to initialize chassis info in STATE_DB (#183)
Browse files Browse the repository at this point in the history
#### Description
I added a new script `chassis_db_init` that uploads chassis hardware information such as serial number, model number and hardware revision to the STATE_DB under the CHASSIS_INFO table. 

#### Motivation and Context
I made this change in order to expose the chassis hardware information to SONiC user space and allow CLI utilities to access it in order to expose it to the user.
  • Loading branch information
alexrallen authored May 18, 2021
1 parent e60804c commit 1adf47b
Show file tree
Hide file tree
Showing 4 changed files with 153 additions and 0 deletions.
105 changes: 105 additions & 0 deletions sonic-chassisd/scripts/chassis_db_init
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
#!/usr/bin/env python3

"""
chassis_db_init
Chassis information update tool for SONiC
This tool runs one time at the launch of the platform monitor in order to populate STATE_DB with chassis information such as model, serial number, and revision.
"""

try:
import os
import sys

from sonic_py_common import daemon_base, logger

# If unit testing is occurring, mock swsscommon and module_base
if os.getenv("CHASSIS_DB_INIT_UNIT_TESTING") == "1":
from tests import mock_swsscommon as swsscommon
else:
from swsscommon import swsscommon
except ImportError as e:
raise ImportError(str(e) + " - required module not found")

#
# Constants
#

SYSLOG_IDENTIFIER = "chassis_db_init"

CHASSIS_INFO_TABLE = 'CHASSIS_INFO'
CHASSIS_INFO_KEY_TEMPLATE = 'chassis {}'
CHASSIS_INFO_CARD_NUM_FIELD = 'module_num'
CHASSIS_INFO_SERIAL_FIELD = 'serial'
CHASSIS_INFO_MODEL_FIELD = 'model'
CHASSIS_INFO_REV_FIELD = 'revision'

CHASSIS_LOAD_ERROR = 1

NOT_AVAILABLE = 'N/A'

#
# Helper functions =============================================================
#

# try get information from platform API and return a default value if caught NotImplementedError


def try_get(callback, *args, **kwargs):
"""
Handy function to invoke the callback and catch NotImplementedError
:param callback: Callback to be invoked
:param args: Arguments to be passed to callback
:param kwargs: Default return value if exception occur
:return: Default return value if exception occur else return value of the callback
"""
default = kwargs.get('default', NOT_AVAILABLE)
try:
ret = callback(*args)
if ret is None:
ret = default
except NotImplementedError:
ret = default

return ret

#
# Functions
#

def provision_db(platform_chassis, log):
# Init state db connection
state_db = daemon_base.db_connect("STATE_DB")
chassis_table = swsscommon.Table(state_db, CHASSIS_INFO_TABLE)

# Populate DB with chassis hardware info
fvs = swsscommon.FieldValuePairs([
(CHASSIS_INFO_SERIAL_FIELD, try_get(platform_chassis.get_serial)),
(CHASSIS_INFO_MODEL_FIELD, try_get(platform_chassis.get_model)),
(CHASSIS_INFO_REV_FIELD, try_get(platform_chassis.get_revision))
])
chassis_table.set(CHASSIS_INFO_KEY_TEMPLATE.format(1), fvs)
log.log_info("STATE_DB provisioned with chassis info.")

return chassis_table


#
# Main
#

def main():
log = logger.Logger(SYSLOG_IDENTIFIER)
log.log_info("Provisioning Database with Chassis Info...")

# Load platform api class
try:
import sonic_platform.platform
platform_chassis = sonic_platform.platform.Platform().get_chassis()
except Exception as e:
log.log_error("Failed to load chassis due to {}".format(repr(e)))
sys.exit(CHASSIS_LOAD_ERROR)

provision_db(platform_chassis, log)

if __name__ == '__main__':
main()
1 change: 1 addition & 0 deletions sonic-chassisd/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
],
scripts=[
'scripts/chassisd',
'scripts/chassis_db_init'
],
setup_requires=[
'pytest-runner',
Expand Down
9 changes: 9 additions & 0 deletions sonic-chassisd/tests/mock_platform.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,3 +92,12 @@ def get_module_index(self, module_name):

def init_midplane_switch(self):
return True

def get_serial(self):
return "Serial No"

def get_model(self):
return "Model A"

def get_revision(self):
return "Rev C"
38 changes: 38 additions & 0 deletions sonic-chassisd/tests/test_chassis_db_init.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import os
import sys
from imp import load_source

from mock import Mock, MagicMock, patch
from sonic_py_common import daemon_base

from .mock_platform import MockChassis, MockModule
from .mock_module_base import ModuleBase

SYSLOG_IDENTIFIER = 'chassis_db_init_test'
NOT_AVAILABLE = 'N/A'

daemon_base.db_connect = MagicMock()

test_path = os.path.dirname(os.path.abspath(__file__))
modules_path = os.path.dirname(test_path)
scripts_path = os.path.join(modules_path, "scripts")
sys.path.insert(0, modules_path)

os.environ["CHASSIS_DB_INIT_UNIT_TESTING"] = "1"
load_source('chassis_db_init', scripts_path + '/chassis_db_init')
from chassis_db_init import *


def test_provision_db():
chassis = MockChassis()
log = MagicMock()
serial = "Serial No"
model = "Model A"
revision = "Rev C"

chassis_table = provision_db(chassis, log)

fvs = chassis_table.get(CHASSIS_INFO_KEY_TEMPLATE.format(1))
assert serial == fvs[CHASSIS_INFO_SERIAL_FIELD]
assert model == fvs[CHASSIS_INFO_MODEL_FIELD]
assert revision == fvs[CHASSIS_INFO_REV_FIELD]

0 comments on commit 1adf47b

Please sign in to comment.