From 32848a7e3647eaab402a3236c26b2fe5be1ac26c Mon Sep 17 00:00:00 2001 From: hewanhan Date: Wed, 24 Sep 2025 16:19:05 +0800 Subject: [PATCH] sync patch and add bmc_block_io spec. --- add-bmc_block_io.patch | 1415 ++++++++++++++++++++++++++++++++++++++++ sysSentry.spec | 26 +- 2 files changed, 1440 insertions(+), 1 deletion(-) create mode 100644 add-bmc_block_io.patch diff --git a/add-bmc_block_io.patch b/add-bmc_block_io.patch new file mode 100644 index 0000000..3047b97 --- /dev/null +++ b/add-bmc_block_io.patch @@ -0,0 +1,1415 @@ +From f3135da8e00fc66d26ad686562d6e20e82eb3a79 Mon Sep 17 00:00:00 2001 +From: hewanhan +Date: Wed, 24 Sep 2025 14:41:40 +0800 +Subject: [PATCH] add bmc_block_io. + +--- + Makefile | 16 +- + config/plugins/bmc_block_io.ini | 5 + + config/tasks/bmc_block_io.mod | 7 + + src/sentryPlugins/bmc_block_io/CMakeLists.txt | 26 ++ + src/sentryPlugins/bmc_block_io/build.sh | 26 ++ + .../bmc_block_io/include/cbmcblockio.h | 70 +++ + .../bmc_block_io/include/common.h | 45 ++ + .../bmc_block_io/include/configure.h | 26 ++ + .../bmc_block_io/include/logger.h | 91 ++++ + .../bmc_block_io/src/cbmcblockio.cpp | 432 ++++++++++++++++++ + src/sentryPlugins/bmc_block_io/src/common.cpp | 237 ++++++++++ + src/sentryPlugins/bmc_block_io/src/logger.cpp | 155 +++++++ + src/sentryPlugins/bmc_block_io/src/main.cpp | 128 ++++++ + 13 files changed, 1262 insertions(+), 2 deletions(-) + create mode 100644 config/plugins/bmc_block_io.ini + create mode 100644 config/tasks/bmc_block_io.mod + create mode 100644 src/sentryPlugins/bmc_block_io/CMakeLists.txt + create mode 100644 src/sentryPlugins/bmc_block_io/build.sh + create mode 100644 src/sentryPlugins/bmc_block_io/include/cbmcblockio.h + create mode 100644 src/sentryPlugins/bmc_block_io/include/common.h + create mode 100644 src/sentryPlugins/bmc_block_io/include/configure.h + create mode 100644 src/sentryPlugins/bmc_block_io/include/logger.h + create mode 100644 src/sentryPlugins/bmc_block_io/src/cbmcblockio.cpp + create mode 100644 src/sentryPlugins/bmc_block_io/src/common.cpp + create mode 100644 src/sentryPlugins/bmc_block_io/src/logger.cpp + create mode 100644 src/sentryPlugins/bmc_block_io/src/main.cpp + +diff --git a/Makefile b/Makefile +index ca2b836..54e62f4 100644 +--- a/Makefile ++++ b/Makefile +@@ -27,7 +27,7 @@ PYTHON_VERSION := $(shell $(PYBIN) --version 2>&1 | awk '{print $$2}' | cut -d ' + PKGVER := syssentry-$(VERSION)-py$(PYTHON_VERSION) + PKGVEREGG := syssentry-$(VERSION)-py$(PYTHON_VERSION).egg-info + +-all: lib ebpf hbm_online_repair sentry_msg_monitor ++all: lib ebpf hbm_online_repair sentry_msg_monitor bmc_block_io + + lib:libxalarm log + +@@ -50,6 +50,9 @@ hbm_online_repair: + sentry_msg_monitor: lib + cd $(CURSRCDIR)/sentryPlugins/sentry_msg_monitor/ && make + ++bmc_block_io: lib ++ cd $(CURSRCDIR)/sentryPlugins/bmc_block_io/ && sh build.sh ++ + install: all dirs isentry + + dirs: +@@ -131,6 +134,11 @@ isentry: + install -m 600 $(CURCONFIGDIR)/env/sentry_msg_monitor.env $(ETCDIR)/sysconfig/ + install -m 600 $(CURCONFIGDIR)/tasks/sentry_msg_monitor.mod $(ETCDIR)/sysSentry/tasks/ + ++ # bmc_block_io ++ install -m 550 $(CURSRCDIR)/sentryPlugins/bmc_block_io/output/bmc_block_io $(BINDIR) ++ install -m 600 $(CURCONFIGDIR)/plugins/bmc_block_io.ini $(ETCDIR)/sysSentry/plugins/ ++ install -m 600 $(CURCONFIGDIR)/tasks/bmc_block_io.mod $(ETCDIR)/sysSentry/tasks/ ++ + # pysentry_notify + install -m 550 src/libsentry/python/pySentryNotify/sentry_notify.py $(PYDIR)/xalarm + +@@ -161,7 +169,10 @@ hbm_clean: + smm_clean: + cd $(CURSRCDIR)/sentryPlugins/sentry_msg_monitor && make clean + +-clean: ebpf_clean hbm_clean smm_clean ++bmc_clean: ++ cd $(CURSRCDIR)/sentryPlugins/bmc_block_io && sh build.sh clean ++ ++clean: ebpf_clean hbm_clean smm_clean bmc_clean + rm -rf $(CURLIBDIR)/build + rm -rf $(CURSRCDIR)/build + rm -rf $(CURSRCDIR)/libsentry/c/log/build +@@ -175,6 +186,7 @@ uninstall: + rm -rf $(BINDIR)/sentryCollector + rm -rf $(BINDIR)/hbm_online_repair + rm -rf $(BINDIR)/sentry_msg_monitor ++ rm -rf $(BINDIR)/bmc_block_io + rm -rf $(BINDIR)/ebpf_collector + rm -rf $(LIBINSTALLDIR)/libxalarm.so + rm -rf $(INCLUDEDIR)/xalarm +diff --git a/config/plugins/bmc_block_io.ini b/config/plugins/bmc_block_io.ini +new file mode 100644 +index 0000000..467abd5 +--- /dev/null ++++ b/config/plugins/bmc_block_io.ini +@@ -0,0 +1,5 @@ ++# log level, accepts debug, info, warning, error or critical ++log_level=info ++ ++# polling cycle, unit: seconds, range: [60, 3600] ++patrol_second=60 +\ No newline at end of file +diff --git a/config/tasks/bmc_block_io.mod b/config/tasks/bmc_block_io.mod +new file mode 100644 +index 0000000..e07350c +--- /dev/null ++++ b/config/tasks/bmc_block_io.mod +@@ -0,0 +1,7 @@ ++[common] ++enabled=yes ++task_start=/usr/bin/bmc_block_io ++task_stop=kill $pid ++type=oneshot ++alarm_id=1002 ++alarm_clear_time=5 +\ No newline at end of file +diff --git a/src/sentryPlugins/bmc_block_io/CMakeLists.txt b/src/sentryPlugins/bmc_block_io/CMakeLists.txt +new file mode 100644 +index 0000000..bdae73b +--- /dev/null ++++ b/src/sentryPlugins/bmc_block_io/CMakeLists.txt +@@ -0,0 +1,26 @@ ++cmake_minimum_required (VERSION 3.12) ++project(bmc_block_io) ++ ++set(CMAKE_CXX_STANDARD 14) ++set(CMAKE_CXX_STANDARD_REQUIRED ON) ++ ++set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/output) ++ ++set(CMAKE_SKIP_BUILD_RPATH TRUE) ++set(CMAKE_SKIP_INSTALL_RPATH TRUE) ++ ++include_directories( ++ ${CMAKE_SOURCE_DIR}/include ++ ${CMAKE_SOURCE_DIR}/../../libs/libxalarm ++) ++link_directories( ++ ${CMAKE_CURRENT_SOURCE_DIR}/../../libs/build/libxalarm ++) ++ ++set(SOURCE src/main.cpp ++ src/logger.cpp ++ src/common.cpp ++ src/cbmcblockio.cpp) ++ ++add_executable(bmc_block_io ${SOURCE}) ++target_link_libraries(bmc_block_io PRIVATE xalarm pthread json-c) +diff --git a/src/sentryPlugins/bmc_block_io/build.sh b/src/sentryPlugins/bmc_block_io/build.sh +new file mode 100644 +index 0000000..8db398c +--- /dev/null ++++ b/src/sentryPlugins/bmc_block_io/build.sh +@@ -0,0 +1,26 @@ ++#!/bin/sh ++echo "----------build begin------------" ++echo "---------------------------------" ++ ++BUILD_DIR=build ++ ++if [ "$1" = "clean" ]; then ++ if [ -d "$BUILD_DIR" ]; then ++ echo "----------clean begin------------" ++ cd "$BUILD_DIR" && make clean ++ echo "----------clean end--------------" ++ else ++ echo "Build directory does not exist. Nothing to clean." ++ fi ++ exit 0 ++fi ++ ++[ ! -d $BUILD_DIR ] && mkdir -p $BUILD_DIR ++cd $BUILD_DIR ++ ++cmake .. ++make || exit "$?" ++ ++echo "------- build end -----------" ++echo "-----------------------------" ++exit 0 +\ No newline at end of file +diff --git a/src/sentryPlugins/bmc_block_io/include/cbmcblockio.h b/src/sentryPlugins/bmc_block_io/include/cbmcblockio.h +new file mode 100644 +index 0000000..04e526d +--- /dev/null ++++ b/src/sentryPlugins/bmc_block_io/include/cbmcblockio.h +@@ -0,0 +1,70 @@ ++/* ++ * Copyright (c) Huawei Technologies Co., Ltd. 2025. All rights reserved. ++ * bmc_block_io is licensed under Mulan PSL v2. ++ * You can use this software according to the terms and conditions of the Mulan PSL v2. ++ * Author: hewanhan@h-partners.com ++ */ ++ ++#ifndef _BMC_BLOCK_IO_H_ ++#define _BMC_BLOCK_IO_H_ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++namespace BMCBlockIoPlu { ++ ++struct ResponseHeader { ++ uint16_t totalEvents; ++ uint8_t eventCount; ++ bool valid; ++}; ++ ++struct IPMIEvent { ++ uint32_t alarmTypeCode; ++ uint32_t timestamp; ++ uint8_t severity; ++ uint8_t subjectType; ++ uint8_t deviceId; ++ bool valid; ++}; ++ ++class CBMCBlockIo { ++public: ++ CBMCBlockIo(); ++ ~CBMCBlockIo(); ++ void Start(); ++ void Stop(); ++ void SetPatrolInterval(int seconds); ++ bool IsRunning(); ++private: ++ void SentryWorker(); ++ void GetBMCIp(); ++ void ReportAlarm(const IPMIEvent& event); ++ void ReportResult(int resultLevel, const std::string& msg); ++ int QueryEvents(); ++ std::string BuildIPMICommand(uint16_t startIndex); ++ std::vector ExecuteIPMICommand(const std::string& cmd); ++ ResponseHeader ParseResponseHeader(const std::vector& hexBytes); ++ IPMIEvent ParseSingleEvent(const std::vector& hexBytes, size_t startPos); ++ void ProcessEvents(const std::vector& hexBytes, uint8_t eventCount); ++ ++private: ++ std::atomic m_running; ++ std::thread m_worker; ++ std::mutex m_mutex; ++ std::condition_variable m_cv; ++ std::string m_bmcIp; ++ std::set m_lastDeviceIds; ++ std::set m_currentDeviceIds; ++ int m_patrolSeconds; ++ int m_alarmId; ++}; ++} ++#endif ++ +diff --git a/src/sentryPlugins/bmc_block_io/include/common.h b/src/sentryPlugins/bmc_block_io/include/common.h +new file mode 100644 +index 0000000..e36e9e7 +--- /dev/null ++++ b/src/sentryPlugins/bmc_block_io/include/common.h +@@ -0,0 +1,45 @@ ++/* ++ * Copyright (c) Huawei Technologies Co., Ltd. 2025. All rights reserved. ++ * bmc_block_io is licensed under Mulan PSL v2. ++ * You can use this software according to the terms and conditions of the Mulan PSL v2. ++ * Author: hewanhan@h-partners.com ++ */ ++ ++#ifndef _BMCPLU_COMMON_H_ ++#define _BMCPLU_COMMON_H_ ++ ++#include ++#include ++#include ++#include ++#include ++#include "configure.h" ++#include "logger.h" ++ ++#define BMCPLU_FAILED (-1) ++#define BMCPLU_SUCCESS (0) ++ ++struct PluConfig { ++ BMCBlockIoPlu::Logger::Level logLevel; ++ int patrolSeconds; ++}; ++ ++struct ConfigItem { ++ bool required; ++ bool found; ++ std::function processor; ++}; ++ ++namespace BMCBlockIoPlu { ++ ++std::string Trim(const std::string& str); ++bool IsValidNumber(const std::string& str, int& num); ++int ParseConfig(const std::string& path, PluConfig& config); ++std::map> parseModConfig(const std::string& path); ++std::string ExtractFileName(const std::string& path); ++int ExecCommand(const std::string& cmd, std::vector& result); ++std::string ByteToHex(uint8_t byte); ++std::vector SplitString(const std::string& str, const std::string& split); ++} ++ ++#endif +diff --git a/src/sentryPlugins/bmc_block_io/include/configure.h b/src/sentryPlugins/bmc_block_io/include/configure.h +new file mode 100644 +index 0000000..0b43209 +--- /dev/null ++++ b/src/sentryPlugins/bmc_block_io/include/configure.h +@@ -0,0 +1,26 @@ ++/* ++ * Copyright (c) Huawei Technologies Co., Ltd. 2025. All rights reserved. ++ * bmc_block_io is licensed under Mulan PSL v2. ++ * You can use this software according to the terms and conditions of the Mulan PSL v2. ++ * Author: hewanhan@h-partners.com ++ */ ++ ++#ifndef _BMCPLU_CONFIGURE_H_ ++#define _BMCPLU_CONFIGURE_H_ ++ ++#include ++ ++namespace BMCBlockIoPlu { ++ ++const std::string BMCPLU_CONFIG_PATH = "/etc/sysSentry/plugins/bmc_block_io.ini"; ++const std::string BMCPLU_LOG_PATH = "/var/log/sysSentry/bmc_block_io.log"; ++const std::string BMCPLU_MOD_CONFIG = "/etc/sysSentry/tasks/bmc_block_io.mod"; ++const int BMCPLU_PATROL_MIN = 60; ++const int BMCPLU_PATROL_MAX = 3600; ++const int BMCPLU_PATROL_DEFAULT = 300; ++const int BMCPLU_CONFIG_CHECK_CYCLE = 10; // seconds ++const int BMCPLU_DEFAULT_SLEEP_CYCLE = 3; // seconds ++const int BMCPLU_LOGFILE_CHECK_CYCLE = 30; // second ++const int BMCPLU_DEFAULT_ALARM_ID = 1002; ++} ++#endif +diff --git a/src/sentryPlugins/bmc_block_io/include/logger.h b/src/sentryPlugins/bmc_block_io/include/logger.h +new file mode 100644 +index 0000000..731b2b2 +--- /dev/null ++++ b/src/sentryPlugins/bmc_block_io/include/logger.h +@@ -0,0 +1,91 @@ ++/* ++ * Copyright (c) Huawei Technologies Co., Ltd. 2025. All rights reserved. ++ * bmc_block_io is licensed under Mulan PSL v2. ++ * You can use this software according to the terms and conditions of the Mulan PSL v2. ++ * Author: hewanhan@h-partners.com ++ */ ++ ++#ifndef __BMCPLU_LOGGER_H__ ++#define __BMCPLU_LOGGER_H__ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++namespace BMCBlockIoPlu { ++ ++class Logger { ++public: ++ enum class Level { ++ Debug, ++ Info, ++ Warning, ++ Error, ++ Critical ++ }; ++ static Logger& GetInstance(); ++ Logger(const Logger&) = delete; ++ Logger& operator=(const Logger&) = delete; ++ bool Initialize(const std::string& logPath, Level level = Level::Info); ++ void SetLevel(Level level); ++ Level GetLevel() const; ++ void WriteLog(Level level, const char* file, int line, const std::string& message); ++ std::string LevelToString(Level level) const; ++private: ++ Logger() = default; ++ void OpenLogFile(); ++ void CheckFileState(); ++ void ReopenLogFile(); ++ std::string GetTimeStamp() const; ++ std::string Format(Level level, const char* file, int line, const std::string& message) const; ++ ++private: ++ std::ofstream m_logFile; ++ std::string m_logPath; ++ Level m_level = Level::Info; ++ mutable std::mutex m_writeMutex; ++ std::time_t m_checkTime = 0; ++ ino_t m_inode = 0; ++ dev_t m_device = 0; ++ off_t m_fileSize = 0; ++ bool m_fileOpen = false; ++}; ++ ++class LogStream { ++public: ++ LogStream(Logger::Level level, const char* file, int line) ++ : m_level(level), m_file(file), m_line(line) ++ {} ++ ~LogStream() ++ { ++ Logger::GetInstance().WriteLog(m_level, m_file, m_line, m_stream.str()); ++ } ++ template ++ LogStream& operator<<(const T& value) ++ { ++ m_stream << value; ++ return *this; ++ } ++ LogStream& operator<<(std::ostream& (*manip)(std::ostream&)) // std::endl, std::flush... ++ { ++ m_stream << manip; ++ return *this; ++ } ++ ++private: ++ Logger::Level m_level; ++ const char* m_file; ++ int m_line; ++ std::ostringstream m_stream; ++}; ++ ++#define BMC_LOG_DEBUG BMCBlockIoPlu::LogStream(BMCBlockIoPlu::Logger::Level::Debug, __FILE__, __LINE__) ++#define BMC_LOG_INFO BMCBlockIoPlu::LogStream(BMCBlockIoPlu::Logger::Level::Info, __FILE__, __LINE__) ++#define BMC_LOG_WARNING BMCBlockIoPlu::LogStream(BMCBlockIoPlu::Logger::Level::Warning, __FILE__, __LINE__) ++#define BMC_LOG_ERROR BMCBlockIoPlu::LogStream(BMCBlockIoPlu::Logger::Level::Error, __FILE__, __LINE__) ++#define BMC_LOG_CRITICAL BMCBlockIoPlu::LogStream(BMCBlockIoPlu::Logger::Level::Critical, __FILE__, __LINE__) ++} ++#endif +\ No newline at end of file +diff --git a/src/sentryPlugins/bmc_block_io/src/cbmcblockio.cpp b/src/sentryPlugins/bmc_block_io/src/cbmcblockio.cpp +new file mode 100644 +index 0000000..5d64bde +--- /dev/null ++++ b/src/sentryPlugins/bmc_block_io/src/cbmcblockio.cpp +@@ -0,0 +1,432 @@ ++/* ++ * Copyright (c) Huawei Technologies Co., Ltd. 2025. All rights reserved. ++ * bmc_block_io is licensed under Mulan PSL v2. ++ * You can use this software according to the terms and conditions of the Mulan PSL v2. ++ * Author: hewanhan@h-partners.com ++ */ ++ ++#include "cbmcblockio.h" ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++extern "C" { ++#include "register_xalarm.h" ++} ++#include "common.h" ++#include "configure.h" ++#include "logger.h" ++ ++namespace BMCBlockIoPlu { ++ ++const int RESP_HEADER_SIZE = 7; ++const int EVENT_SIZE = 15; ++const uint32_t ALARM_OCCUR_CODE = 0x02000039; ++const uint32_t ALARM_CLEAR_CODE = 0x0200003A; ++const std::string BMC_TASK_NAME = "bmc_block_io"; ++const std::string GET_BMCIP_CMD = "ipmitool lan print"; ++const std::string IPMI_KEY_IP_ADDR = "IP Address"; ++const std::string MSG_BMCIP_EMPTY = "ipmitool get bmc ip failed."; ++const std::string MSG_BMC_QUERY_FAIL = "ipmitool query failed."; ++const std::string MSG_EXIT_SUCCESS = "receive exit signal, task completed."; ++const std::string JSON_KEY_MSG = "msg"; ++const std::string JSON_KEY_ALARM_SOURCE = "alarm_source"; ++const std::string JSON_KEY_DRIVER_NAME = "driver_name"; ++const std::string JSON_KEY_IO_TYPE = "io_type"; ++const std::string JSON_KEY_REASON = "reason"; ++const std::string JSON_KEY_BLOCK_STACK = "block_stack"; ++const std::string JSON_KEY_DETAILS = "details"; ++const std::string MOD_SECTION_COMMON = "common"; ++const std::string MOD_COMMON_ALARM_ID = "alarm_id"; ++ ++CBMCBlockIo::CBMCBlockIo() : ++ m_running(false), ++ m_patrolSeconds(BMCPLU_PATROL_DEFAULT) ++{ ++ std::map> modConfig = parseModConfig(BMCPLU_MOD_CONFIG); ++ if (modConfig.find(MOD_SECTION_COMMON) != modConfig.end()) { ++ auto commonSection = modConfig[MOD_SECTION_COMMON]; ++ if (commonSection.find(MOD_COMMON_ALARM_ID) != commonSection.end()) { ++ int alarmId = 0; ++ if (IsValidNumber(commonSection[MOD_COMMON_ALARM_ID], alarmId) && alarmId > 0) { ++ m_alarmId = alarmId; ++ } else { ++ m_alarmId = BMCPLU_DEFAULT_ALARM_ID; ++ BMC_LOG_WARNING << "Invalid alarm_id in mod config, use default alarm id: " << BMCPLU_DEFAULT_ALARM_ID; ++ } ++ } ++ } ++} ++ ++CBMCBlockIo::~CBMCBlockIo() ++{ ++} ++ ++void CBMCBlockIo::Start() ++{ ++ if (m_running) { ++ return; ++ } ++ ++ GetBMCIp(); ++ if (m_bmcIp.empty()) { ++ BMC_LOG_ERROR << "BMC Ip is empty."; ++ ReportResult(RESULT_LEVEL_FAIL, MSG_BMCIP_EMPTY); ++ return; ++ } ++ m_running = true; ++ m_worker = std::thread(&CBMCBlockIo::SentryWorker, this); ++ BMC_LOG_INFO << "BMC block io Start."; ++} ++ ++void CBMCBlockIo::Stop() ++{ ++ { ++ std::lock_guard lock(m_mutex); ++ m_running = false; ++ } ++ m_cv.notify_all(); ++ ++ if (m_worker.joinable()) { ++ m_worker.join(); ++ } ++ BMC_LOG_INFO <<"BMC block io Stop."; ++} ++ ++void CBMCBlockIo::SetPatrolInterval(int seconds) ++{ ++ m_patrolSeconds = seconds; ++} ++ ++bool CBMCBlockIo::IsRunning() ++{ ++ return m_running; ++} ++ ++void CBMCBlockIo::SentryWorker() ++{ ++ int ret = BMCPLU_SUCCESS; ++ while (m_running) { ++ std::unique_lock lock(m_mutex); ++ m_cv.wait_for(lock, std::chrono::seconds(m_patrolSeconds), [this] { ++ return !m_running; ++ }); ++ ++ if (!m_running) { ++ break; ++ } ++ ret = QueryEvents(); ++ if (ret != BMCPLU_SUCCESS) { ++ break; ++ } ++ } ++ ++ if (ret == BMCPLU_SUCCESS) { ++ ReportResult(RESULT_LEVEL_PASS, MSG_EXIT_SUCCESS); ++ } else { ++ ReportResult(RESULT_LEVEL_FAIL, MSG_BMC_QUERY_FAIL); ++ } ++ m_running = false; ++ BMC_LOG_INFO << "BMC block io SentryWorker exit."; ++ return; ++} ++ ++void CBMCBlockIo::GetBMCIp() ++{ ++ std::vector result; ++ if (ExecCommand(GET_BMCIP_CMD, result)) { ++ return; ++ } ++ for (const auto& iter: result) { ++ if (iter.find(IPMI_KEY_IP_ADDR) != std::string::npos) { ++ size_t eq_pos = iter.find(':'); ++ if (eq_pos != std::string::npos) { ++ std::string key = Trim(iter.substr(0, eq_pos)); ++ std::string value = Trim(iter.substr(eq_pos + 1)); ++ if (key == IPMI_KEY_IP_ADDR) { ++ m_bmcIp = value; ++ return; ++ } ++ } ++ } ++ } ++ return; ++} ++ ++/***** ipml protocol *****/ ++/* ++请求 字节顺序 含义 ++ 1-3 厂商id 默认0xDB 0x07 0x0 ++ 4 子命令 默认0x40 ++ 5 请求类型 默认0x00 ++ 6-7 需要查询的事件起始编号,某些情况下查询到的事件可能有多条, ++ 单次响应无法全部返回,因此需要修改该值分页查询 ++ 8 事件严重级别 位图形式,bit0-normal,bit1-minor,bit2-major,bit3-critical,慢盘事件只支持normal ++ 9 主体类型 硬盘类型0x02 ++响应 字节顺序 含义 ++ 1 completion code 调用成功时该字节不会显示在终端上 ++ 2-4 厂商ID,对应请求中内容 ++ 5-6 事件总数量 ++ 7 本次返回中包含的事件数量 ++ 8 占位字节,默认0 ++ 9-12 告警类型码,0x0200039为告警产生,0x0200003A为告警消除 ++ 13-16 事件发生的linux时间戳 ++ 17 事件严重级别,0-normal,1-minor,2-major,3-critical ++ 18 主体类型,对应请求中内容 ++ 19 设备序号 带外编号 ++ 20-23 占位字节,默认0 ++ N+1-N+15重复上面9-23中的内容,表示下一个事件 ++厂商ID固定,其他所有多字节对象均为小端序, eg: ++ipmitool raw 0x30 0x94 0xDB 0x07 0x00 0x40 0x00 0x00 0x00 0x01 0x02 ++db 07 00 03 00 03 00 39 00 00 02 2f ab 91 68 00 02 04 00 00 00 00 ++39 00 00 02 2e ab 91 68 00 02 02 00 00 00 00 39 00 00 02 2e ab 91 ++68 00 02 01 00 00 00 00 ++ */ ++int CBMCBlockIo::QueryEvents() ++{ ++ uint16_t currentIndex = 0; ++ int ret = BMCPLU_SUCCESS; ++ m_currentDeviceIds.clear(); ++ ++ while (true) { ++ std::string cmd = BuildIPMICommand(currentIndex); ++ std::vector hexBytes = ExecuteIPMICommand(cmd); ++ if (hexBytes.empty()) { ++ break; ++ } ++ ++ ResponseHeader header = ParseResponseHeader(hexBytes); ++ if (!header.valid) { ++ ret = BMCPLU_FAILED; ++ break; ++ } ++ ++ BMC_LOG_INFO << "Total events: " << header.totalEvents ++ << ", returned: " << static_cast(header.eventCount) ++ << ", current index: " << currentIndex; ++ if (header.eventCount == 0) { ++ break; ++ } ++ ++ size_t expectedSize = RESP_HEADER_SIZE + header.eventCount * EVENT_SIZE; ++ if (hexBytes.size() != expectedSize) { ++ BMC_LOG_ERROR << "Response size invalid. Expected: " << expectedSize ++ << ", Actual: " << hexBytes.size(); ++ ret = BMCPLU_FAILED; ++ break; ++ } ++ ++ ProcessEvents(hexBytes, header.eventCount); ++ currentIndex += header.eventCount; ++ ++ if (currentIndex >= header.totalEvents) { ++ break; ++ } ++ } ++ ++ if (ret == BMCPLU_SUCCESS) { ++ for (const auto& id : m_lastDeviceIds) { ++ if (m_currentDeviceIds.find(id) == m_currentDeviceIds.end()) { ++ uint32_t timeNow = static_cast(std::chrono::system_clock::to_time_t(std::chrono::system_clock::now())); ++ IPMIEvent clearEvent = {ALARM_CLEAR_CODE, timeNow, 0, 0x02, id, true}; ++ ReportAlarm(clearEvent); ++ } ++ } ++ m_lastDeviceIds = m_currentDeviceIds; ++ } ++ return ret; ++} ++ ++std::string CBMCBlockIo::BuildIPMICommand(uint16_t startIndex) ++{ ++ uint8_t indexHigh = static_cast((startIndex >> 8) & 0xff); ++ uint8_t indexLow = static_cast(startIndex & 0xff); ++ std::ostringstream cmdStream; ++ cmdStream << "ipmitool raw 0x30 0x94 0xDB 0x07 0x00 0x40 0x00" ++ << " " << ByteToHex(indexLow) ++ << " " << ByteToHex(indexHigh) ++ << " 0x01 0x02"; ++ return cmdStream.str(); ++} ++ ++std::vector CBMCBlockIo::ExecuteIPMICommand(const std::string& cmd) ++{ ++ BMC_LOG_DEBUG << "IPMI event query command: " << cmd; ++ ++ std::vector cmdOut; ++ if (ExecCommand(cmd, cmdOut)) { ++ BMC_LOG_ERROR << "IPMI command execute failed."; ++ return {}; ++ } ++ ++ std::ostringstream responseStream; ++ for (size_t i = 0; i < cmdOut.size(); ++i) { ++ std::string line = cmdOut[i]; ++ BMC_LOG_DEBUG << "Execute IPMI event response: " << line; ++ line.erase(std::remove(line.begin(), line.end(), '\r'), line.end()); ++ line.erase(std::remove(line.begin(), line.end(), '\n'), line.end()); ++ if (i > 0 && !line.empty()) { ++ responseStream << ' '; ++ } ++ responseStream << line; ++ } ++ return SplitString(responseStream.str(), " "); ++} ++ ++ResponseHeader CBMCBlockIo::ParseResponseHeader(const std::vector& hexBytes) ++{ ++ ResponseHeader header = {0, 0, false}; ++ ++ if (hexBytes.size() < RESP_HEADER_SIZE) { ++ BMC_LOG_ERROR << "Invalid response length: " << hexBytes.size(); ++ return header; ++ } ++ ++ if (hexBytes[0] != "db" || hexBytes[1] != "07" || hexBytes[2] != "00") { ++ BMC_LOG_ERROR << "Unexpected manufacturer ID: " ++ << hexBytes[0] << " " << hexBytes[1] << " " << hexBytes[2]; ++ return header; ++ } ++ ++ char* endPtr = nullptr; ++ unsigned long totalLow = std::strtoul(hexBytes[3].c_str(), &endPtr, 16); ++ if (endPtr == hexBytes[3].c_str() || *endPtr != '\0' || totalLow > 0xff) { ++ BMC_LOG_ERROR << "Invalid totalLow byte: " << hexBytes[3]; ++ return header; ++ } ++ ++ unsigned long totalHigh = std::strtoul(hexBytes[4].c_str(), &endPtr, 16); ++ if (endPtr == hexBytes[4].c_str() || *endPtr != '\0' || totalHigh > 0xff) { ++ BMC_LOG_ERROR << "Invalid totalHigh byte: " << hexBytes[4]; ++ return header; ++ } ++ ++ header.totalEvents = static_cast(totalLow) | (static_cast(totalHigh) << 8); ++ unsigned long count = std::strtoul(hexBytes[5].c_str(), &endPtr, 16); ++ if (endPtr == hexBytes[5].c_str() || *endPtr != '\0' || count > 0xff) { ++ BMC_LOG_ERROR << "Invalid event count byte: " << hexBytes[5]; ++ return header; ++ } ++ ++ header.eventCount = static_cast(count); ++ header.valid = true; ++ return header; ++} ++ ++IPMIEvent CBMCBlockIo::ParseSingleEvent(const std::vector& hexBytes, size_t startPos) ++{ ++ IPMIEvent event = {0, 0, 0, 0, 0, false}; ++ char* endPtr = nullptr; ++ ++ for (int i = 0; i < 4; ++i) { ++ unsigned long byte = std::strtoul(hexBytes[startPos + i].c_str(), &endPtr, 16); ++ if (endPtr == hexBytes[startPos + i].c_str() || *endPtr != '\0' || byte > 0xff) { ++ BMC_LOG_ERROR << "Invalid alarm type byte at pos " << startPos + i ++ << ": " << hexBytes[startPos + i]; ++ return event; ++ } ++ event.alarmTypeCode |= (static_cast(byte) << (i * 8)); ++ } ++ ++ for (int i = 0; i < 4; ++i) { ++ unsigned long byte = std::strtoul(hexBytes[startPos + 4 + i].c_str(), &endPtr, 16); ++ if (endPtr == hexBytes[startPos + 4 + i].c_str() || *endPtr != '\0' || byte > 0xff) { ++ BMC_LOG_ERROR << "Invalid timestamp byte at pos " << startPos + 4 + i ++ << ": " << hexBytes[startPos + 4 + i]; ++ return event; ++ } ++ event.timestamp |= (static_cast(byte) << (i * 8)); ++ } ++ ++ unsigned long severity = std::strtoul(hexBytes[startPos + 8].c_str(), &endPtr, 16); ++ if (endPtr == hexBytes[startPos + 8].c_str() || *endPtr != '\0' || severity > 0xff) { ++ BMC_LOG_ERROR << "Invalid severity byte: " << hexBytes[startPos + 8]; ++ return event; ++ } ++ event.severity = static_cast(severity); ++ ++ unsigned long subjectType = std::strtoul(hexBytes[startPos + 9].c_str(), &endPtr, 16); ++ if (endPtr == hexBytes[startPos + 9].c_str() || *endPtr != '\0' || subjectType > 0xff) { ++ BMC_LOG_ERROR << "Invalid subject type byte: " << hexBytes[startPos + 9]; ++ return event; ++ } ++ event.subjectType = static_cast(subjectType); ++ ++ unsigned long deviceId = std::strtoul(hexBytes[startPos + 10].c_str(), &endPtr, 16); ++ if (endPtr == hexBytes[startPos + 10].c_str() || *endPtr != '\0' || deviceId > 0xff) { ++ BMC_LOG_ERROR << "Invalid device ID byte: " << hexBytes[startPos + 10]; ++ return event; ++ } ++ event.deviceId = static_cast(deviceId); ++ ++ event.valid = true; ++ return event; ++} ++ ++void CBMCBlockIo::ProcessEvents(const std::vector& hexBytes, uint8_t eventCount) ++{ ++ for (int i = 0; i < eventCount; ++i) { ++ size_t startPos = RESP_HEADER_SIZE + i * EVENT_SIZE; ++ ++ IPMIEvent event = ParseSingleEvent(hexBytes, startPos); ++ if (!event.valid) { ++ continue; ++ } ++ ++ ReportAlarm(event); ++ } ++ return; ++} ++ ++void CBMCBlockIo::ReportAlarm(const IPMIEvent& event) ++{ ++ uint8_t ucAlarmLevel = MINOR_ALM; ++ uint8_t ucAlarmType = 0; ++ if (event.alarmTypeCode == ALARM_OCCUR_CODE) { ++ ucAlarmType = ALARM_TYPE_OCCUR; ++ m_currentDeviceIds.insert(event.deviceId); ++ } else if (event.alarmTypeCode == ALARM_CLEAR_CODE) { ++ ucAlarmType = ALARM_TYPE_RECOVER; ++ } else { ++ BMC_LOG_DEBUG << "Skipping unknown alarm type: 0x" ++ << std::hex << event.alarmTypeCode; ++ return; ++ } ++ ++ BMC_LOG_INFO << "Report alarm, type: " << static_cast(ucAlarmType); ++ BMC_LOG_INFO << "level: " << static_cast(ucAlarmLevel); ++ BMC_LOG_INFO << "deviceId: " << static_cast(event.deviceId); ++ BMC_LOG_INFO << "timestamp: " << event.timestamp; ++ json_object* jObject = json_object_new_object(); ++ json_object_object_add(jObject, JSON_KEY_ALARM_SOURCE.c_str(), json_object_new_string(BMC_TASK_NAME.c_str())); ++ json_object_object_add(jObject, JSON_KEY_DRIVER_NAME.c_str(), json_object_new_string(std::to_string(event.deviceId).c_str())); ++ json_object_object_add(jObject, JSON_KEY_IO_TYPE.c_str(), json_object_new_string("read,write")); ++ json_object_object_add(jObject, JSON_KEY_REASON.c_str(), json_object_new_string("driver slow")); ++ json_object_object_add(jObject, JSON_KEY_BLOCK_STACK.c_str(), json_object_new_string("rq_driver")); ++ json_object_object_add(jObject, JSON_KEY_DETAILS.c_str(), json_object_new_string("{}}")); ++ const char *jData = json_object_to_json_string(jObject); ++ int ret = xalarm_Report(m_alarmId, ucAlarmLevel, ucAlarmType, const_cast(jData)); ++ if (ret != RETURE_CODE_SUCCESS) { ++ BMC_LOG_ERROR << "Failed to xalarm_Report, ret: " << ret; ++ } ++ json_object_put(jObject); ++ return; ++} ++ ++void CBMCBlockIo::ReportResult(int resultLevel, const std::string& msg) ++{ ++ RESULT_LEVEL level = static_cast(resultLevel); ++ json_object* jObject = json_object_new_object(); ++ json_object_object_add(jObject, JSON_KEY_MSG.c_str(), json_object_new_string(msg.c_str())); ++ const char *jData = json_object_to_json_string(jObject); ++ int ret = report_result(BMC_TASK_NAME.c_str(), level, const_cast(jData)); ++ if (ret != RETURE_CODE_SUCCESS) { ++ BMC_LOG_ERROR << "Failed to report_result, ret: " << ret; ++ } ++ json_object_put(jObject); ++ return; ++} ++}; +diff --git a/src/sentryPlugins/bmc_block_io/src/common.cpp b/src/sentryPlugins/bmc_block_io/src/common.cpp +new file mode 100644 +index 0000000..b1372f6 +--- /dev/null ++++ b/src/sentryPlugins/bmc_block_io/src/common.cpp +@@ -0,0 +1,237 @@ ++/* ++ * Copyright (c) Huawei Technologies Co., Ltd. 2025. All rights reserved. ++ * bmc_block_io is licensed under Mulan PSL v2. ++ * You can use this software according to the terms and conditions of the Mulan PSL v2. ++ * Author: hewanhan@h-partners.com ++ */ ++ ++#include "common.h" ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++namespace BMCBlockIoPlu { ++ ++std::string Trim(const std::string& str) ++{ ++ size_t first = str.find_first_not_of(" \t\n\r\v\f"); ++ if (std::string::npos == first) { ++ return ""; ++ } ++ size_t last = str.find_last_not_of(" \t\n\r\v\f"); ++ return str.substr(first, (last - first + 1)); ++} ++ ++bool IsValidNumber(const std::string& str, int& num) ++{ ++ if (str.empty()) { ++ return false; ++ } ++ for (const auto& iter : str) { ++ if (!std::isdigit(iter)) { ++ return false; ++ } ++ } ++ std::istringstream iss(str); ++ if (!(iss >> num)) { ++ return false; ++ } ++ return true; ++} ++ ++int ParseConfig(const std::string& path, PluConfig& config) ++{ ++ std::ifstream file(path); ++ if (!file.is_open()) { ++ BMC_LOG_ERROR << "Failed to open config file: " << path; ++ return BMCPLU_FAILED; ++ } ++ ++ std::unordered_map configMap; ++ configMap["log_level"] = {true, false, [&](const std::string& value) { ++ if (value == "debug") { ++ config.logLevel = Logger::Level::Debug; ++ } else if (value == "info") { ++ config.logLevel = Logger::Level::Info; ++ } else if (value == "warning") { ++ config.logLevel = Logger::Level::Warning; ++ } else if (value == "error") { ++ config.logLevel = Logger::Level::Error; ++ } else if (value == "critical") { ++ config.logLevel = Logger::Level::Critical; ++ } else { ++ BMC_LOG_ERROR << "Invalid log_level value."; ++ return false; ++ } ++ return true; ++ }}; ++ ++ configMap["patrol_second"] = {true, false, [&](const std::string& value) { ++ int num = 0; ++ if (!IsValidNumber(value, num) || !(num >= BMCPLU_PATROL_MIN && num <= BMCPLU_PATROL_MAX)) { ++ BMC_LOG_ERROR << "Invalid patrol_second value."; ++ return false; ++ } ++ config.patrolSeconds = num; ++ return true; ++ }}; ++ ++ std::string line; ++ while (std::getline(file, line)) { ++ line = Trim(line); ++ if (line.empty() || line[0] == '#') { ++ continue; ++ } ++ ++ size_t eqPos = line.find('='); ++ if (eqPos == std::string::npos || eqPos == 0) { ++ BMC_LOG_ERROR << "Config file format invalid."; ++ return BMCPLU_FAILED; ++ } ++ ++ std::string key = Trim(line.substr(0, eqPos)); ++ std::string value = Trim(line.substr(eqPos + 1)); ++ if (value.empty()) { ++ BMC_LOG_ERROR << "Config key: " << key << " cannot empty."; ++ return BMCPLU_FAILED; ++ } ++ ++ auto iter = configMap.find(key); ++ if (iter == configMap.end()) { ++ BMC_LOG_ERROR << "Config error, unknown key : " << key; ++ return BMCPLU_FAILED; ++ } ++ ++ if (!iter->second.processor(value)) { ++ return BMCPLU_FAILED; ++ } ++ iter->second.found = true; ++ } ++ ++ for (const auto& iter : configMap) { ++ if (iter.second.required && !iter.second.found) { ++ BMC_LOG_ERROR << "Config error, missing required key : " << iter.first; ++ return BMCPLU_FAILED; ++ } ++ } ++ return BMCPLU_SUCCESS; ++} ++ ++std::map> parseModConfig(const std::string& path) ++{ ++ std::map> result; ++ ++ std::ifstream file(path); ++ if (!file.is_open()) { ++ BMC_LOG_ERROR << "Failed to open mod file: " << path; ++ return result; ++ } ++ ++ std::string line; ++ std::string currentSection; ++ while (std::getline(file, line)) { ++ line = Trim(line); ++ if (line.empty() || line[0] == '#') { ++ continue; ++ } ++ ++ // check for section ++ if (line[0] == '[' && line[line.length() - 1] == ']') { ++ currentSection = Trim(line.substr(1, line.length() - 2)); ++ if (!currentSection.empty()) { ++ result[currentSection] = std::map(); ++ } ++ continue; ++ } ++ ++ // check for key=value ++ size_t eqPos = line.find('='); ++ if (eqPos != std::string::npos && !currentSection.empty()) { ++ std::string key = Trim(line.substr(0, eqPos)); ++ std::string value = Trim(line.substr(eqPos + 1)); ++ if (!key.empty()) { ++ result[currentSection][key] = value; ++ } ++ } ++ } ++ ++ return result; ++} ++ ++std::string ExtractFileName(const std::string& path) ++{ ++ size_t lastSlashPos = path.find_last_of('/'); ++ if (lastSlashPos == std::string::npos) { ++ return path; ++ } else { ++ return path.substr(lastSlashPos + 1); ++ } ++} ++ ++int ExecCommand(const std::string& cmd, std::vector& result) ++{ ++ FILE* pipe = popen(cmd.c_str(), "r"); ++ if (!pipe) { ++ BMC_LOG_ERROR << "Cmd: " << cmd << ", popen failed."; ++ return BMCPLU_FAILED; ++ } ++ ++ char buffer[512]; ++ result.clear(); ++ while (fgets(buffer, sizeof(buffer), pipe)) { ++ result.push_back(buffer); ++ } ++ ++ int status = pclose(pipe); ++ if (status == -1) { ++ BMC_LOG_ERROR << "Cmd: " << cmd << ", pclose failed."; ++ return BMCPLU_FAILED; ++ } else { ++ int exitCode = WEXITSTATUS(status); ++ if (exitCode != 0) { ++ BMC_LOG_ERROR << "Cmd: " << cmd << ", exit failed, err code: " << exitCode; ++ return BMCPLU_FAILED; ++ } ++ } ++ return BMCPLU_SUCCESS; ++} ++ ++std::string ByteToHex(uint8_t byte) ++{ ++ std::ostringstream oss; ++ const int hexLen = 2; ++ oss << std::hex << std::setfill('0') << std::setw(hexLen) << static_cast(byte); ++ return "0x" + oss.str(); ++} ++ ++std::vector SplitString(const std::string& str, const std::string& split) ++{ ++ std::vector result; ++ if (split.empty()) { ++ result.push_back(str); ++ return result; ++ } ++ ++ size_t pos = 0; ++ while (true) { ++ size_t split_pos = str.find(split, pos); ++ std::string substring = str.substr(pos, split_pos - pos); ++ ++ if (!substring.empty()) { ++ result.push_back(substring); ++ } ++ ++ if (split_pos == std::string::npos) { ++ break; ++ } ++ pos = split_pos + split.size(); ++ } ++ return result; ++} ++} +diff --git a/src/sentryPlugins/bmc_block_io/src/logger.cpp b/src/sentryPlugins/bmc_block_io/src/logger.cpp +new file mode 100644 +index 0000000..2854c44 +--- /dev/null ++++ b/src/sentryPlugins/bmc_block_io/src/logger.cpp +@@ -0,0 +1,155 @@ ++/* ++ * Copyright (c) Huawei Technologies Co., Ltd. 2025. All rights reserved. ++ * bmc_block_io is licensed under Mulan PSL v2. ++ * You can use this software according to the terms and conditions of the Mulan PSL v2. ++ * Author: hewanhan@h-partners.com ++ */ ++ ++#include "logger.h" ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "common.h" ++ ++namespace BMCBlockIoPlu { ++ ++Logger& Logger::GetInstance() ++{ ++ static Logger instance; ++ return instance; ++} ++ ++bool Logger::Initialize(const std::string& logPath, Level level) ++{ ++ m_logPath = logPath; ++ m_level = level; ++ OpenLogFile(); ++ return m_fileOpen; ++} ++ ++void Logger::SetLevel(Level level) ++{ ++ m_level = level; ++} ++ ++Logger::Level Logger::GetLevel() const ++{ ++ return m_level; ++} ++ ++void Logger::OpenLogFile() ++{ ++ m_logFile.open(m_logPath, std::ios::out | std::ios::app); ++ if (!m_logFile.is_open()) { ++ std::cerr << "Failed to open log file: " << m_logPath ++ << ", error: " << strerror(errno) << std::endl; ++ m_fileOpen = false; ++ return; ++ } ++ ++ struct stat fileStat; ++ if (stat(m_logPath.c_str(), &fileStat) == 0) { ++ m_inode = fileStat.st_ino; ++ m_device = fileStat.st_dev; ++ m_fileSize = fileStat.st_size; ++ } ++ m_checkTime = std::time(nullptr); ++ ++ m_fileOpen = true; ++ return; ++} ++ ++void Logger::CheckFileState() ++{ ++ std::time_t timeNow = std::time(nullptr); ++ if (timeNow - m_checkTime < BMCPLU_LOGFILE_CHECK_CYCLE) { ++ return; ++ } ++ ++ struct stat fileStat; ++ if (stat(m_logPath.c_str(), &fileStat) != 0) { ++ if (errno == ENOENT) { // file deleted ++ std::lock_guard lock(m_writeMutex); ++ ReopenLogFile(); ++ } ++ std::cerr << "Failed to get file state: " << m_logPath ++ << ", error: " << strerror(errno) << std::endl; ++ return; ++ } ++ ++ if (fileStat.st_ino != m_inode || fileStat.st_dev != m_device || fileStat.st_size < m_fileSize) { ++ ReopenLogFile(); ++ } else { ++ m_fileSize = fileStat.st_size; ++ } ++ ++ m_checkTime = timeNow; ++} ++ ++void Logger::ReopenLogFile() ++{ ++ if (m_logFile.is_open()) { ++ m_logFile.close(); ++ } ++ OpenLogFile(); ++ return; ++} ++ ++void Logger::WriteLog(Level level, const char* file, int line, const std::string& message) ++{ ++ if (level < GetLevel() || message.empty()) { ++ return; ++ } ++ ++ CheckFileState(); ++ std::lock_guard lock(m_writeMutex); ++ if (m_fileOpen && m_logFile.good()) { ++ m_logFile << Format(level, file, line, message) << std::endl; ++ m_logFile.flush(); ++ } else { ++ std::cerr << Format(level, file, line, message) << std::endl; ++ } ++} ++ ++std::string Logger::LevelToString(Level level) const ++{ ++ switch (level) { ++ case Level::Debug: return std::string("DEBUG"); ++ case Level::Info: return std::string("INFO"); ++ case Level::Warning: return std::string("WARNING"); ++ case Level::Error: return std::string("ERROR"); ++ case Level::Critical: return std::string("CRITICAL"); ++ default: return std::string("UNKNOWN"); ++ } ++ return std::string("UNKNOWN"); ++} ++ ++std::string Logger::GetTimeStamp() const ++{ ++ auto now = std::chrono::system_clock::now(); ++ auto nowTimer = std::chrono::system_clock::to_time_t(now); ++ auto milliseconds = std::chrono::duration_cast(now.time_since_epoch()) % 1000; ++ ++ struct tm nowTm; ++ localtime_r(&nowTimer, &nowTm); ++ ++ std::ostringstream oss; ++ const int millisecLen = 3; ++ oss << std::put_time(&nowTm, "%Y-%m-%d %H:%M:%S"); ++ oss << '.' << std::setfill('0') << std::setw(millisecLen) << milliseconds.count(); ++ ++ return oss.str(); ++} ++ ++std::string Logger::Format(Level level, const char* file, int line, const std::string & message) const ++{ ++ std::ostringstream oss; ++ oss << GetTimeStamp() << " - " << LevelToString(level) << " - [" ++ << ExtractFileName(file) << ":" << line << "]" << " - " << message; ++ return oss.str(); ++} ++} +diff --git a/src/sentryPlugins/bmc_block_io/src/main.cpp b/src/sentryPlugins/bmc_block_io/src/main.cpp +new file mode 100644 +index 0000000..0229ee1 +--- /dev/null ++++ b/src/sentryPlugins/bmc_block_io/src/main.cpp +@@ -0,0 +1,128 @@ ++/* ++ * Copyright (c) Huawei Technologies Co., Ltd. 2025. All rights reserved. ++ * bmc_block_io is licensed under Mulan PSL v2. ++ * You can use this software according to the terms and conditions of the Mulan PSL v2. ++ * Author: hewanhan@h-partners.com ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "cbmcblockio.h" ++#include "configure.h" ++#include "logger.h" ++#include "common.h" ++ ++std::atomic g_exit(false); ++std::mutex g_mutex; ++std::condition_variable g_cv; ++ ++void HandleSignal(int sig) ++{ ++ if (sig == SIGTERM || sig == SIGINT) { ++ g_exit = true; ++ BMC_LOG_INFO << "Receive signal SIGTERM or SIGINT, exit."; ++ g_cv.notify_all(); ++ } ++ return; ++} ++ ++void SetSignalHandler() ++{ ++ struct sigaction sa; ++ sigemptyset(&sa.sa_mask); ++ sigaddset(&sa.sa_mask, SIGTERM); // block SIGTERM ++ sigaddset(&sa.sa_mask, SIGINT); // block SIGINT ++ sa.sa_handler = HandleSignal; ++ sa.sa_flags = SA_RESTART; ++ ++ if (sigaction(SIGTERM, &sa, nullptr) == -1) { ++ BMC_LOG_ERROR << "Failed to setup signal with SIGTERM:" << strerror(errno); ++ } ++ ++ if (sigaction(SIGINT, &sa, nullptr) == -1) { ++ BMC_LOG_ERROR << "Failed to setup signal with SIGINT:" << strerror(errno); ++ } ++} ++ ++int main(int argc, char* argv[]) ++{ ++ if (!BMCBlockIoPlu::Logger::GetInstance().Initialize(BMCBlockIoPlu::BMCPLU_LOG_PATH)) { ++ std::cerr << "Failed to initialize logger." << std::endl; ++ } ++ SetSignalHandler(); ++ ++ BMCBlockIoPlu::CBMCBlockIo blockIo; ++ PluConfig config; ++ if (BMCBlockIoPlu::ParseConfig(BMCBlockIoPlu::BMCPLU_CONFIG_PATH, config)) { ++ BMC_LOG_ERROR << "Parse config failed, use default configuration."; ++ } else { ++ BMCBlockIoPlu::Logger::GetInstance().SetLevel(config.logLevel); ++ blockIo.SetPatrolInterval(config.patrolSeconds); ++ } ++ ++ std::thread configMonitor([&] { ++ time_t lastModTime = 0; ++ struct stat st; ++ if (stat(BMCBlockIoPlu::BMCPLU_CONFIG_PATH.c_str(), &st) == 0) { ++ lastModTime = st.st_mtime; ++ } ++ ++ while (!g_exit) { ++ { ++ std::unique_lock lock(g_mutex); ++ g_cv.wait_for(lock, std::chrono::seconds(BMCBlockIoPlu::BMCPLU_CONFIG_CHECK_CYCLE), ++ [] { return g_exit.load(); }); ++ if (g_exit) { ++ break; ++ } ++ } ++ ++ struct stat st_; ++ if (stat(BMCBlockIoPlu::BMCPLU_CONFIG_PATH.c_str(), &st_) != 0) { ++ continue; ++ } ++ if (st_.st_mtime != lastModTime) { ++ lastModTime = st_.st_mtime; ++ PluConfig newConfig; ++ if (BMCBlockIoPlu::ParseConfig(BMCBlockIoPlu::BMCPLU_CONFIG_PATH, newConfig) == BMCPLU_SUCCESS) { ++ if (newConfig.logLevel != config.logLevel) { ++ config.logLevel = newConfig.logLevel; ++ BMC_LOG_INFO << "Log level update to " ++ << BMCBlockIoPlu::Logger::GetInstance().LevelToString(config.logLevel); ++ BMCBlockIoPlu::Logger::GetInstance().SetLevel(config.logLevel); ++ } ++ if (newConfig.patrolSeconds != config.patrolSeconds) { ++ config.patrolSeconds = newConfig.patrolSeconds; ++ BMC_LOG_INFO << "Patrol interval update to " << config.patrolSeconds; ++ blockIo.SetPatrolInterval(config.patrolSeconds); ++ } ++ } ++ } ++ } ++ }); ++ blockIo.Start(); ++ while (!g_exit) { ++ { ++ std::unique_lock lock(g_mutex); ++ g_cv.wait_for(lock, std::chrono::seconds(BMCBlockIoPlu::BMCPLU_DEFAULT_SLEEP_CYCLE), ++ [] { return g_exit.load(); }); ++ } ++ if (!blockIo.IsRunning()) { ++ g_exit = true; ++ g_cv.notify_all(); ++ break; ++ } ++ } ++ blockIo.Stop(); ++ if (configMonitor.joinable()) { ++ configMonitor.join(); ++ } ++ return 0; ++} +-- +2.48.1 + diff --git a/sysSentry.spec b/sysSentry.spec index 9349c5f..b0f09a0 100644 --- a/sysSentry.spec +++ b/sysSentry.spec @@ -4,7 +4,7 @@ Summary: System Inspection Framework Name: sysSentry Version: 1.0.3 -Release: 14 +Release: 15 License: Mulan PSL v2 Group: System Environment/Daemons Source0: https://gitee.com/openeuler/sysSentry/releases/download/v%{version}/%{name}-%{version}.tar.gz @@ -27,6 +27,7 @@ Patch15: fix-env-for-subprocess.Popen.patch Patch16: Use-malloc-to-allocate-memory-as-much-as-possible.patch Patch17: fix-cpu_sentry-result-when-found_fault_cores_number-.patch Patch18: fix-some-code-bugs.patch +Patch19: add-bmc_block_io.patch BuildRequires: cmake gcc-c++ BuildRequires: python3 python3-setuptools @@ -119,6 +120,16 @@ Provides: sentry_msg_monitor = %{version} %description -n sentry_msg_monitor This package provides a plugin for sysSentry to listening specific messages +%package -n bmc_block_io +Summary: bmc_block_io for the sysSentry +Provides: bmc_block_io = %{version} +BuildRequires: json-c-devel libxalarm-devel +Requires: libxalarm ipmitool json-c +Requires: sysSentry = %{version}-%{release} + +%description -n bmc_block_io +This package provides bmc_block_io for the sysSentry. + %prep %autosetup -n %{name}-%{version} -p1 @@ -177,6 +188,8 @@ rm -rf /var/run/sysSentry | : %exclude %{_sysconfdir}/sysSentry/plugins/ai_block_io.ini %exclude %{_sysconfdir}/sysSentry/tasks/avg_block_io.mod %exclude %{_sysconfdir}/sysSentry/plugins/avg_block_io.ini +%exclude %{_sysconfdir}/sysSentry/tasks/bmc_block_io.mod +%exclude %{_sysconfdir}/sysSentry/plugins/bmc_block_io.ini # xalarm %attr(0550,root,root) %{_bindir}/xalarmd @@ -242,7 +255,18 @@ rm -rf /var/run/sysSentry | : %attr(0600,root,root) %{_sysconfdir}/sysconfig/sentry_msg_monitor.env %attr(0600,root,root) %{_sysconfdir}/sysSentry/tasks/sentry_msg_monitor.mod +%files -n bmc_block_io +%attr(0550,root,root) %{_bindir}/bmc_block_io +%attr(0600,root,root) %{_sysconfdir}/sysSentry/plugins/bmc_block_io.ini +%attr(0600,root,root) %{_sysconfdir}/sysSentry/tasks/bmc_block_io.mod + %changelog +* Wed Sep 24 2025 hewanhan - 1.0.3-15 +- Type:feature +- CVE:NA +- SUG:NA +- DESC:add bmc_block_io + * Mon Sep 22 2025 hewanhan - 1.0.3-14 - Type:bugfix - CVE:NA -- Gitee