#!/usr/bin/env python # -*- coding: utf-8 -*- """ 解析dmidecode命令輸出結果,返回JSON格式資料 測試伺服器Dell VMware虛擬機器 測試系統為CentOS 6.x 7.x Python版本為Python3.6 原版參考的是 https://pypi.org/project/dmidecode/ 但是在Python3上無法直接使用而且我覺得它有些邏輯問題需要做一些修改 """ import sys import subprocess __version__ = "0.1.0" __author__ = "rex.chen" class Dmidecode(object): def __init__(self): # 註釋掉裡面的鍵值意味著忽略某些型別 self._DMI_TYPE = { 0: "BIOS Information", # BIOS資訊 提供商、版本等 1: "System Information", # 系統資訊包括伺服器廠商、伺服器的星號、伺服器序列號 2: "Base Board Information", 3: "Chassis Information", # 可以獲取伺服器的高度,比如1U等。 4: "Processor Information", # 每個邏輯CPU的資訊,物理CPU數量*核心數量=邏輯CPU數量 6: "Memory Module Information", 7: "Cache Information", 8: "Port Connector Information", 9: "System Slot Information", 10: "On Board Device Information", 11: "OEM Strings", 15: "System Event Log", 16: "Physical Memory Array", 17: "Memory Device", # 每個記憶體槽位上查的記憶體條資訊,型別、容量、主頻、序列號等 18: "32-bit Memory Error Information", 19: "Memory Array Mapped Address", 20: "Memory Device Mapped Address", 23: "System Reset", 24: "Hardware Security", 30: "Out-of-band Remote Access", 32: "System Boot Information", 33: "64-bit Memory Error Information", 38: "IPMI Device Information", 41: "Onboard Device", # 126: "Inactive", # 127: "End Of Table" } def parse_dmi(self, content): """ 解析dmidecode命令輸出 :param content: 傳遞進來dmidecode命令執行的原始輸出結果 :return: 重新組裝後的資料字典 """ info = {} try: """ 這裡是一個關鍵點,dmidecode命令輸出其實是層級結構的,它使用製表符\t來表示層級,lines可以列表,但後續處理會比較麻煩 所以這裡使用迭代器一個是佔用空間少,另外是你每一次傳遞lines到其他地方當呼叫next()或者for迴圈時它都是從上一次的位置 繼續向下,這樣對於處理這種dmidecode輸出的有層級關係的非結構化資料比較方便。 """ lines = iter(content.strip().splitlines()) while True: try: line = next(lines) if line.startswith(b'Handle 0x'): typ = int(str(line).split(',', 2)[1].strip()[len('DMI type'):]) if typ in self._DMI_TYPE: if typ not in info: info[self._DMI_TYPE[typ]] = [] info[self._DMI_TYPE[typ]].append(self._parse_handle_section(lines)) else: info[self._DMI_TYPE[typ]].append(self._parse_handle_section(lines)) except StopIteration: break return info except Exception as err: print("Error occured in Function parse_dmi") print(err) def _parse_handle_section(self, lines): """ 解析每個type下面的資訊,也就是每一個 Handle 0x 下面的資訊 :param lines: 傳遞所有的內容進來,也就是之前生成的迭代器,而且這個迭代器是接著上面的位置繼續向後迭代 :return: 字典,每個type下面的子資訊組成的字典 """ data = {} title = str(next(lines).strip().decode(encoding='utf-8')) try: for line in lines: line = line.rstrip() strline = str(line.strip().decode(encoding='utf-8')) if line.startswith(b'\t\t'): data[k].append(strline) elif line.startswith(b'\t'): k, v = str(line.strip().decode(encoding='utf-8')).split(":", 1) if v: data[k] = v.strip() else: data[k] = [] else: break except Exception as err: print("Error occured in Function parse_handle_section") print("Data section is %s " % title) print(err) return data def main(): cmd = "sshpass -p 123456 ssh root@172.16.48.171 '/usr/sbin/dmidecode'" mydmi = Dmidecode() try: completed_process = subprocess.run(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) if completed_process.returncode == 0: data = completed_process.stdout print(mydmi.parse_dmi(data)) else: print("Returncode is not 0") except Exception as err: print(err) if __name__ == "__main__": try: main() finally: sys.exit()