This commit is contained in:
root
2026-02-10 02:54:13 +08:00
parent 4a59323398
commit 64bfd85368
22 changed files with 2572 additions and 422 deletions

View File

@@ -4,6 +4,7 @@ import json
import logging
import re
import os
from system_compat import get_system_compat
logger = logging.getLogger(__name__)
@@ -26,20 +27,26 @@ class SystemInfoManager:
logger.debug(f"运行命令: {' '.join(command_list)}")
try:
# Python 3.6 兼容: 使用 stdout/stderr 参数代替 capture_output
# Python 3.6 兼容: 不使用 text 参数,手动解码
result = subprocess.run(
command_list,
capture_output=check_output,
text=True,
stdout=subprocess.PIPE if check_output else None,
stderr=subprocess.PIPE if check_output else None,
stdin=subprocess.PIPE if input_data else None,
check=True,
encoding='utf-8',
encoding='utf-8' if check_output else None,
input=input_data
)
return result.stdout if check_output else "", result.stderr if check_output else ""
if check_output:
return result.stdout, result.stderr
else:
return "", ""
except subprocess.CalledProcessError as e:
logger.error(f"命令执行失败: {' '.join(command_list)}")
logger.error(f"退出码: {e.returncode}")
logger.error(f"标准输出: {e.stdout.strip()}")
logger.error(f"标准错误: {e.stderr.strip()}")
logger.error(f"标准输出: {e.stdout.strip() if e.stdout else ''}")
logger.error(f"标准错误: {e.stderr.strip() if e.stderr else ''}")
raise
except FileNotFoundError:
logger.error(f"命令 '{command_list[0]}' 未找到。请确保已安装相关工具。")
@@ -52,33 +59,32 @@ class SystemInfoManager:
"""
使用 lsblk 获取块设备信息。
返回一个字典列表,每个字典代表一个设备。
自动适配不同系统的 lsblk 版本。
"""
cmd = [
"lsblk", "-J", "-o",
"NAME,FSTYPE,SIZE,MOUNTPOINT,RO,TYPE,UUID,PARTUUID,VENDOR,MODEL,SERIAL,MAJ:MIN,PKNAME,PATH"
]
try:
# 使用兼容性模块获取适当的命令
compat = get_system_compat()
cmd, need_manual_parse = compat.get_lsblk_command()
stdout, _ = self._run_command(cmd)
data = json.loads(stdout)
devices = data.get('blockdevices', [])
def add_path_recursive(dev_list):
devices = compat.parse_lsblk_output(stdout, need_manual_parse)
# 统一处理 path 字段
def normalize_path_recursive(dev_list):
for dev in dev_list:
if 'PATH' not in dev and 'NAME' in dev:
dev['PATH'] = f"/dev/{dev['NAME']}"
# Rename PATH to path (lowercase) for consistency
if 'path' not in dev and 'name' in dev:
dev['path'] = f"/dev/{dev['name']}"
if 'PATH' in dev:
dev['path'] = dev.pop('PATH')
if 'children' in dev:
add_path_recursive(dev['children'])
add_path_recursive(devices)
normalize_path_recursive(dev['children'])
normalize_path_recursive(devices)
return devices
except subprocess.CalledProcessError as e:
logger.error(f"获取块设备信息失败: {e.stderr.strip()}")
return []
except json.JSONDecodeError as e:
logger.error(f"解析 lsblk JSON 输出失败: {e}")
return []
except Exception as e:
logger.error(f"获取块设备信息失败 (未知错误): {e}")
return []
@@ -419,85 +425,50 @@ class SystemInfoManager:
def get_lvm_info(self):
"""
获取 LVM 物理卷 (PVs)、卷组 (VGs) 和逻辑卷 (LVs) 的信息。
自动适配不同系统的 LVM 版本。
"""
lvm_info = {'pvs': [], 'vgs': [], 'lvs': []}
# 使用兼容性模块获取适当的命令
compat = get_system_compat()
commands = compat.get_lvm_commands()
# Get PVs
try:
stdout, stderr = self._run_command(["pvs", "--reportformat", "json"])
data = json.loads(stdout)
if 'report' in data and data['report']:
for pv_data in data['report'][0].get('pv', []):
lvm_info['pvs'].append({
'pv_name': pv_data.get('pv_name'),
'vg_name': pv_data.get('vg_name'),
'pv_uuid': pv_data.get('pv_uuid'),
'pv_size': pv_data.get('pv_size'),
'pv_free': pv_data.get('pv_free'),
'pv_attr': pv_data.get('pv_attr'),
'pv_fmt': pv_data.get('pv_fmt')
})
cmd, need_manual_parse = commands['pvs']
stdout, stderr = self._run_command(cmd)
lvm_info['pvs'] = compat.parse_pvs_output(stdout, need_manual_parse)
except subprocess.CalledProcessError as e:
if "No physical volume found" in e.stderr or "No physical volumes found" in e.stdout:
logger.info("未找到任何LVM物理卷。")
else:
logger.error(f"获取LVM物理卷信息失败: {e.stderr.strip()}")
except json.JSONDecodeError as e:
logger.error(f"解析LVM物理卷JSON输出失败: {e}")
except Exception as e:
logger.error(f"获取LVM物理卷信息失败 (未知错误): {e}")
# Get VGs
try:
stdout, stderr = self._run_command(["vgs", "--reportformat", "json"])
data = json.loads(stdout)
if 'report' in data and data['report']:
for vg_data in data['report'][0].get('vg', []):
lvm_info['vgs'].append({
'vg_name': vg_data.get('vg_name'),
'vg_uuid': vg_data.get('vg_uuid'),
'vg_size': vg_data.get('vg_size'),
'vg_free': vg_data.get('vg_free'),
'vg_attr': vg_data.get('vg_attr'),
'pv_count': vg_data.get('pv_count'),
'lv_count': vg_data.get('lv_count'),
'vg_alloc_percent': vg_data.get('vg_alloc_percent'),
'vg_fmt': vg_data.get('vg_fmt')
})
cmd, need_manual_parse = commands['vgs']
stdout, stderr = self._run_command(cmd)
lvm_info['vgs'] = compat.parse_vgs_output(stdout, need_manual_parse)
except subprocess.CalledProcessError as e:
if "No volume group found" in e.stderr or "No volume groups found" in e.stdout:
logger.info("未找到任何LVM卷组。")
else:
logger.error(f"获取LVM卷组信息失败: {e.stderr.strip()}")
except json.JSONDecodeError as e:
logger.error(f"解析LVM卷组JSON输出失败: {e}")
except Exception as e:
logger.error(f"获取LVM卷组信息失败 (未知错误): {e}")
# Get LVs (MODIFIED: added -o lv_path)
# Get LVs
try:
# 明确请求 lv_path因为默认的 --reportformat json 不包含它
stdout, stderr = self._run_command(["lvs", "-o", "lv_name,vg_name,lv_uuid,lv_size,lv_attr,origin,snap_percent,lv_path", "--reportformat", "json"])
data = json.loads(stdout)
if 'report' in data and data['report']:
for lv_data in data['report'][0].get('lv', []):
lvm_info['lvs'].append({
'lv_name': lv_data.get('lv_name'),
'vg_name': lv_data.get('vg_name'),
'lv_uuid': lv_data.get('lv_uuid'),
'lv_size': lv_data.get('lv_size'),
'lv_attr': lv_data.get('lv_attr'),
'origin': lv_data.get('origin'),
'snap_percent': lv_data.get('snap_percent'),
'lv_path': lv_data.get('lv_path') # 现在应该能正确获取到路径了
})
cmd, need_manual_parse = commands['lvs']
stdout, stderr = self._run_command(cmd)
lvm_info['lvs'] = compat.parse_lvs_output(stdout, need_manual_parse)
except subprocess.CalledProcessError as e:
if "No logical volume found" in e.stderr or "No logical volumes found" in e.stdout:
logger.info("未找到任何LVM逻辑卷。")
else:
logger.error(f"获取LVM逻辑卷信息失败: {e.stderr.strip()}")
except json.JSONDecodeError as e:
logger.error(f"解析LVM逻辑卷JSON输出失败: {e}")
except Exception as e:
logger.error(f"获取LVM逻辑卷信息失败 (未知错误): {e}")