Skip to content

Add SSD Health CLI utility #587

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Sep 17, 2019
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions doc/Command-Reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -583,7 +583,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 @@ -99,6 +100,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.
123 changes: 123 additions & 0 deletions ssdutil/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
#!/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)

# ==================== 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())
print "Temperature : {}C".format(ssd.get_temperature())
if args.vendor:
print ssd.get_vendor_output()

if __name__ == '__main__':
ssdutil()