Skip to content

Commit

Permalink
Renamed ssd_base -> storage_base, added class for common calls, modif…
Browse files Browse the repository at this point in the history
…ied child class implementation accordingly
  • Loading branch information
assrinivasan committed Feb 15, 2024
1 parent 4e5e79d commit 2ebc2c1
Show file tree
Hide file tree
Showing 5 changed files with 138 additions and 36 deletions.
15 changes: 13 additions & 2 deletions sonic_platform_base/sonic_ssd/ssd_emmc.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,17 @@

try:
import os
from .ssd_base import SsdBase
from .storage_base import StorageBase
from .storage_common import StorageCommon
except ImportError as e:
raise ImportError(str(e) + "- required module not found")


class EmmcUtil(SsdBase):
class EmmcUtil(StorageBase, StorageCommon):
def __init__(self, diskdev):
self.diskdev = diskdev
self.path = os.path.join('/sys/block', os.path.basename(diskdev))
StorageCommon.__init__(self, diskdev)

def _read_device_entry(self, entry, default=None):
path = os.path.join(self.path, 'device', entry)
Expand Down Expand Up @@ -49,3 +51,12 @@ def get_serial(self):

def get_vendor_output(self):
return ''

def get_disk_io_reads(self):
return 'N/A'

def get_disk_io_writes(self):
return 'N/A'

def get_reserved_blocks(self):
return 'N/A'
57 changes: 31 additions & 26 deletions sonic_platform_base/sonic_ssd/ssd_generic.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@
try:
import re
import subprocess
from .ssd_base import SsdBase
from .storage_base import StorageBase
from .storage_common import StorageCommon
except ImportError as e:
raise ImportError (str(e) + "- required module not found")

Expand Down Expand Up @@ -51,7 +52,7 @@
TRANSCEND_HEALTH_ID = 169
TRANSCEND_TEMPERATURE_ID = 194

class SsdUtil(SsdBase):
class SsdUtil(StorageBase, StorageCommon):
"""
Generic implementation of the SSD health API
"""
Expand All @@ -62,8 +63,10 @@ class SsdUtil(SsdBase):
health = NOT_AVAILABLE
ssd_info = NOT_AVAILABLE
vendor_ssd_info = NOT_AVAILABLE
io_reads = NOT_AVAILABLE
io_writes = NOT_AVAILABLE
fs_io_reads = NOT_AVAILABLE
fs_io_writes = NOT_AVAILABLE
disk_io_reads = NOT_AVAILABLE
disk_io_writes = NOT_AVAILABLE
reserved_blocks = NOT_AVAILABLE

def __init__(self, diskdev):
Expand Down Expand Up @@ -98,6 +101,8 @@ def __init__(self, diskdev):
# Failed to get disk model
self.model = "Unknown"

StorageCommon.__init__(self, diskdev)

def _execute_shell(self, cmd):
process = subprocess.Popen(cmd.split(), universal_newlines=True, stdout=subprocess.PIPE)
output, error = process.communicate()
Expand Down Expand Up @@ -164,12 +169,12 @@ def parse_generic_ssd_info(self):
self.firmware = self._parse_re('Firmware Version:\s*(.+?)\n', self.ssd_info)

io_reads_raw = self.parse_id_number(GENERIC_IO_READS_ID)
if io_reads_raw == NOT_AVAILABLE: self.io_reads = NOT_AVAILABLE
else: self.io_reads = io_reads_raw.split()[-1]
if io_reads_raw == NOT_AVAILABLE: self.disk_io_reads = NOT_AVAILABLE
else: self.disk_io_reads = io_reads_raw.split()[-1]

io_writes_raw = self.parse_id_number(GENERIC_IO_WRITES_ID)
if io_writes_raw == NOT_AVAILABLE: self.io_writes = NOT_AVAILABLE
else: self.io_writes = io_writes_raw.split()[-1]
if io_writes_raw == NOT_AVAILABLE: self.disk_io_writes = NOT_AVAILABLE
else: self.disk_io_writes = io_writes_raw.split()[-1]

for ID in GENERIC_RESERVED_BLOCKS_ID:
rbc_raw = self.parse_id_number(ID)
Expand All @@ -195,18 +200,18 @@ def parse_innodisk_info(self):
self.temperature = NOT_AVAILABLE
else:
self.temperature = temp_raw.split()[-6]
if self.io_reads == NOT_AVAILABLE:
if self.disk_io_reads == NOT_AVAILABLE:
io_reads_raw = self.parse_id_number(INNODISK_IO_READS_ID)
if io_reads_raw == NOT_AVAILABLE:
self.io_reads == NOT_AVAILABLE
self.disk_io_reads == NOT_AVAILABLE
else:
self.io_reads = io_reads_raw.split()[-1]
if self.io_writes == NOT_AVAILABLE:
self.disk_io_reads = io_reads_raw.split()[-1]
if self.disk_io_writes == NOT_AVAILABLE:
io_writes_raw = self.parse_id_number(INNODISK_IO_WRITES_ID)
if io_writes_raw == NOT_AVAILABLE:
self.io_writes == NOT_AVAILABLE
self.disk_io_writes == NOT_AVAILABLE
else:
self.io_writes = io_writes_raw.split()[-1]
self.disk_io_writes = io_writes_raw.split()[-1]
if self.reserved_blocks == NOT_AVAILABLE:
rbc_raw = self.parse_id_number(INNODISK_RESERVED_BLOCKS_ID)
if rbc_raw == NOT_AVAILABLE:
Expand Down Expand Up @@ -237,19 +242,19 @@ def parse_virtium_info(self):
except ValueError:
pass

if self.io_reads == NOT_AVAILABLE:
if self.disk_io_reads == NOT_AVAILABLE:
io_reads_raw = self.parse_id_number(VIRTIUM_IO_READS_ID)
if io_reads_raw == NOT_AVAILABLE:
self.io_reads == NOT_AVAILABLE
self.disk_io_reads == NOT_AVAILABLE
else:
self.io_reads = io_reads_raw.split()[-1]
self.disk_io_reads = io_reads_raw.split()[-1]

if self.io_writes == NOT_AVAILABLE:
if self.disk_io_writes == NOT_AVAILABLE:
io_writes_raw = self.parse_id_number(VIRTIUM_IO_WRITES_ID)
if io_writes_raw == NOT_AVAILABLE:
self.io_writes == NOT_AVAILABLE
self.disk_io_writes == NOT_AVAILABLE
else:
self.io_writes = io_writes_raw.split()[-1]
self.disk_io_writes = io_writes_raw.split()[-1]

if self.reserved_blocks == NOT_AVAILABLE:
rbc_raw = self.parse_id_number(VIRTIUM_RESERVED_BLOCKS_ID)
Expand Down Expand Up @@ -287,8 +292,8 @@ def parse_micron_info(self):
pass

io_writes_raw = self.parse_id_number(MICRON_IO_WRITES_ID)
if io_writes_raw == NOT_AVAILABLE: self.io_writes = NOT_AVAILABLE
else: self.io_writes = io_writes_raw.split()[-1]
if io_writes_raw == NOT_AVAILABLE: self.disk_io_writes = NOT_AVAILABLE
else: self.disk_io_writes = io_writes_raw.split()[-1]

rbc_raw = self.parse_id_number(MICRON_RESERVED_BLOCKS_ID)
if rbc_raw == NOT_AVAILABLE: self.reserved_blocks = NOT_AVAILABLE
Expand Down Expand Up @@ -369,23 +374,23 @@ def get_serial(self):
"""
return self.serial

def get_io_reads(self):
def get_disk_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 self.io_reads
return self.disk_io_reads

def get_io_writes(self):
def get_disk_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
return self.disk_io_writes

def get_reserved_blocks(self):
"""
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
#
# ssd_base.py
# storage_base.py
#
# Base class for implementing common SSD health features
#


class SsdBase(object):
class StorageBase(object):
"""
Base class for interfacing with a SSD
"""
Expand Down Expand Up @@ -74,18 +74,18 @@ def get_vendor_output(self):
"""
raise NotImplementedError

def get_io_reads(self):
def get_disk_io_reads(self):
"""
Retrieves the total number of Input/Output (I/O) reads done on an SSD
Retrieves the total number of Input/Output (I/O) reads done on a storage disk
Returns:
An integer value of the total number of I/O reads
"""
raise NotImplementedError

def get_io_writes(self):
def get_disk_io_writes(self):
"""
Retrieves the total number of Input/Output (I/O) writes done on an SSD
Retrieves the total number of Input/Output (I/O) writes done on a sorage disk
Returns:
An integer value of the total number of I/O writes
Expand All @@ -99,4 +99,4 @@ def get_reserved_blocks(self):
Returns:
An integer value of the total number of reserved blocks
"""
raise NotImplementedError
raise NotImplementedError
85 changes: 85 additions & 0 deletions sonic_platform_base/sonic_ssd/storage_common.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
#
# storage_common.py
#
# Class for common implementation functions,
# i.e. functions that are storage device type agnostic.
#

try:
import os
import sys
except ImportError as e:
raise ImportError (str(e) + "- required module not found")

try:
import psutil
except ImportError as e:
pass

class StorageCommon(object):
def __init__(self, diskdev):
"""
Constructor
Args:
Block device path for which we need to get information
"""
self.DISKSTATS_FILE = "/proc/diskstats"
self.MOUNTS_FILE = "/proc/mounts"
self.diskdev = os.path.basename(diskdev)
self.partition = self.__set_host_partition(self.diskdev)

def __set_host_partition(self, diskdev):
"""
internal function to fetch SONiC partition
Returns:
The partition containing '/host' mount, or 'N/A' if not found
Args:
N/A
"""
if 'psutil' in sys.modules:
for p in psutil.disk_partitions():
if p.mountpoint == "/host":
return os.path.basename(p.device)
return None

else:
mounts = ""
with open(self.MOUNTS_FILE) as f:
mounts = f.readlines()

for mt in mounts:
if '/host' in mt and diskdev in mt:
return os.path.basename(mt.split()[0])
return None

def get_fs_io_reads(self):

searchterm = self.partition
if searchterm == None: searchterm = self.diskdev

if 'psutil' in sys.modules:
return psutil.disk_io_counters(perdisk=True, nowrap=True)[searchterm].read_count
else:
with open(self.DISKSTATS_FILE) as f:
statsfile = f.readlines()
for line in statsfile:
if searchterm in line:
return line.split()[3]
return 'N/A'

def get_fs_io_writes(self):

searchterm = self.partition
if searchterm == None: searchterm = self.diskdev

if 'psutil' in sys.modules:
return psutil.disk_io_counters(perdisk=True, nowrap=True)[searchterm].write_count
else:
with open(self.DISKSTATS_FILE) as f:
statsfile = f.readlines()
for line in statsfile:
if searchterm in line:
return line.split()[7]
return 'N/A'
3 changes: 2 additions & 1 deletion tests/ssd_emmc_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@
'/sys/block/emmctest/device/life_time': '0x02 0x02',
'/sys/block/emmctest/device/name': 'Test eMMC device',
'/sys/block/emmctest/device/fwrev': '0xAA00000000000000',
'/sys/block/emmctest/device/serial': '0xabcdefef'
'/sys/block/emmctest/device/serial': '0xabcdefef',
'/proc/mounts' : '/dev/emmctestp1 /host ext4 rw,relatime 0 0'
}


Expand Down

0 comments on commit 2ebc2c1

Please sign in to comment.