mirror of https://github.com/nicolargo/glances.git
Removed pySMART version hack, now using pySMART.smartx from pip
This commit is contained in:
parent
c15a970937
commit
4259f78eda
|
|
@ -1,113 +0,0 @@
|
|||
# Copyright (C) 2014 Marc Herndon
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License,
|
||||
# version 2, as published by the Free Software Foundation.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
# MA 02110-1301, USA.
|
||||
#
|
||||
################################################################
|
||||
"""
|
||||
Copyright (C) 2014 Marc Herndon
|
||||
|
||||
pySMART is a simple Python wrapper for the `smartctl` component of
|
||||
`smartmontools`. It works under Linux and Windows, as long as smartctl is on
|
||||
the system path. Running with administrative (root) privilege is strongly
|
||||
recommended, as smartctl cannot accurately detect all device types or parse
|
||||
all SMART information without full permissions.
|
||||
|
||||
With only a device's name (ie: /dev/sda, pd0), the API will create a
|
||||
`Device` object, populated with all relevant information about
|
||||
that device. The documented API can then be used to query this object for
|
||||
information, initiate device self-tests, and perform other functions.
|
||||
|
||||
Usage
|
||||
-----
|
||||
The most common way to use pySMART is to create a logical representation of the
|
||||
physical storage device that you would like to work with, as shown:
|
||||
|
||||
#!bash
|
||||
>>> from pySMART import Device
|
||||
>>> sda = Device('/dev/sda')
|
||||
>>> sda
|
||||
<SATA device on /dev/sda mod:WDC WD5000AAKS-60Z1A0 sn:WD-WCAWFxxxxxxx>
|
||||
|
||||
`Device` class members can be accessed directly, and a number of helper methods
|
||||
are provided to retrieve information in bulk. Some examples are shown below:
|
||||
|
||||
#!bash
|
||||
>>> sda.assessment # Query the SMART self-assessment
|
||||
'PASS'
|
||||
>>> sda.attributes[9] # Query a single SMART attribute
|
||||
<SMART Attribute 'Power_On_Hours' 068/000 raw:23644>
|
||||
>>> sda.all_attributes() # Print the entire SMART attribute table
|
||||
ID# ATTRIBUTE_NAME CUR WST THR TYPE UPDATED WHEN_FAIL RAW
|
||||
1 Raw_Read_Error_Rate 200 200 051 Pre-fail Always - 0
|
||||
3 Spin_Up_Time 141 140 021 Pre-fail Always - 3908
|
||||
4 Start_Stop_Count 098 098 000 Old_age Always - 2690
|
||||
5 Reallocated_Sector_Ct 200 200 140 Pre-fail Always - 0
|
||||
... # Edited for brevity
|
||||
199 UDMA_CRC_Error_Count 200 200 000 Old_age Always - 0
|
||||
200 Multi_Zone_Error_Rate 200 200 000 Old_age Offline - 0
|
||||
>>> sda.tests[0] # Query the most recent self-test result
|
||||
<SMART Self-test [Short offline|Completed without error] hrs:23734 LBA:->
|
||||
>>> sda.all_selftests() # Print the entire self-test log
|
||||
ID Test_Description Status Left Hours 1st_Error@LBA
|
||||
1 Short offline Completed without error 00% 23734 -
|
||||
2 Short offline Completed without error 00% 23734 -
|
||||
... # Edited for brevity
|
||||
7 Short offline Completed without error 00% 23726 -
|
||||
8 Short offline Completed without error 00% 1 -
|
||||
|
||||
Alternatively, the package provides a `DeviceList` class. When instantiated,
|
||||
this will auto-detect all local storage devices and create a list containing
|
||||
one `Device` object for each detected storage device.
|
||||
|
||||
#!bash
|
||||
>>> from pySMART import DeviceList
|
||||
>>> devlist = DeviceList()
|
||||
>>> devlist
|
||||
<DeviceList contents:
|
||||
<SAT device on /dev/sdb mod:WDC WD20EADS-00R6B0 sn:WD-WCAVYxxxxxxx>
|
||||
<SAT device on /dev/sdc mod:WDC WD20EADS-00S2B0 sn:WD-WCAVYxxxxxxx>
|
||||
<CSMI device on /dev/csmi0,0 mod:WDC WD5000AAKS-60Z1A0 sn:WD-WCAWFxxxxxxx>
|
||||
>
|
||||
>>> devlist.devices[0].attributes[5] # Access Device data as above
|
||||
<SMART Attribute 'Reallocated_Sector_Ct' 173/140 raw:214>
|
||||
|
||||
Using the pySMART wrapper, Python applications be be rapidly developed to take
|
||||
advantage of the powerful features of smartmontools.
|
||||
|
||||
Acknowledgements
|
||||
----------------
|
||||
I would like to thank the entire team behind smartmontools for creating and
|
||||
maintaining such a fantastic product.
|
||||
|
||||
In particular I want to thank Christian Franke, who maintains the Windows port
|
||||
of the software. For several years I have written Windows batch files that
|
||||
rely on smartctl.exe to automate evaluation and testing of large pools of
|
||||
storage devices under Windows. Without his work, my job would have been
|
||||
significantly more miserable. :)
|
||||
|
||||
Having recently migrated my development from Batch to Python for Linux
|
||||
portabiity, I thought a simple wrapper for smartctl would save time in the
|
||||
development of future automated test tools.
|
||||
"""
|
||||
from . import utils
|
||||
utils.configure_trace_logging()
|
||||
|
||||
from .attribute import Attribute
|
||||
from .device import Device, smart_health_assement
|
||||
from .device_list import DeviceList
|
||||
from .test_entry import Test_Entry
|
||||
|
||||
|
||||
__version__ = '0.3'
|
||||
|
|
@ -1,99 +0,0 @@
|
|||
# Copyright (C) 2014 Marc Herndon
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License,
|
||||
# version 2, as published by the Free Software Foundation.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
# MA 02110-1301, USA.
|
||||
#
|
||||
################################################################
|
||||
"""
|
||||
This module contains the definition of the `Attribute` class, used to represent
|
||||
individual SMART attributes associated with a `Device`.
|
||||
"""
|
||||
|
||||
|
||||
class Attribute(object):
|
||||
"""
|
||||
Contains all of the information associated with a single SMART attribute
|
||||
in a `Device`'s SMART table. This data is intended to exactly mirror that
|
||||
obtained through smartctl.
|
||||
"""
|
||||
|
||||
def __init__(self, num, name, flags, value, worst, thresh, attr_type, updated, when_failed, raw):
|
||||
self.num = num
|
||||
"""**(str):** Attribute's ID as a decimal value (1-255)."""
|
||||
self.name = name
|
||||
"""
|
||||
**(str):** Attribute's name, as reported by smartmontools' drive.db.
|
||||
"""
|
||||
self.flags = flags
|
||||
"""**(str):** Attribute flags as a hexadecimal value (ie: 0x0032)."""
|
||||
self.value = value
|
||||
"""**(str):** Attribute's current normalized value."""
|
||||
self.worst = worst
|
||||
"""**(str):** Worst recorded normalized value for this attribute."""
|
||||
self.thresh = thresh
|
||||
"""**(str):** Attribute's failure threshold."""
|
||||
self.type = attr_type
|
||||
"""**(str):** Attribute's type, generally 'pre-fail' or 'old-age'."""
|
||||
self.updated = updated
|
||||
"""
|
||||
**(str):** When is this attribute updated? Generally 'Always' or
|
||||
'Offline'
|
||||
"""
|
||||
self.when_failed = when_failed
|
||||
"""
|
||||
**(str):** When did this attribute cross below
|
||||
`pySMART.attribute.Attribute.thresh`? Reads '-' when not failed.
|
||||
Generally either 'FAILING_NOW' or 'In_the_Past' otherwise.
|
||||
"""
|
||||
self.raw = raw
|
||||
"""**(str):** Attribute's current raw (non-normalized) value."""
|
||||
|
||||
def __repr__(self):
|
||||
"""Define a basic representation of the class object."""
|
||||
return "<SMART Attribute %r %s/%s raw:%s>" % (
|
||||
self.name, self.value, self.thresh, self.raw)
|
||||
|
||||
def __str__(self):
|
||||
"""
|
||||
Define a formatted string representation of the object's content.
|
||||
In the interest of not overflowing 80-character lines this does not
|
||||
print the value of `pySMART.attribute.Attribute.flags_hex`.
|
||||
"""
|
||||
return "{0:>3} {1:24}{2:4}{3:4}{4:4}{5:9}{6:8}{7:12}{8}".format(
|
||||
self.num,
|
||||
self.name,
|
||||
self.value,
|
||||
self.worst,
|
||||
self.thresh,
|
||||
self.type,
|
||||
self.updated,
|
||||
self.when_failed,
|
||||
self.raw
|
||||
)
|
||||
|
||||
def __getstate__(self):
|
||||
return {
|
||||
'num': self.num,
|
||||
'flags': self.flags,
|
||||
'raw': self.raw,
|
||||
'value': self.value,
|
||||
'worst': self.worst,
|
||||
'threshold': self.thresh,
|
||||
'type': self.type,
|
||||
'updated': self.updated,
|
||||
'when_failed': self.when_failed,
|
||||
}
|
||||
|
||||
|
||||
__all__ = ['Attribute']
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -1,112 +0,0 @@
|
|||
# Copyright (C) 2014 Marc Herndon
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License,
|
||||
# version 2, as published by the Free Software Foundation.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
# MA 02110-1301, USA.
|
||||
#
|
||||
################################################################
|
||||
"""
|
||||
This module contains the definition of the `DeviceList` class, used to
|
||||
represent all physical storage devices connected to the system.
|
||||
Once initialized, the sole member `devices` will contain a list of `Device`
|
||||
objects.
|
||||
|
||||
This class has no public methods. All interaction should be through the
|
||||
`Device` class API.
|
||||
"""
|
||||
# Python built-ins
|
||||
from subprocess import Popen, PIPE
|
||||
|
||||
# pySMART module imports
|
||||
from .device import Device
|
||||
from .utils import SMARTCTL_PATH
|
||||
|
||||
|
||||
class DeviceList(object):
|
||||
"""
|
||||
Represents a list of all the storage devices connected to this computer.
|
||||
"""
|
||||
|
||||
def __init__(self, init=True):
|
||||
"""
|
||||
Instantiates and optionally initializes the `DeviceList`.
|
||||
|
||||
###Args:
|
||||
* **init (bool):** By default, `pySMART.device_list.DeviceList.devices`
|
||||
is populated with `Device` objects during instantiation. Setting init
|
||||
to False will skip initialization and create an empty
|
||||
`pySMART.device_list.DeviceList` object instead.
|
||||
"""
|
||||
self.devices = []
|
||||
"""
|
||||
**(list of `Device`):** Contains all storage devices detected during
|
||||
instantiation, as `Device` objects.
|
||||
"""
|
||||
if init:
|
||||
self._initialize()
|
||||
|
||||
def __repr__(self):
|
||||
"""Define a basic representation of the class object."""
|
||||
rep = "<DeviceList contents:\n"
|
||||
for device in self.devices:
|
||||
rep += str(device) + '\n'
|
||||
return rep + '>'
|
||||
# return "<DeviceList contents:%r>" % (self.devices)
|
||||
|
||||
def _cleanup(self):
|
||||
"""
|
||||
Removes duplicate ATA devices that correspond to an existing CSMI
|
||||
device. Also removes any device with no capacity value, as this
|
||||
indicates removable storage, ie: CD/DVD-ROM, ZIP, etc.
|
||||
"""
|
||||
# We can't operate directly on the list while we're iterating
|
||||
# over it, so we collect indeces to delete and remove them later
|
||||
to_delete = []
|
||||
# Enumerate the list to get tuples containing indeces and values
|
||||
for index, device in enumerate(self.devices):
|
||||
if device.interface == 'csmi':
|
||||
for otherindex, otherdevice in enumerate(self.devices):
|
||||
if (otherdevice.interface == 'ata' or
|
||||
otherdevice.interface == 'sata'):
|
||||
if device.serial == otherdevice.serial:
|
||||
to_delete.append(otherindex)
|
||||
device._sd_name = otherdevice.name
|
||||
if device.capacity is None and index not in to_delete:
|
||||
to_delete.append(index)
|
||||
# Recreate the self.devices list without the marked indeces
|
||||
self.devices[:] = [v for i, v in enumerate(self.devices)
|
||||
if i not in to_delete]
|
||||
|
||||
def _initialize(self):
|
||||
"""
|
||||
Scans system busses for attached devices and add them to the
|
||||
`DeviceList` as `Device` objects.
|
||||
"""
|
||||
cmd = Popen([SMARTCTL_PATH, '--scan-open'], stdout=PIPE, stderr=PIPE)
|
||||
_stdout, _stderr = [i.decode('utf8') for i in cmd.communicate()]
|
||||
for line in _stdout.split('\n'):
|
||||
if not ('failed:' in line or line == ''):
|
||||
name = line.split(' ')[0].replace('/dev/', '')
|
||||
# CSMI devices are explicitly of the 'csmi' type and do not
|
||||
# require further disambiguation
|
||||
if name[0:4] == 'csmi':
|
||||
self.devices.append(Device(name, interface='csmi'))
|
||||
# Other device types will be disambiguated by Device.__init__
|
||||
else:
|
||||
self.devices.append(Device(name))
|
||||
# Remove duplicates and unwanted devices (optical, etc.) from the list
|
||||
self._cleanup()
|
||||
# Sort the list alphabetically by device name
|
||||
self.devices.sort(key=lambda device: device.name)
|
||||
|
||||
__all__ = ['DeviceList']
|
||||
|
|
@ -1,139 +0,0 @@
|
|||
# Copyright (C) 2014 Marc Herndon
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License,
|
||||
# version 2, as published by the Free Software Foundation.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
# MA 02110-1301, USA.
|
||||
#
|
||||
################################################################
|
||||
"""
|
||||
This module contains the definition of the `Test_Entry` class, used to
|
||||
represent individual entries in a `Device`'s SMART Self-test Log.
|
||||
"""
|
||||
|
||||
|
||||
class Test_Entry(object):
|
||||
"""
|
||||
Contains all of the information associated with a single SMART Self-test
|
||||
log entry. This data is intended to exactly mirror that obtained through
|
||||
smartctl.
|
||||
"""
|
||||
|
||||
def __init__(self, format, num, test_type, status, hours, LBA, remain=None, segment=None, sense=None, ASC=None, ASCQ=None):
|
||||
self._format = format
|
||||
"""
|
||||
**(str):** Indicates whether this entry was taken from an 'ata' or
|
||||
'scsi' self-test log. Used to display the content properly.
|
||||
"""
|
||||
self.num = num
|
||||
"""
|
||||
**(str):** Entry's position in the log from 1 (most recent) to 21
|
||||
(least recent). ATA logs save the last 21 entries while SCSI logs
|
||||
only save the last 20.
|
||||
"""
|
||||
self.type = test_type
|
||||
"""
|
||||
**(str):** Type of test run. Generally short, long (extended), or
|
||||
conveyance, plus offline (background) or captive (foreground).
|
||||
"""
|
||||
self.status = status
|
||||
"""
|
||||
**(str):** Self-test's status message, for example 'Completed without
|
||||
error' or 'Completed: read failure'.
|
||||
"""
|
||||
self.hours = hours
|
||||
"""
|
||||
**(str):** The device's power-on hours at the time the self-test
|
||||
was initiated.
|
||||
"""
|
||||
self.LBA = LBA
|
||||
"""
|
||||
**(str):** Indicates the first LBA at which an error was encountered
|
||||
during this self-test. Presented as a decimal value for ATA/SATA
|
||||
devices and in hexadecimal notation for SAS/SCSI devices.
|
||||
"""
|
||||
self.remain = remain
|
||||
"""
|
||||
**(str):** Percentage value indicating how much of the self-test is
|
||||
left to perform. '00%' indicates a complete test, while any other
|
||||
value could indicate a test in progress or one that failed prior to
|
||||
completion. Only reported by ATA devices.
|
||||
"""
|
||||
self.segment = segment
|
||||
"""
|
||||
**(str):** A manufacturer-specific self-test segment number reported
|
||||
by SCSI devices on self-test failure. Set to '-' otherwise.
|
||||
"""
|
||||
self.sense = sense
|
||||
"""
|
||||
**(str):** SCSI sense key reported on self-test failure. Set to '-'
|
||||
otherwise.
|
||||
"""
|
||||
self.ASC = ASC
|
||||
"""
|
||||
**(str):** SCSI 'Additonal Sense Code' reported on self-test failure.
|
||||
Set to '-' otherwise.
|
||||
"""
|
||||
self.ASCQ = ASCQ
|
||||
"""
|
||||
**(str):** SCSI 'Additonal Sense Code Quaifier' reported on self-test
|
||||
failure. Set to '-' otherwise.
|
||||
"""
|
||||
|
||||
def __getstate__(self):
|
||||
try:
|
||||
num = int(self.num)
|
||||
except:
|
||||
num = None
|
||||
return {
|
||||
'num': num,
|
||||
'type': self.type,
|
||||
'status': self.status,
|
||||
'hours': self.hours,
|
||||
'lba': self.LBA,
|
||||
'remain': self.remain,
|
||||
'segment': self.segment,
|
||||
'sense': self.sense,
|
||||
'asc': self.ASC,
|
||||
'ascq': self.ASCQ
|
||||
}
|
||||
|
||||
def __repr__(self):
|
||||
"""Define a basic representation of the class object."""
|
||||
return "<SMART Self-test [%s|%s] hrs:%s LBA:%s>" % (
|
||||
self.type, self.status, self.hours, self.LBA)
|
||||
|
||||
def __str__(self):
|
||||
"""
|
||||
Define a formatted string representation of the object's content.
|
||||
Looks nearly identical to the output of smartctl, without overflowing
|
||||
80-character lines.
|
||||
"""
|
||||
if self._format == 'ata':
|
||||
return "{0:>2} {1:17}{2:30}{3:5}{4:7}{5:17}".format(
|
||||
self.num, self.type, self.status, self.remain, self.hours,
|
||||
self.LBA)
|
||||
else:
|
||||
# 'Segment' could not be fit on the 80-char line. It's of limited
|
||||
# utility anyway due to it's manufacturer-proprietary nature...
|
||||
return ("{0:>2} {1:17}{2:23}{3:7}{4:14}[{5:4}{6:5}{7:4}]".format(
|
||||
self.num,
|
||||
self.type,
|
||||
self.status,
|
||||
self.hours,
|
||||
self.LBA,
|
||||
self.sense,
|
||||
self.ASC,
|
||||
self.ASCQ
|
||||
))
|
||||
|
||||
__all__ = ['Test_Entry']
|
||||
|
|
@ -1,95 +0,0 @@
|
|||
# Copyright (C) 2014 Marc Herndon
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License,
|
||||
# version 2, as published by the Free Software Foundation.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
# MA 02110-1301, USA.
|
||||
#
|
||||
################################################################
|
||||
"""
|
||||
This module contains generic utilities and configuration information for use
|
||||
by the other submodules of the `pySMART` package.
|
||||
"""
|
||||
|
||||
import logging
|
||||
import logging.handlers
|
||||
import os
|
||||
import io
|
||||
import traceback
|
||||
from shutil import which
|
||||
|
||||
_srcfile = __file__
|
||||
TRACE = logging.DEBUG - 5
|
||||
|
||||
|
||||
class TraceLogger(logging.Logger):
|
||||
def __init__(self, name):
|
||||
logging.Logger.__init__(self, name)
|
||||
logging.addLevelName(TRACE, 'TRACE')
|
||||
return
|
||||
|
||||
def trace(self, msg, *args, **kwargs):
|
||||
self.log(TRACE, msg, *args, **kwargs)
|
||||
|
||||
def findCaller(self, stack_info=False):
|
||||
"""
|
||||
Overload built-in findCaller method
|
||||
to omit not only logging/__init__.py but also the current file
|
||||
"""
|
||||
f = logging.currentframe()
|
||||
# On some versions of IronPython, currentframe() returns None if
|
||||
# IronPython isn't run with -X:Frames.
|
||||
if f is not None:
|
||||
f = f.f_back
|
||||
rv = "(unknown file)", 0, "(unknown function)", None
|
||||
while hasattr(f, "f_code"):
|
||||
co = f.f_code
|
||||
filename = os.path.normcase(co.co_filename)
|
||||
if filename in (logging._srcfile, _srcfile):
|
||||
f = f.f_back
|
||||
continue
|
||||
sinfo = None
|
||||
if stack_info:
|
||||
sio = io.StringIO()
|
||||
sio.write('Stack (most recent call last):\n')
|
||||
traceback.print_stack(f, file=sio)
|
||||
sinfo = sio.getvalue()
|
||||
if sinfo[-1] == '\n':
|
||||
sinfo = sinfo[:-1]
|
||||
sio.close()
|
||||
rv = (co.co_filename, f.f_lineno, co.co_name, sinfo)
|
||||
break
|
||||
return rv
|
||||
|
||||
|
||||
def configure_trace_logging():
|
||||
if getattr(logging.handlers.logging.getLoggerClass(), 'trace', None) is None:
|
||||
logging.setLoggerClass(TraceLogger)
|
||||
|
||||
|
||||
smartctl_type = {
|
||||
'ata': 'ata',
|
||||
'csmi': 'ata',
|
||||
'nvme': 'nvme',
|
||||
'sas': 'scsi',
|
||||
'sat': 'sat',
|
||||
'sata': 'ata',
|
||||
'scsi': 'scsi',
|
||||
'atacam': 'atacam'
|
||||
}
|
||||
SMARTCTL_PATH = which('smartctl')
|
||||
"""
|
||||
**(dict of str):** Contains actual interface types (ie: sas, csmi) as keys and
|
||||
the corresponding smartctl interface type (ie: scsi, ata) as values.
|
||||
"""
|
||||
|
||||
__all__ = ['smartctl_type', 'SMARTCTL_PATH']
|
||||
|
|
@ -24,14 +24,10 @@ Must execute as root
|
|||
"usermod -a -G disk USERNAME" is not sufficient unfortunately
|
||||
SmartCTL (/usr/sbin/smartctl) must be in system path for python2.
|
||||
|
||||
PySMART is a python2 library.
|
||||
There are a few forks that are potentially python 3 compatible
|
||||
- https://github.com/ilyinon/py.SMART/ https://pypi.org/project/py.SMART/
|
||||
- https://github.com/freenas/py-SMART/ - BSD port
|
||||
The python2 PySMART library expects smartctl to be in PATH, but adding a bash alias does not help with this.
|
||||
The BSD port uses shutil.which() to get smartctl, but this does not exist on python2.
|
||||
Regular PySMART is a python2 library.
|
||||
We are using the pySMART.smartx updated library to support both python 2 and 3.
|
||||
|
||||
If we only have disk group access:
|
||||
If we only have disk group access (no root):
|
||||
$ smartctl -i /dev/sda
|
||||
smartctl 6.6 2016-05-31 r4324 [x86_64-linux-4.15.0-30-generic] (local build)
|
||||
Copyright (C) 2002-16, Bruce Allen, Christian Franke, www.smartmontools.org
|
||||
|
|
@ -44,20 +40,15 @@ This is not very hopeful: https://medium.com/opsops/why-smartctl-could-not-be-ru
|
|||
|
||||
So, here is what we are going to do:
|
||||
Check for admin access. If no admin access, disable SMART plugin.
|
||||
Check for python version. If 3.x use patched library, if 2.7 use library from pypi
|
||||
|
||||
If smartmontools is not installed, we will catch the error upstream in plugin initialization.
|
||||
If smartmontools is not installed, we should catch the error upstream in plugin initialization.
|
||||
"""
|
||||
|
||||
from glances.plugins.glances_plugin import GlancesPlugin
|
||||
from glances.logger import logger
|
||||
from glances.main import disable
|
||||
import sys, os
|
||||
if sys.version_info >= (3,0):
|
||||
# https://github.com/freenas/py-SMART/ commit 881d09e85f7171f927d528b6205ce2015c7631bb
|
||||
from BpySMART import DeviceList
|
||||
else:
|
||||
from pySMART import DeviceList
|
||||
import os
|
||||
from pySMART import DeviceList
|
||||
|
||||
DEVKEY = "DeviceName"
|
||||
|
||||
|
|
|
|||
|
|
@ -1,2 +1,2 @@
|
|||
psutil==5.4.3
|
||||
pysmart==0.3
|
||||
pySMART.smartx
|
||||
Loading…
Reference in New Issue