Skip to content
Snippets Groups Projects
Commit 5d94c034 authored by Helga Velroyen's avatar Helga Velroyen
Browse files

Use os.statvfs to determine free disk space


This simplifies my previous commit (820bade9) by using os.statvfs
instead of parsing the output of 'df'.

Signed-off-by: default avatarHelga Velroyen <helgav@google.com>
Reviewed-by: default avatarBernardo Dal Seno <bdalseno@google.com>
parent f08b1a00
No related branches found
No related tags found
No related merge requests found
......@@ -23,56 +23,26 @@
"""
from ganeti import errors
from ganeti import utils
DF_M_UNIT = 'M'
DF_MIN_NUM_COLS = 4
DF_NUM_LINES = 2
def _ParseDfResult(dfresult):
"""Parses the output of the call of the 'df' tool.
import os
@type dfresult: string
@param dfresult: output of the 'df' call
@return: tuple (size, free) of the total and free disk space in MebiBytes
"""
df_lines = dfresult.splitlines()
if len(df_lines) != DF_NUM_LINES:
raise errors.CommandError("'df' output has wrong number of lines: %s" %
len(df_lines))
df_values = df_lines[1].strip().split()
if len(df_values) < DF_MIN_NUM_COLS:
raise errors.CommandError("'df' output does not have enough columns: %s" %
len(df_values))
size_str = df_values[1]
if size_str[-1] != DF_M_UNIT:
raise errors.CommandError("'df': 'size' not given in Mebibytes.")
free_str = df_values[3]
if free_str[-1] != DF_M_UNIT:
raise errors.CommandError("'df': 'free' not given in Mebibytes.")
size = int(size_str[:-1])
free = int(free_str[:-1])
return (size, free)
from ganeti import errors
def GetSpaceInfo(path, _parsefn=_ParseDfResult):
def GetSpaceInfo(path):
"""Retrieves the free and total space of the device where the file is
located.
@type path: string
@param path: Path of the file whose embracing device's capacity is
reported.
@type _parsefn: function
@param _parsefn: Function that parses the output of the 'df' command;
given as parameter to make this code more testable.
@return: a dictionary containing 'vg_size' and 'vg_free'
@return: a dictionary containing 'vg_size' and 'vg_free' given in MebiBytes
"""
cmd = ['df', '-BM', path]
result = utils.RunCmd(cmd)
if result.failed:
raise errors.CommandError("Failed to run 'df' command: %s - %s" %
(result.fail_reason, result.output))
(size, free) = _parsefn(result.stdout)
return {"vg_size": size, "vg_free": free}
try:
result = os.statvfs(path)
free = (result.f_frsize * result.f_bavail) / (1024 * 1024)
size = (result.f_frsize * result.f_blocks) / (1024 * 1024)
return {"vg_size": size, "vg_free": free}
except OSError, e:
raise errors.CommandError("Failed to retrieve file system information about"
" path: %s - %s" % (path, e.strerror))
......@@ -45,50 +45,6 @@ class TestFileStorageSpaceInfo(unittest.TestCase):
"""
info = filestorage.GetSpaceInfo("/")
def testParseDfOutputValidInput(self):
"""Tests that parsing of the output of 'df' works correctly.
"""
valid_df_output = \
"Filesystem 1M-blocks Used Available Use% Mounted on\n" \
"/dev/mapper/sysvg-root 161002M 58421M 94403M 39% /"
expected_size = 161002
expected_free = 94403
(size, free) = filestorage._ParseDfResult(valid_df_output)
self.assertEqual(expected_size, size,
"Calculation of total size is incorrect.")
self.assertEqual(expected_free, free,
"Calculation of free space is incorrect.")
def testParseDfOutputInvalidInput(self):
"""Tests that parsing of the output of 'df' works correctly when invalid
input is given.
"""
invalid_output_header_missing = \
"/dev/mapper/sysvg-root 161002M 58421M 94403M 39% /"
invalid_output_dataline_missing = \
"Filesystem 1M-blocks Used Available Use% Mounted on\n"
invalid_output_wrong_num_columns = \
"Filesystem 1M-blocks Available\n" \
"/dev/mapper/sysvg-root 161002M 94403M"
invalid_output_units_wrong = \
"Filesystem 1M-blocks Used Available Use% Mounted on\n" \
"/dev/mapper/sysvg-root 161002G 58421G 94403G 39% /"
invalid_output_units_missing = \
"Filesystem 1M-blocks Used Available Use% Mounted on\n" \
"/dev/mapper/sysvg-root 161002 58421 94403 39% /"
invalid_outputs = [invalid_output_header_missing,
invalid_output_dataline_missing,
invalid_output_wrong_num_columns,
invalid_output_units_wrong,
invalid_output_units_missing]
for output in invalid_outputs:
self.assertRaises(errors.CommandError, filestorage._ParseDfResult, output)
if __name__ == "__main__":
testutils.GanetiTestProgram()
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment