Skip to content

Commit

Permalink
Add SSD Health CLI utility (sonic-net#587)
Browse files Browse the repository at this point in the history
* Add SSD Health CLI utility

Signed-off-by: Andriy Moroz <c_andriym@mellanox.com>

* Add SSD Health command reference

* Rename ssdutility entrypoint to ssdutil

Signed-off-by: Andriy Moroz <c_andriym@mellanox.com>

* Fix - do not add units if value is N/A

Signed-off-by: Andriy Moroz <c_andriym@mellanox.com>
  • Loading branch information
andriymoroz-mlnx authored and lguohan committed Sep 17, 2019
1 parent cbcdc82 commit 065414a
Show file tree
Hide file tree
Showing 5 changed files with 158 additions and 0 deletions.
12 changes: 12 additions & 0 deletions doc/Command-Reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -598,7 +598,19 @@ Couple of example outputs are given below.
(checksum valid)
```

**show platform ssdhealth**
This command displays health parameters of the device's SSD

- Usage:
show platform ssdhealth [--verbose, --vendor]

- Example:
```
root@arc-switch1029:/home/admin# show platform ssdhealth
Device Model : M.2 (S42) 3IE3
Health : 99.665%
Temperature : 30C
```

**show platform psustatus**
This command displays the status of the device's power supply units
Expand Down
2 changes: 2 additions & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
'debug',
'pfcwd',
'sfputil',
'ssdutil',
'pfc',
'psuutil',
'show',
Expand Down Expand Up @@ -100,6 +101,7 @@
'debug = debug.main:cli',
'pfcwd = pfcwd.main:cli',
'sfputil = sfputil.main:cli',
'ssdutil = ssdutil.main:ssdutil',
'pfc = pfc.main:cli',
'psuutil = psuutil.main:cli',
'show = show.main:cli',
Expand Down
14 changes: 14 additions & 0 deletions show/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -1258,6 +1258,20 @@ def psustatus(index, verbose):

run_command(cmd, display_cmd=verbose)

# 'ssdhealth' subcommand ("show platform ssdhealth [--verbose/--vendor]")
@platform.command()
@click.argument('device', required=False)
@click.option('--verbose', is_flag=True, help="Enable verbose output")
@click.option('--vendor', is_flag=True, help="Enable vendor specific output")
def ssdhealth(device, verbose, vendor):
"""Show SSD Health information"""
if not device:
device = os.popen("lsblk -o NAME,TYPE -p | grep disk").readline().strip().split()[0]
cmd = "ssdutil -d " + device
options = " -v" if verbose else ""
options += " -e" if vendor else ""
run_command(cmd + options, display_cmd=verbose)

#
# 'logging' command ("show logging")
#
Expand Down
Empty file added ssdutil/__init__.py
Empty file.
130 changes: 130 additions & 0 deletions ssdutil/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
#!/usr/bin/env python
#
# main.py
#
# Command-line utility to check SSD health and parameters
#

try:
import sys
import os
import subprocess
import argparse
import syslog
except ImportError as e:
raise ImportError("%s - required module not found" % str(e))

DEFAULT_DEVICE="/dev/sda"
SYSLOG_IDENTIFIER = "ssdutil"

PLATFORM_ROOT_PATH = '/usr/share/sonic/device'
SONIC_CFGGEN_PATH = '/usr/local/bin/sonic-cfggen'
HWSKU_KEY = 'DEVICE_METADATA.localhost.hwsku'
PLATFORM_KEY = 'DEVICE_METADATA.localhost.platform'

def syslog_msg(severity, msg, stdout=False):
"""
Prints to syslog (and stdout if needed) message with specified severity
Args:
severity : message severity
msg : message
stdout : also primt message to stdout
"""
syslog.openlog(SYSLOG_IDENTIFIER)
syslog.syslog(severity, msg)
syslog.closelog()

if stdout:
print msg

def get_platform_and_hwsku():
"""
Retrieves current platform name and hwsku
Raises an OSError exception when failed to fetch
Returns:
tuple of strings platform and hwsku
e.g. ("x86_64-mlnx_msn2700-r0", "ACS-MSN2700")
"""
try:
proc = subprocess.Popen([SONIC_CFGGEN_PATH, '-H', '-v', PLATFORM_KEY],
stdout=subprocess.PIPE,
shell=False,
stderr=subprocess.STDOUT)
stdout = proc.communicate()[0]
proc.wait()
platform = stdout.rstrip('\n')

proc = subprocess.Popen([SONIC_CFGGEN_PATH, '-d', '-v', HWSKU_KEY],
stdout=subprocess.PIPE,
shell=False,
stderr=subprocess.STDOUT)
stdout = proc.communicate()[0]
proc.wait()
hwsku = stdout.rstrip('\n')
except OSError, e:
raise OSError("Cannot detect platform")

return (platform, hwsku)

def import_ssd_api(diskdev):
"""
Loads platform specific or generic ssd_util module from source
Raises an ImportError exception if none of above available
Returns:
Instance of the class with SSD API implementation (vendor or generic)
"""

# Get platform and hwsku
(platform, hwsku) = get_platform_and_hwsku()

# try to load platform specific module
try:
hwsku_plugins_path = "/".join([PLATFORM_ROOT_PATH, platform, "plugins"])
sys.path.append(os.path.abspath(hwsku_plugins_path))
from ssd_util import SsdUtil
except ImportError as e:
syslog_msg(syslog.LOG_WARNING, "Platform specific SsdUtil module not found. Falling down to the generic implementation")
try:
from sonic_platform_base.sonic_ssd.ssd_generic import SsdUtil
except ImportError as e:
syslog_msg(syslog.LOG_ERR, "Failed to import default SsdUtil. Error: {}".format(str(e)), True)
raise e

return SsdUtil(diskdev)

def is_number(s):
try:
float(s)
return True
except ValueError:
return False

# ==================== Entry point ====================
def ssdutil():
if os.geteuid() != 0:
print "Root privileges are required for this operation"
sys.exit(1)

parser = argparse.ArgumentParser()
parser.add_argument("-d", "--device", help="Device name to show health info", default=DEFAULT_DEVICE)
parser.add_argument("-v", "--verbose", action="store_true", default=False, help="Show verbose output (some additional parameters)")
parser.add_argument("-e", "--vendor", action="store_true", default=False, help="Show vendor output (extended output if provided by platform vendor)")
args = parser.parse_args()

ssd = import_ssd_api(args.device)

print "Device Model : {}".format(ssd.get_model())
if args.verbose:
print "Firmware : {}".format(ssd.get_firmware())
print "Serial : {}".format(ssd.get_serial())
print "Health : {}{}".format(ssd.get_health(), "%" if is_number(ssd.get_health()) else "")
print "Temperature : {}{}".format(ssd.get_temperature(), "C" if is_number(ssd.get_temperature()) else "")
if args.vendor:
print ssd.get_vendor_output()

if __name__ == '__main__':
ssdutil()

0 comments on commit 065414a

Please sign in to comment.