diff --git a/jc/parsers/df.py b/jc/parsers/df.py index 2fc61246..a4639c79 100644 --- a/jc/parsers/df.py +++ b/jc/parsers/df.py @@ -92,13 +92,14 @@ Examples: ... ] """ +import hashlib import jc.utils import jc.parsers.universal class info(): """Provides parser metadata (version, author, etc.)""" - version = '1.7' + version = '1.8' description = '`df` command parser' author = 'Kelly Brazil' author_email = 'kellyjonbrazil@gmail.com' @@ -165,6 +166,29 @@ def _process(proc_data): return proc_data +def _long_filesystem_hash(header, line): + """Returns truncated hash and value of the filesystem field if it is too long for the column""" + filesystem_field = line.split()[0] + + # get length of filesystem column + space_count = 0 + for char in header[10:]: + if char == ' ': + space_count += 1 + continue + + break + + filesystem_col_len = space_count + 9 + + # return the hash and value if the field data is longer than the column length + if len(filesystem_field) > filesystem_col_len: + truncated_hash = hashlib.sha256(filesystem_field.encode('utf-8')).hexdigest()[:filesystem_col_len] + return truncated_hash, filesystem_field + + return None, None + + def parse(data, raw=False, quiet=False): """ Main text parsing function @@ -184,7 +208,9 @@ def parse(data, raw=False, quiet=False): jc.utils.compatibility(__name__, info.compatible) cleandata = data.splitlines() + fix_data = [] raw_output = [] + filesystem_map = {} if jc.utils.has_data(data): @@ -193,8 +219,25 @@ def parse(data, raw=False, quiet=False): cleandata[0] = cleandata[0].replace('-', '_') cleandata[0] = cleandata[0].replace('mounted on', 'mounted_on') + # fix long filesystem data in some older versions of df + header = cleandata[0] + fix_data.append(header) + for line in cleandata[1:]: + field_hash, field_value = _long_filesystem_hash(header, line) + if field_hash: + filesystem_map.update({field_hash: field_value}) + newline = line.replace(field_value, field_hash) + fix_data.append(newline) + else: + fix_data.append(line) + # parse the data - raw_output = jc.parsers.universal.sparse_table_parse(cleandata) + raw_output = jc.parsers.universal.sparse_table_parse(fix_data) + + # replace hash values with real values to fix long filesystem data in some older versions of df + for item in raw_output: + if item['filesystem'] in filesystem_map: + item['filesystem'] = filesystem_map[item['filesystem']] if raw: return raw_output diff --git a/tests/fixtures/generic/df-long-filesystem.json b/tests/fixtures/generic/df-long-filesystem.json new file mode 100644 index 00000000..dfe51152 --- /dev/null +++ b/tests/fixtures/generic/df-long-filesystem.json @@ -0,0 +1 @@ +[{"filesystem":"/dev/mapper/VolGroup00-LogVol00","type":"ext3","1024_blocks":6030784,"used":1147932,"available":4571556,"mounted_on":"/","capacity_percent":21},{"filesystem":"proc","type":"proc","1024_blocks":0,"used":0,"available":0,"mounted_on":"/proc","capacity_percent":null},{"filesystem":"sysfs","type":"sysfs","1024_blocks":0,"used":0,"available":0,"mounted_on":"/sys","capacity_percent":null}] diff --git a/tests/fixtures/generic/df-long-filesystem.out b/tests/fixtures/generic/df-long-filesystem.out new file mode 100644 index 00000000..d1179f32 --- /dev/null +++ b/tests/fixtures/generic/df-long-filesystem.out @@ -0,0 +1,4 @@ +Filesystem Type 1024-blocks Used Available Capacity Mounted on +/dev/mapper/VolGroup00-LogVol00 ext3 6030784 1147932 4571556 21% / +proc proc 0 0 0 - /proc +sysfs sysfs 0 0 0 - /sys diff --git a/tests/test_df.py b/tests/test_df.py index d59ef778..0736e95b 100644 --- a/tests/test_df.py +++ b/tests/test_df.py @@ -34,6 +34,9 @@ class MyTests(unittest.TestCase): with open(os.path.join(THIS_DIR, os.pardir, 'tests/fixtures/osx-10.14.6/df-h.out'), 'r', encoding='utf-8') as f: self.osx_10_14_6_df_h = f.read() + with open(os.path.join(THIS_DIR, os.pardir, 'tests/fixtures/generic/df-long-filesystem.out'), 'r', encoding='utf-8') as f: + self.generic_df_long_filesystem = f.read() + # output with open(os.path.join(THIS_DIR, os.pardir, 'tests/fixtures/centos-7.7/df.json'), 'r', encoding='utf-8') as f: self.centos_7_7_df_json = json.loads(f.read()) @@ -59,6 +62,9 @@ class MyTests(unittest.TestCase): with open(os.path.join(THIS_DIR, os.pardir, 'tests/fixtures/osx-10.14.6/df-h.json'), 'r', encoding='utf-8') as f: self.osx_10_14_6_df_h_json = json.loads(f.read()) + with open(os.path.join(THIS_DIR, os.pardir, 'tests/fixtures/generic/df-long-filesystem.json'), 'r', encoding='utf-8') as f: + self.generic_df_long_filesystem_json = json.loads(f.read()) + def test_df_nodata(self): """ Test plain 'df' with no data @@ -113,6 +119,12 @@ class MyTests(unittest.TestCase): """ self.assertEqual(jc.parsers.df.parse(self.osx_10_14_6_df_h, quiet=True), self.osx_10_14_6_df_h_json) + def test_df_long_filesystem(self): + """ + Test older version of 'df' with long filesystem data + """ + self.assertEqual(jc.parsers.df.parse(self.generic_df_long_filesystem, quiet=True), self.generic_df_long_filesystem_json) + if __name__ == '__main__': unittest.main()