diff --git a/sonic-storagemond/pytest.ini b/sonic-storagemond/pytest.ini deleted file mode 100644 index d90ee9ed9..000000000 --- a/sonic-storagemond/pytest.ini +++ /dev/null @@ -1,2 +0,0 @@ -[pytest] -addopts = --cov=scripts --cov-report html --cov-report term --cov-report xml --junitxml=test-results.xml -vv diff --git a/sonic-storagemond/scripts/storagemond b/sonic-storagemond/scripts/storagemond deleted file mode 100644 index 29e9f4f41..000000000 --- a/sonic-storagemond/scripts/storagemond +++ /dev/null @@ -1,189 +0,0 @@ -#!/usr/bin/env python3 - -""" - storagemond - Strage Monitoring device monitoring daemon for SONiC -""" - -import os -import signal -import sys -import threading -import subprocess -import shutil - -from sonic_py_common import daemon_base, device_info, logger -from swsscommon import swsscommon -from sonic_platform_base.sonic_storage.storage_devices import StorageDevices - -# -# Constants ==================================================================== -# - -# TODO: Once we no longer support Python 2, we can eliminate this and get the -# name using the 'name' field (e.g., `signal.SIGINT.name`) starting with Python 3.5 -SIGNALS_TO_NAMES_DICT = dict((getattr(signal, n), n) - for n in dir(signal) if n.startswith('SIG') and '_' not in n) - -SYSLOG_IDENTIFIER = "storagemond" - -STORAGE_DEVICE_TABLE_NAME = "STORAGE_INFO" - -STORMOND_MAIN_THREAD_SLEEP_SECS = 3600 #one hour - -STORAGEUTIL_LOAD_ERROR = 127 - -log = logger.Logger(SYSLOG_IDENTIFIER) - -exit_code = 0 - -# -# Daemon ======================================================================= -# - - -class DaemonStorage(daemon_base.DaemonBase): - def __init__(self, log_identifier): - super(DaemonStorage, self).__init__(log_identifier) - - self.timeout = STORMOND_MAIN_THREAD_SLEEP_SECS - self.stop_event = threading.Event() - self.state_db = None - self.device_table = None - self.storage = StorageDevices(log_identifier) - - self.static_fields = ["device_model", "serial"] - self.dynamic_fields = ["firmware", "health", "temperature", "fs_io_reads", "fs_io_writes", "disk_io_reads", "disk_io_writes", "reserved_blocks"] - - self.read_static_fields = dict((disk, False) for disk in self.storage.devices) - self.updated_static_fields_statedb = dict((disk, False) for disk in self.storage.devices) - - # Connect to STATE_DB and create Storage device table - self.state_db = daemon_base.db_connect("STATE_DB") - self.device_table = swsscommon.Table(self.state_db, STORAGE_DEVICE_TABLE_NAME) - - def __del__(self): - if self.device_table: - table_keys = self.device_table.getKeys() - for tk in table_keys: - self.device_table._del(tk) - - - # Update the Storage device info to State DB - def update_storage_info_status_db(self, disk_device, disk_fields, kvp_dict): - - for field in disk_fields: - fvp = swsscommon.FieldValuePairs([(field, str(kvp_dict[field]))]) - self.device_table.set(disk_device, fvp) - - - # Get Static attributes and update the State DB, once - def get_static_fields(self): - - # Get relevant information about each Storage Device on the switch - for storage_device in self.storage.devices: - try: - if self.storage.devices[storage_device] is None: - self.log_warning("{} does not have an instantiated object. Static Information cannot be gathered.".format(storage_device)) - continue - - if self.read_static_fields[storage_device] and self.updated_static_fields_statedb[storage_device]: - self.log_info("Static information from {} has already been parsed and updated to StateDB.".format(storage_device)) - continue - - static_kvp_dict = dict((field, "") for field in self.static_fields) - - static_kvp_dict["device_model"] = self.storage.devices[storage_device].get_model() - static_kvp_dict["serial"] = self.storage.devices[storage_device].get_serial() - - self.log_info("Storage Device: {}, Device Model: {}, Serial: {}".format(storage_device, static_kvp_dict["device_model"], static_kvp_dict["serial"])) - self.read_static_fields[storage_device] = True - - # update Storage Device Status to DB - self.update_storage_info_status_db(storage_device, self.static_fields, static_kvp_dict) - self.updated_static_fields_statedb[storage_device] = True - - except Exception as ex: - self.log_warning("get_static_fields() failed with: {}".format(str(ex))) - - # Get Dynamic attributes and update the State DB - def get_dynamic_fields(self): - - # Get relevant information about each storage disk on the device - for storage_device in self.storage.devices: - try: - if self.storage.devices[storage_device] is None: - self.log_warning("{} does not have an instantiated object. Dynamic Information cannot be gathered.".format(storage_device)) - continue - - dynamic_kvp_dict = dict((field, "") for field in self.dynamic_fields) - - dynamic_kvp_dict["firmware"] = self.storage.devices[storage_device].get_firmware() - dynamic_kvp_dict["health"] = self.storage.devices[storage_device].get_health() - dynamic_kvp_dict["temperature"] = self.storage.devices[storage_device].get_temperature() - dynamic_kvp_dict["fs_io_reads"] = self.storage.devices[storage_device].get_fs_io_reads() - dynamic_kvp_dict["fs_io_writes"] = self.storage.devices[storage_device].get_fs_io_writes() - dynamic_kvp_dict["disk_io_reads"] = self.storage.devices[storage_device].get_disk_io_reads() - dynamic_kvp_dict["disk_io_writes"] = self.storage.devices[storage_device].get_disk_io_writes() - dynamic_kvp_dict["reserved_blocks"] = self.storage.devices[storage_device].get_reserved_blocks() - - self.log_info("Storage Device: {}, Firmware: {}, health: {}%, Temp: {}C, FS IO Reads: {}, FS IO Writes: {}".format(\ - storage_device, dynamic_kvp_dict["firmware"], dynamic_kvp_dict["health"], dynamic_kvp_dict["temperature"], dynamic_kvp_dict["fs_io_reads"],dynamic_kvp_dict["fs_io_writes"],)) - self.log_info("Disk IO Reads: {}, Disk IO Writes: {}, Reserved Blocks: {}".format(dynamic_kvp_dict["disk_io_reads"], dynamic_kvp_dict["disk_io_writes"], \ - dynamic_kvp_dict["reserved_blocks"])) - - # update Storage Device Status to DB - self.update_storage_info_status_db(storage_device, self.dynamic_fields, dynamic_kvp_dict) - - except Exception as ex: - self.log_warning("get_dynamic_fields() failed with: {}".format(str(ex))) - - - # Override signal handler from DaemonBase - def signal_handler(self, sig, frame): - FATAL_SIGNALS = [signal.SIGINT, signal.SIGTERM] - NONFATAL_SIGNALS = [signal.SIGHUP] - - global exit_code - - if sig in FATAL_SIGNALS: - self.log_info("Caught signal '{}' - exiting...".format(SIGNALS_TO_NAMES_DICT[sig])) - exit_code = 128 + sig # Make sure we exit with a non-zero code so that supervisor will try to restart us - self.stop_event.set() - elif sig in NONFATAL_SIGNALS: - self.log_info("Caught signal '{}' - ignoring...".format(SIGNALS_TO_NAMES_DICT[sig])) - else: - self.log_warning("Caught unhandled signal '{}' - ignoring...".format(SIGNALS_TO_NAMES_DICT[sig])) - - # Main daemon logic - def run(self): - if self.stop_event.wait(self.timeout): - # We received a fatal signal - return False - - # Read and update Static Fields to the StateDB once - self.get_static_fields() - - # Repeatedly read and update Dynamic Fields to the StateDB - self.get_dynamic_fields() - - return True -# -# Main ========================================================================= -# - - -def main(): - stormon = DaemonStorage(SYSLOG_IDENTIFIER) - - stormon.log_info("Starting Storage Monitoring Daemon") - - while stormon.run(): - pass - - stormon.log_info("Shutting down Storage Monitoring Daemon") - - return exit_code - -if __name__ == '__main__': - sys.exit(main()) diff --git a/sonic-storagemond/setup.cfg b/sonic-storagemond/setup.cfg deleted file mode 100644 index b7e478982..000000000 --- a/sonic-storagemond/setup.cfg +++ /dev/null @@ -1,2 +0,0 @@ -[aliases] -test=pytest diff --git a/sonic-storagemond/setup.py b/sonic-storagemond/setup.py deleted file mode 100644 index a4eb129dc..000000000 --- a/sonic-storagemond/setup.py +++ /dev/null @@ -1,43 +0,0 @@ -from setuptools import setup - -setup( - name='sonic-stormond', - version='1.0', - description='Storage Device status daemon for SONiC', - license='Apache 2.0', - author='SONiC Team', - author_email='linuxnetdev@microsoft.com', - url='https://github.com/sonic-net/sonic-platform-daemons', - maintainer='Ashwin Srinivasan', - maintainer_email='assrinivasan@microsoft.com', - scripts=[ - 'scripts/storagemond', - ], - setup_requires=[ - 'pytest-runner', - 'wheel' - ], - install_requires=[ - 'enum34; python_version < "3.4"', - 'sonic-py-common', - ], - tests_require=[ - 'mock>=2.0.0; python_version < "3.3"', - 'pytest', - 'pytest-cov', - ], - classifiers=[ - 'Development Status :: 4 - Beta', - 'Environment :: No Input/Output (Daemon)', - 'Intended Audience :: Developers', - 'Intended Audience :: Information Technology', - 'Intended Audience :: System Administrators', - 'License :: OSI Approved :: Apache Software License', - 'Natural Language :: English', - 'Operating System :: POSIX :: Linux', - 'Programming Language :: Python :: 2.7', - 'Topic :: System :: Hardware', - ], - keywords='sonic SONiC ssd Ssd SSD ssdmond storage stormond storagemond', - test_suite='setup.get_test_suite' -) diff --git a/sonic-storagemond/tests/__init__.py b/sonic-storagemond/tests/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/sonic-storagemond/tests/mock_platform.py b/sonic-storagemond/tests/mock_platform.py deleted file mode 100644 index a5b3070bf..000000000 --- a/sonic-storagemond/tests/mock_platform.py +++ /dev/null @@ -1,15 +0,0 @@ - -""" - Mock implementation of sonic_platform package for unit testing -""" - -# TODO: Clean this up once we no longer need to support Python 2 -import sys -if sys.version_info.major == 3: - from unittest import mock -else: - import mock - -class MockStorageDevice(): - def __init__(self): - super(MockStorageDevice, self).__init__() \ No newline at end of file diff --git a/sonic-storagemond/tests/mocked_libs/sonic_platform/__init__.py b/sonic-storagemond/tests/mocked_libs/sonic_platform/__init__.py deleted file mode 100644 index 136bb0dcc..000000000 --- a/sonic-storagemond/tests/mocked_libs/sonic_platform/__init__.py +++ /dev/null @@ -1,6 +0,0 @@ -""" - Mock implementation of sonic_platform package for unit testing -""" - -from . import ssd - diff --git a/sonic-storagemond/tests/mocked_libs/sonic_platform/ssd.py b/sonic-storagemond/tests/mocked_libs/sonic_platform/ssd.py deleted file mode 100644 index 572f190ef..000000000 --- a/sonic-storagemond/tests/mocked_libs/sonic_platform/ssd.py +++ /dev/null @@ -1,13 +0,0 @@ -""" - Mock implementation of sonic_platform package for unit testing -""" - -from sonic_platform_base.ssd_base import SsdBase - - -class Ssd(SsdBase): - def __init__(self): - self.platform_ssdutil = "/tmp/Ssd" - - def __str__(self): - return self.platform_ssdutil diff --git a/sonic-storagemond/tests/mocked_libs/sonic_platform_base/__init__.py b/sonic-storagemond/tests/mocked_libs/sonic_platform_base/__init__.py deleted file mode 100644 index 8b1378917..000000000 --- a/sonic-storagemond/tests/mocked_libs/sonic_platform_base/__init__.py +++ /dev/null @@ -1 +0,0 @@ - diff --git a/sonic-storagemond/tests/mocked_libs/sonic_platform_base/sonic_storage/__init__.py b/sonic-storagemond/tests/mocked_libs/sonic_platform_base/sonic_storage/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/sonic-storagemond/tests/mocked_libs/sonic_platform_base/sonic_storage/ssd.py b/sonic-storagemond/tests/mocked_libs/sonic_platform_base/sonic_storage/ssd.py deleted file mode 100644 index a157aab81..000000000 --- a/sonic-storagemond/tests/mocked_libs/sonic_platform_base/sonic_storage/ssd.py +++ /dev/null @@ -1,127 +0,0 @@ -# -# ssd_generic.py -# -# Generic implementation of the SSD health API -# SSD models supported: -# - InnoDisk -# - StorFly -# - Virtium - -try: - import re - import subprocess - from .storage_base import StorageBase -except ImportError as e: - raise ImportError (str(e) + "- required module not found") - -SMARTCTL = "smartctl {} -a" -INNODISK = "iSmart -d {}" -VIRTIUM = "SmartCmd -m {}" - -NOT_AVAILABLE = "N/A" - -# Set Vendor Specific IDs -INNODISK_HEALTH_ID = 169 -INNODISK_TEMPERATURE_ID = 194 -SWISSBIT_HEALTH_ID = 248 -SWISSBIT_TEMPERATURE_ID = 194 - -class SsdUtil(StorageBase): - """ - Generic implementation of the SSD health API - """ - - def __init__(self, diskdev): - model = 'InnoDisk Corp. - mSATA 3IE3' - serial = 'BCA11712190600251' - firmware = 'S16425cG' - temperature = 32.3 - health = 91.6 - ssd_info = NOT_AVAILABLE - vendor_ssd_info = NOT_AVAILABLE - io_reads = 20000 - io_writes = 20005 - reserved_blocks = 3746218 - - def get_health(self): - """ - Retrieves current disk health in percentages - - Returns: - A float number of current ssd health - e.g. 83.5 - """ - return self.health - - def get_temperature(self): - """ - Retrieves current disk temperature in Celsius - - Returns: - A float number of current temperature in Celsius - e.g. 40.1 - """ - return self.temperature - - def get_model(self): - """ - Retrieves model for the given disk device - - Returns: - A string holding disk model as provided by the manufacturer - """ - return self.model - - def get_firmware(self): - """ - Retrieves firmware version for the given disk device - - Returns: - A string holding disk firmware version as provided by the manufacturer - """ - return self.firmware - - def get_serial(self): - """ - Retrieves serial number for the given disk device - - Returns: - A string holding disk serial number as provided by the manufacturer - """ - return self.serial - - def get_vendor_output(self): - """ - Retrieves vendor specific data for the given disk device - - Returns: - A string holding some vendor specific disk information - """ - return self.vendor_ssd_info - - def get_io_writes(self): - """ - Retrieves the total number of Input/Output (I/O) writes done on an SSD - - Returns: - An integer value of the total number of I/O writes - """ - return self.io_writes - - def get_io_reads(self): - """ - Retrieves the total number of Input/Output (I/O) writes done on an SSD - - Returns: - An integer value of the total number of I/O writes - """ - return self.io_reads - - def get_reserves_blocks(self): - """ - Retrieves the total number of reserved blocks in an SSD - - Returns: - An integer value of the total number of reserved blocks - """ - return self.reserved_blocks diff --git a/sonic-storagemond/tests/mocked_libs/sonic_platform_base/sonic_storage/storage_base.py b/sonic-storagemond/tests/mocked_libs/sonic_platform_base/sonic_storage/storage_base.py deleted file mode 100644 index 380a7a54a..000000000 --- a/sonic-storagemond/tests/mocked_libs/sonic_platform_base/sonic_storage/storage_base.py +++ /dev/null @@ -1,122 +0,0 @@ -# -# storage_base.py -# -# Abstract base class for implementing platform-specific -# Storage information gathering functionality for SONiC -# - -try: - import abc -except ImportError as e: - raise ImportError(str(e) + " - required module not found") - -# -# storage_base.py -# -# Base class for implementing common Storage Device health features -# - - -class SsdBase(object): - """ - Base class for interfacing with a SSD - """ - def __init__(self, diskdev): - """ - Constructor - - Args: - diskdev: Linux device name to get parameters for - """ - pass - - @abc.abstractmethod - def get_health(self): - """ - Retrieves current disk health in percentages - - Returns: - A float number of current ssd health - e.g. 83.5 - """ - return 91.6 - - @abc.abstractmethod - def get_temperature(self): - """ - Retrieves current disk temperature in Celsius - - Returns: - A float number of current temperature in Celsius - e.g. 40.1 - """ - return 32.3 - - @abc.abstractmethod - def get_model(self): - """ - Retrieves model for the given disk device - - Returns: - A string holding disk model as provided by the manufacturer - """ - return '' - - @abc.abstractmethod - def get_firmware(self): - """ - Retrieves firmware version for the given disk device - - Returns: - A string holding disk firmware version as provided by the manufacturer - """ - return '' - - @abc.abstractmethod - def get_serial(self): - """ - Retrieves serial number for the given disk device - - Returns: - A string holding disk serial number as provided by the manufacturer - """ - return '' - - @abc.abstractmethod - def get_vendor_output(self): - """ - Retrieves vendor specific data for the given disk device - - Returns: - A string holding some vendor specific disk information - """ - return '' - - def get_io_reads(self): - """ - Retrieves the total number of Input/Output (I/O) reads done on an SSD - - Returns: - An integer value of the total number of I/O reads - """ - return 20000 - - @abc.abstractmethod - def get_io_writes(self): - """ - Retrieves the total number of Input/Output (I/O) writes done on an SSD - - Returns: - An integer value of the total number of I/O writes - """ - return 20005 - - @abc.abstractmethod - def get_reserves_blocks(self): - """ - Retrieves the total number of reserved blocks in an SSD - - Returns: - An integer value of the total number of reserved blocks - """ - return 3746218 \ No newline at end of file diff --git a/sonic-storagemond/tests/mocked_libs/swsscommon/__init__.py b/sonic-storagemond/tests/mocked_libs/swsscommon/__init__.py deleted file mode 100644 index 012af621e..000000000 --- a/sonic-storagemond/tests/mocked_libs/swsscommon/__init__.py +++ /dev/null @@ -1,5 +0,0 @@ -''' - Mock implementation of swsscommon package for unit testing -''' - -from . import swsscommon diff --git a/sonic-storagemond/tests/mocked_libs/swsscommon/swsscommon.py b/sonic-storagemond/tests/mocked_libs/swsscommon/swsscommon.py deleted file mode 100644 index ddb3cd686..000000000 --- a/sonic-storagemond/tests/mocked_libs/swsscommon/swsscommon.py +++ /dev/null @@ -1,66 +0,0 @@ -''' - Mock implementation of swsscommon package for unit testing -''' - -STATE_DB = '' - - -class Table: - def __init__(self, db, table_name): - self.table_name = table_name - self.mock_dict = {} - - def _del(self, key): - del self.mock_dict[key] - pass - - def set(self, key, fvs): - self.mock_dict[key] = fvs.fv_dict - pass - - def get(self, key): - if key in self.mock_dict: - return self.mock_dict[key] - return None - - def get_size(self): - return (len(self.mock_dict)) - - def getKeys(self): - return list(self.mock_dict.keys()) - - -class FieldValuePairs: - fv_dict = {} - - def __init__(self, tuple_list): - if isinstance(tuple_list, list) and isinstance(tuple_list[0], tuple): - self.fv_dict = dict(tuple_list) - - def __setitem__(self, key, kv_tuple): - self.fv_dict[kv_tuple[0]] = kv_tuple[1] - - def __getitem__(self, key): - return self.fv_dict[key] - - def __eq__(self, other): - if not isinstance(other, FieldValuePairs): - # don't attempt to compare against unrelated types - return NotImplemented - - return self.fv_dict == other.fv_dict - - def __repr__(self): - return repr(self.fv_dict) - - def __str__(self): - return repr(self.fv_dict) - -class ConfigDBConnector: - pass - -class SonicDBConfig: - pass - -class SonicV2Connector: - pass diff --git a/sonic-storagemond/tests/test_DaemonStorage.py b/sonic-storagemond/tests/test_DaemonStorage.py deleted file mode 100644 index b64fd536f..000000000 --- a/sonic-storagemond/tests/test_DaemonStorage.py +++ /dev/null @@ -1,40 +0,0 @@ -import datetime -import os -import sys -from imp import load_source # Replace with importlib once we no longer need to support Python 2 - -import pytest - -# TODO: Clean this up once we no longer need to support Python 2 -if sys.version_info.major == 3: - from unittest import mock -else: - import mock - -from .mock_platform import MockStorageDevice - -SYSLOG_IDENTIFIER = 'storage_daemon_test' -NOT_AVAILABLE = 'N/A' - - -tests_path = os.path.dirname(os.path.abspath(__file__)) - -# Add mocked_libs path so that the file under test can load mocked modules from there -mocked_libs_path = os.path.join(tests_path, "mocked_libs") -sys.path.insert(0, mocked_libs_path) - -from sonic_py_common import daemon_base -daemon_base.db_connect = mock.MagicMock() - -# Add path to the file under test so that we can load it -modules_path = os.path.dirname(tests_path) -scripts_path = os.path.join(modules_path, "scripts") -sys.path.insert(0, modules_path) -load_source('storagemond', os.path.join(scripts_path, 'storagemond')) -import storagemond - - -class TestDaemonStorage(object): - """ - Test cases to cover functionality in DaemonStorage class - """ diff --git a/sonic-storagemond/tests/test_StorageDevice.py b/sonic-storagemond/tests/test_StorageDevice.py deleted file mode 100644 index 21f589d07..000000000 --- a/sonic-storagemond/tests/test_StorageDevice.py +++ /dev/null @@ -1,33 +0,0 @@ -import os -import sys -from imp import load_source # Replace with importlib once we no longer need to support Python 2 - -import pytest - -# TODO: Clean this up once we no longer need to support Python 2 -if sys.version_info >= (3, 3): - from unittest.mock import MagicMock, patch, mock_open -else: - from mock import MagicMock, patch, mock_open - -from .mock_platform import MockStorageDevice - -tests_path = os.path.dirname(os.path.abspath(__file__)) - -# Add mocked_libs path so that the file under test can load mocked modules from there -mocked_libs_path = os.path.join(tests_path, "mocked_libs") -sys.path.insert(0, mocked_libs_path) -from sonic_py_common import daemon_base, device_info - -# Add path to the file under test so that we can load it -modules_path = os.path.dirname(tests_path) -scripts_path = os.path.join(modules_path, "scripts") -sys.path.insert(0, modules_path) -load_source('storagemond', os.path.join(scripts_path, 'storagemond')) -import storagemond - - -daemon_base.db_connect = MagicMock() - -SYSLOG_IDENTIFIER = 'storagedevice_test' -NOT_AVAILABLE = 'N/A' \ No newline at end of file