Open In App

Python | Monitor hard-disk health using smartmontools

Improve
Improve
Like Article
Like
Save
Share
Report

Smartmontools, an acronym for ‘S.M.A.R.T monitoring’ tools is a package that is used to control and monitor computer storage systems using S.M.A.R.T. (Self-Monitoring, Analysis and Reporting Technology) system built into most modern (P)ATA, Serial ATA, SCSI/SAS devices. It contains 2 utility programs: smartctl and smartd. These utilities give warnings or alerts of disk degradation and failure. smartmontools can be used in any Unix/Linux-based operating system. It allows us to run various tests to check the health of the HDD or SSD in your system.

S.M.A.R.T

Most modern hard drives use S.M.A.R.T. (Self-Monitoring, Analysis, and Reporting Technology) to assess their condition to determine if something is wrong with the device. This allows the user to view the hard drive’s SMART data and take necessary actions to repair or replace the device. In this article, we will explore smartmontools and retrieve information on the HDDs and SSD in the system. We will also write a python script to parse the output of smartmontools and store the outputs in an excel sheet.

Installations –

sudo pip3 install pandas
sudo apt-get install smartmontools 

Once smartmontools has been installed, we can use the terminal or command line to obtain details of the hard drives.

Device information –

To check whether your device supports SMART monitoring and to obtain other information such as device model, capacity, serial number, etc, we use the following command:

sudo smartctl -i /dev/sda

If it is not enabled, the following command enables SMART monitoring:

sudo smartctl -s on /dev/sda

Checking the health of the device

To display the overall health of the disk, we use the following command:

sudo smartctl -H /dev/sda

This displays the status of your hard drive. If it displays any errors, then your hard drive might be experiencing some problems and you should consider backing up your data.

Tests –

To run a short test :

sudo smartctl --test=short /dev/sda

The goal of the short test is the rapid identification of a defective hard drive. Therefore, the maximum run time for the short test is 2 min. To run a long test:

sudo smartctl --test=long /dev/sda

Long tests also identify defects but here, there is no time restriction. The test is more thorough. To check the results of the test:

sudo smartctl -l selftest /dev/sda

An example –

We can use Python to automate this process and generate a report. For this, we shall use Pandas to store the result in excel sheets and the os module to run the commands. 

Python3




# importing libraries
import os
import pandas as pd
from pandas import ExcelWriter
 
# class to hold all the
# details about the device
class Device():
 
    def __init__(self):
 
        self.device_name = None
        self.info = {}
        self.results = []
 
    # get the details of the device
    def get_device_name(self):
 
        cmd = 'smartctl --scan'
 
        data = os.popen(cmd)
        res = data.read()
        temp = res.split(' ')
 
        temp = temp[0].split('/')
        name = temp[2]
        self.device_name = name
 
 
    # get the device info (sda or sdb)
    def get_device_info(self):
 
        cmd = 'smartctl -i /dev/' + self.device_name
 
        data = os.popen(cmd)
 
        res = data.read().splitlines()
 
        device_info = {}
 
        for i in range(4, len(res) - 1):
            line = res[i]
            temp = line.split(':')
            device_info[temp[0]] = temp[1]
 
        self.info = device_info
 
    # save the results as an excel file
    def save_to_excel(self):
 
        try:
            os.mkdir('outputs')
        except(Exception):
            pass
 
        os.chdir('outputs')
 
        col1 = list(self.info.keys())
        col2 = list(self.info.values())
 
        output = pd.DataFrame()
        output['Name'] = col1
        output['Info'] = col2
 
        writer = ExcelWriter('Device_info.xlsx')
        output.to_excel(writer, 'Info_report', index = False)
 
        workbook = writer.book
        worksheet = writer.sheets['Info_report']
 
        # Account info columns
        worksheet.set_column('A:A', 35)
        # State column
        worksheet.set_column('B:B', 55)
        # Post code
        # worksheet.set_column('F:F', 10)
        writer.save()
        os.chdir('..')
 
    # function to check the health
    # of the device
    def check_device_health(self):
 
        cmd = 'smartctl -H /dev/' + self.device_name
 
        data = os.popen(cmd).read()
        res = data.splitlines()
        health = res[4].split(':')
        print(health[0] + ':' + health[1])
 
 
    # function to run the short test
    def run_short_test(self):
 
        cmd = 'smartctl --test = short /dev/' + self.device_name
        data = os.popen(cmd).read().splitlines()
 
 
    # function to get the results
    # of the test.
    def get_results(self):
 
        cmd = 'smartctl -l selftest /dev/' + self.device_name
        data = os.popen(cmd).read()
        res = data.splitlines()
 
        # stores the names of columns
        columns = res[5].split(' ')
        columns = ' '.join(columns)
        columns = columns.split()
 
        info = [columns]
 
        # iterate through the important
        # rows since 0-5 is not required
        for i in range(6, len(res)):
                 
            line = res[i]
 
            line = ' '.join(line.split())
            row = line.split(' ')
            info.append(row)
 
        # save the results
        self.results = info
 
 
    # function to convert the
    # results of the test to an
    # excel file and save it
    def save_results_to_excel(self):
 
        # create a folder to store outputs
        try:
            os.mkdir('outputs')
        except(Exception):
            pass
 
        os.chdir('outputs')
 
        # get the columns
        columns = self.results[0]
 
        # create a dataframe to store
        # the result in excel
        outputs = pd.DataFrame()
 
        col1, col2, col3, col4 = [], [], [], []
         
        l = len(self.results[1])
 
        # iterate through all the rows and store
        # it in the data frame
        for i in range(1, len(self.results) - 1):
 
            if(len(self.results[i]) == l):
                col1.append(' '.join(self.results[i][2:4]))
                col2.append(' '.join(self.results[i][4:7]))
                col3.append(self.results[i][7])
                col4.append(self.results[i][8])           
            else:
 
                col1.append(' '.join(self.results[i][1:3]))
                col2.append(' '.join(self.results[i][3:6]))
                col3.append(self.results[i][6])
                col4.append(self.results[i][7])   
 
        # store the columns that we
        # require in the data frame
        outputs[columns[1]] = col1
        outputs[columns[2]] = col2
        outputs[columns[3]] = col3
        outputs[columns[4]] = col4
         
        # an excel writer object to save as excel.
        writer = ExcelWriter('Test_results.xlsx')
     
        outputs.to_excel(writer, 'Test_report', index = False)
 
        # manipulating the dimensions of the columns
        # to make it more presentable.
        workbook = writer.book
        worksheet = writer.sheets['Test_report']
 
        worksheet.set_column('A:A', 25)
        worksheet.set_column('B:B', 25)
        worksheet.set_column('C:C', 25)
        worksheet.set_column('D:D', 25)
 
        # saving the file
        writer.save()
 
        os.chdir('..')
 
 
# driver function
if __name__ == '__main__':
 
    device = Device()
    device.get_device_name()
    device.get_device_info() 
    device.save_to_excel()
    device.check_device_health()
    device.run_short_test()
    device.get_results()
    device.save_results_to_excel()


Output : Device Info: Test results:

Code Explanation:

  1. The code starts by importing the libraries needed to run the program.
  2. The Device class is then defined, which will hold all of the device’s information and results.
  3. Next, a function called get_device_name() is created that will return the name of the device being used for analysis.
  4. This function uses smartctl to scan for devices on your computer and returns their names in an array.
  5. The next step is creating a list with all of the devices found by scanning your computer with smartctl: list = [] for i in range(0, len(temp)): list.append([i+1]) Next, we need to create an ExcelWriter object so that we can write our data into a spreadsheet: writer = ExcelWriter(‘C:/Users/user/Desktop/DeviceList’)
  6. The code is used to get the device name of a computer.
  7. The following code is used to create a class called Device which will hold all the details about the device.
  8. The __init__ method of the Device class is where we initialize our variables and set our default values for them.
  9. The get_device_name method of this class is where we use smartctl –scan to find out what our device name is, then split it into its components, and finally store that in self.device_name .
  10. The code is trying to get the device information for a hard drive.
  11. It does this by using the smartctl command, which is used to check on the health of a hard drive.
  12. The code opens up an output from that command and splits it into lines based on commas.
  13. Then it creates an empty dictionary called “device_info” with keys corresponding to each line in the output.
  14. For every line in the output, it looks at what key was given and assigns that value as being equal to whatever is after : (in this case, sda or sdb).
  15. The next part of the code loops through all four values in order: 4, 3, 2, 1.
  16. This means that there are four comma-delimited pieces of data coming from smartctl – one piece per line – so we need to loop through them all until we find our last piece of data (the fourth) because then we know where our last key ends up being assigned (“sda”).
  17. The code will open a command prompt and run the smartctl command with the device name as self.device_name.
  18. The output of this is then read into a list which is then stored in a dictionary (self.info).
  19. The code above has four main parts: 1) Define what to do, 2) Open up a command prompt, 3) Run the smartctl command and 4) Read the output of that into a list which is then stored in self.info
  20. The code starts by creating a directory called outputs.
  21. Then it changes the current working directory to the output folder and creates an empty dataframe called output.
  22. The code then iterates through each of the keys in self.info and assigns them to col1, which is a list, and iterates through each value in self.info and assigns them to col2, which is also a list.
  23. Finally, it writes out this information into excel using ExcelWriter(‘Device_info.xlsx’).
  24. The code saves the data from a pandas DataFrame to an excel file.
  25. The code above creates a directory called outputs and changes the current working directory to this location.
  26. The code is a function that will check the health of the device.
  27. The code starts by creating an object called self, which is then passed to another function called check_device_health().
  28. This function creates a command line for smartctl and runs it on the device.
  29. It then reads in the output from this command and splits it into lines using splitlines() method.
  30. The next step is to create a new worksheet with two columns: one column for state information and one column for post code information.
  31. Then we set these columns as 35×55 cells respectively so they are big enough to hold all of our data.
  32. Next, we use set_column() method to specify what each cell should be named (A:A, B:B).
  33. We also use set_column() method again but this time with index=False parameter so that Excel doesn’t automatically number them 1-35 or A1-A35 instead of A1-B55 or B1-F10).
  34. Finally, we save our workbook and run short test on our device using smartctl tool before exiting back out of program.
  35. The code is a snippet of code that will create an Excel file with the data from the device.
  36. The output of this code will be in the form: A:A 35 B:B 55 F:F 10
  37. The code starts by importing the pandas library.
  38. Then it creates a variable called columns that stores the names of columns in a list.
  39. Next, it iterates through all the rows and stores them in an array called info .
  40. The code then saves this information to a file using save_results_to_excel() .
  41. The function starts by creating a folder for storing outputs and then changing directory into that folder.
  42. It gets the column names from self.results[0] , which is where we store our dataframe with excel results, so we can use those as input to create an output dataframe with excel results.
  43. We also need to know how many rows are in our dataframe because we want to make sure that there are enough cells for each row on Excel’s spreadsheet before saving it out.
  44. So, we start by getting len(self) which tells us how many rows are in our dataset and then looping through all of those rows until len(self) – 1 , or 6-1=5 since 5 is not required when you’re making an excel sheet with only one column (the first).
  45. After doing this, if there aren’t any more rows left after looping through everything else, col1 will be empty because there
  46. The code iterates through the important rows since 0-5 is not required.
  47. The code then saves the results to an excel file and save it.


Last Updated : 29 Nov, 2022
Like Article
Save Article
Previous
Next
Share your thoughts in the comments
Similar Reads