fix: plp 输出展示错误

This commit is contained in:
td-zhangshun 2025-04-23 19:28:02 +08:00 committed by Netlops
parent 3c1cc26896
commit a1c99352a8
5 changed files with 274 additions and 5 deletions

1
.gitignore vendored
View File

@ -22,7 +22,6 @@ mem.pprof
# Go语言相关
*.o
*.a
/pkg/
/vendor/
# IDE和编辑器文件

View File

@ -196,7 +196,7 @@ func (c *Client) MonitorTestStatus(testID string) error {
return
case "integrity":
if info, ok := update.Data.(map[string]interface{}); ok {
c.logger.Infof("数据完整性: 可用块: %.0f, 损坏块: %.0f, 丢失块: %.0f, 数据丢失: %.2f MB",
c.logger.Infof("数据完整性: 可用块: %.0f, 损坏块: %.0f, 没写入块: %.0f, 数据丢失: %.2f MB",
info["available_blocks"], info["corrupted_blocks"], info["missing_blocks"], info["data_loss_mb"])
}
}

View File

@ -487,11 +487,12 @@ func StartServer(cfg *config.Config, runner *TestRunner, logger *logrus.Logger)
// 保存完整性信息
runner.SaveIntegrityInfo(testID, integrityInfo)
// 发送完整性信息
// 发送完整性信息 && BlocksMap 清理掉
integrityInfo.BlocksMap = nil
runner.sendIntegrityUpdate(testID, "数据完整性检查完成", integrityInfo)
logger.Infof("恢复测试完成: 丢失数据: %.2f MB", integrityInfo.DataLossMB)
logger.Infof("恢复测试完成: 没填充的数据: %.2f MB", integrityInfo.DataLossMB)
} else {
logger.Error("不是断电测试实例,无法执行数据完整性检查")
runner.sendErrorUpdate(testID, "不是断电测试实例,无法执行数据完整性检查")

View File

@ -403,7 +403,7 @@ func (t *PowerLossTest) CheckIntegrity() *model.IntegrityInfo {
t.integrityInfo.DataLossMB = utils.BytesToMB((t.integrityInfo.MissingBlocks + t.integrityInfo.CorruptedBlocks) * t.blockSize)
t.integrityInfo.RecoverySuccess = t.integrityInfo.CorruptedBlocks == 0 && t.integrityInfo.MissingBlocks == 0
t.setMessage(fmt.Sprintf("数据完整性检查完成: %d 个块正常, %d 个块丢失, %d 个块损坏",
t.setMessage(fmt.Sprintf("数据完整性检查完成: %d 个块正常, %d 个块没写入, %d 个块损坏",
t.integrityInfo.AvailableBlocks, t.integrityInfo.MissingBlocks, t.integrityInfo.CorruptedBlocks))
return t.integrityInfo

269
pkg/opencastools/opencas.go Normal file
View File

@ -0,0 +1,269 @@
package opencastools
import (
"fmt"
"regexp"
"strings"
"plp-test/internal/utils"
"github.com/sirupsen/logrus"
)
// CacheInstance 表示Open-CAS缓存实例
type CacheInstance struct {
ID string
CacheDevice string
CoreDevice string
CacheMode string
Status string
WritePolicy string
Mounted bool
MountPoint string
}
// OpenCASManager 管理Open-CAS实例
type OpenCASManager struct {
logger *logrus.Logger
}
// NewOpenCASManager 创建OpenCAS管理器
func NewOpenCASManager(logger *logrus.Logger) *OpenCASManager {
return &OpenCASManager{
logger: logger,
}
}
// CreateCacheInstance 创建一个Open-CAS缓存实例
func (m *OpenCASManager) CreateCacheInstance(id string, cacheDevice, coreDevice, cacheMode string) error {
m.logger.Infof("创建缓存实例 %s: 缓存设备=%s, 核心设备=%s, 模式=%s", id, cacheDevice, coreDevice, cacheMode)
// 检查设备是否存在
if !utils.FileExists(cacheDevice) {
return fmt.Errorf("缓存设备不存在: %s", cacheDevice)
}
if !utils.FileExists(coreDevice) {
return fmt.Errorf("核心设备不存在: %s", coreDevice)
}
// 检查设备是否已被使用
output, err := utils.ExecuteCommand("casadm", "-L")
if err == nil && strings.Contains(output, cacheDevice) {
return fmt.Errorf("缓存设备已在使用中: %s", cacheDevice)
}
// 启动缓存
_, err = utils.ExecuteCommand("casadm", "-S", "-d", cacheDevice, "-i", id, "-c", cacheMode)
if err != nil {
msg, err := utils.ExecuteCommand("casadm", "-S", "-d", cacheDevice, "--load")
if err != nil && !strings.Contains(msg, "is already used as cache") {
return fmt.Errorf("启动缓存失败: %v", err)
}
}
// 添加核心设备
msg, err := utils.ExecuteCommand("casadm", "-A", "-i", id, "-d", coreDevice)
if err != nil && !strings.Contains(msg, "Device already added as a core") {
// 如果添加核心设备失败,尝试停止缓存
utils.ExecuteCommand("casadm", "-T", "-i", id)
return fmt.Errorf("添加核心设备失败: %v", err)
}
m.logger.Infof("缓存实例 %s 创建成功", id)
return nil
}
// StopCacheInstance 停止缓存实例
func (m *OpenCASManager) StopCacheInstance(id string) error {
m.logger.Infof("停止缓存实例 %s", id)
_, err := utils.ExecuteCommand("casadm", "-T", "-i", id)
if err != nil {
return fmt.Errorf("停止缓存实例失败: %v", err)
}
return nil
}
// GetCacheStatus 获取缓存状态
func (m *OpenCASManager) GetCacheStatus(id string) (*CacheInstance, error) {
output, err := utils.ExecuteCommand("casadm", "-L")
if err != nil {
return nil, fmt.Errorf("获取缓存状态失败: %v", err)
}
// 解析输出以查找指定ID的缓存实例
lines := strings.Split(output, "\n")
var cacheInfo, coreInfo string
for i, line := range lines {
if strings.Contains(line, "cache "+id) {
if i+1 < len(lines) {
cacheInfo = lines[i+1]
}
}
if strings.Contains(line, "└─") && strings.Contains(line, "core") {
coreInfo = line
}
}
if cacheInfo == "" {
return nil, fmt.Errorf("未找到ID为 %s 的缓存实例", id)
}
// 提取缓存信息
instance := &CacheInstance{
ID: id,
}
// 提取缓存设备
cacheDevicePattern := regexp.MustCompile(`/dev/\w+`)
cacheMatches := cacheDevicePattern.FindStringSubmatch(cacheInfo)
if len(cacheMatches) > 0 {
instance.CacheDevice = cacheMatches[0]
}
// 提取核心设备
coreMatches := cacheDevicePattern.FindStringSubmatch(coreInfo)
if len(coreMatches) > 0 {
instance.CoreDevice = coreMatches[0]
}
// 提取缓存模式
if strings.Contains(cacheInfo, "wb") {
instance.CacheMode = "Write-Back"
instance.WritePolicy = "Write-Back"
} else if strings.Contains(cacheInfo, "wt") {
instance.CacheMode = "Write-Through"
instance.WritePolicy = "Write-Through"
} else if strings.Contains(cacheInfo, "wo") {
instance.CacheMode = "Write-Only"
instance.WritePolicy = "Write-Only"
} else if strings.Contains(cacheInfo, "pt") {
instance.CacheMode = "Pass-Through"
instance.WritePolicy = "Pass-Through"
}
// 检查状态
if strings.Contains(cacheInfo, "Running") {
instance.Status = "Running"
} else if strings.Contains(cacheInfo, "Stopping") {
instance.Status = "Stopping"
} else {
instance.Status = "Unknown"
}
// 检查是否已挂载
cacheDevicePath := fmt.Sprintf("/dev/cas%s-1", id)
instance.Mounted = utils.IsMounted(cacheDevicePath)
// 如果已挂载,尝试获取挂载点
if instance.Mounted {
output, err := utils.ExecuteCommand("mount")
if err == nil {
lines = strings.Split(output, "\n")
for _, line := range lines {
if strings.Contains(line, cacheDevicePath) {
parts := strings.Split(line, " ")
if len(parts) > 2 {
instance.MountPoint = parts[2]
}
}
}
}
}
return instance, nil
}
// FlushCache 刷新缓存数据
func (m *OpenCASManager) FlushCache(id string) error {
m.logger.Infof("刷新缓存实例 %s 的数据", id)
_, err := utils.ExecuteCommand("casadm", "-F", "-i", id)
if err != nil {
return fmt.Errorf("刷新缓存失败: %v", err)
}
return nil
}
// GetStats 获取缓存统计信息
func (m *OpenCASManager) GetStats(id string) (string, error) {
output, err := utils.ExecuteCommand("casadm", "-P", "-i", id, "--stats")
if err != nil {
return "", fmt.Errorf("获取缓存统计信息失败: %v", err)
}
return output, nil
}
// FormatDevice 格式化设备
func (m *OpenCASManager) FormatDevice(device, fsType string) error {
m.logger.Infof("格式化设备 %s 为 %s 文件系统", device, fsType)
_, err := utils.ExecuteCommand("mkfs", "-t", fsType, device)
if err != nil {
return fmt.Errorf("格式化设备失败: %v", err)
}
return nil
}
// MountDevice 挂载设备
func (m *OpenCASManager) MountDevice(device, mountPoint string) error {
m.logger.Infof("挂载设备 %s 到 %s", device, mountPoint)
// 确保挂载点存在
err := utils.CreateDirIfNotExist(mountPoint)
if err != nil {
return fmt.Errorf("创建挂载点失败: %v", err)
}
// 执行挂载
_, err = utils.ExecuteCommand("mount", device, mountPoint)
if err != nil {
return fmt.Errorf("挂载设备失败: %v", err)
}
return nil
}
// UnmountDevice 卸载设备
func (m *OpenCASManager) UnmountDevice(mountPoint string) error {
m.logger.Infof("卸载挂载点 %s", mountPoint)
_, err := utils.ExecuteCommand("umount", mountPoint)
if err != nil {
return fmt.Errorf("卸载设备失败: %v", err)
}
return nil
}
// SimulatePowerCut 模拟断电
func (m *OpenCASManager) SimulatePowerCut(id string) error {
m.logger.Warn("模拟断电,将强制停止缓存实例 %s", id)
// 获取缓存状态
instance, err := m.GetCacheStatus(id)
if err != nil {
return fmt.Errorf("获取缓存状态失败: %v", err)
}
// 如果已挂载,先卸载
if instance.Mounted && instance.MountPoint != "" {
err = m.UnmountDevice(instance.MountPoint)
if err != nil {
m.logger.Warn("卸载设备失败,继续强制停止: %v", err)
}
}
// 强制停止缓存,模拟断电
_, err = utils.ExecuteCommand("casadm", "-T", "-i", id, "-f")
if err != nil {
return fmt.Errorf("模拟断电失败: %v", err)
}
m.logger.Info("模拟断电完成")
return nil
}
// RepairCache 尝试修复损坏的缓存
func (m *OpenCASManager) RepairCache(id string, cacheDevice string) error {
m.logger.Info("尝试修复缓存实例 %s", id)
_, err := utils.ExecuteCommand("casadm", "-L", "-i", id, "-d", cacheDevice)
if err != nil {
return fmt.Errorf("修复缓存失败: %v", err)
}
return nil
}