From 1bf6a801cadb59f1b9ea21422b08864713209a1a Mon Sep 17 00:00:00 2001 From: shixuantong Date: Fri, 31 May 2024 11:35:12 +0800 Subject: [PATCH] add report_result API --- sysSentry-1.0.2/src/libso/CMakeLists.txt | 3 +- .../src/libso/xalarm/register_xalarm.c | 174 ++++++++++++++++++ .../src/libso/xalarm/register_xalarm.h | 28 ++- .../src/python/syssentry/result.py | 113 ++++++++++++ 4 files changed, 316 insertions(+), 2 deletions(-) create mode 100644 sysSentry-1.0.2/src/python/syssentry/result.py diff --git a/sysSentry-1.0.2/src/libso/CMakeLists.txt b/sysSentry-1.0.2/src/libso/CMakeLists.txt index 3ca3f7f..5101fb6 100644 --- a/sysSentry-1.0.2/src/libso/CMakeLists.txt +++ b/sysSentry-1.0.2/src/libso/CMakeLists.txt @@ -5,5 +5,6 @@ cmake_minimum_required(VERSION 3.12.1) project(libxalarm) SET(CMAKE_VERBOSE_MAKEFILE OFF) - +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g") + add_subdirectory(xalarm) diff --git a/sysSentry-1.0.2/src/libso/xalarm/register_xalarm.c b/sysSentry-1.0.2/src/libso/xalarm/register_xalarm.c index 31714fa..9fa1dc9 100644 --- a/sysSentry-1.0.2/src/libso/xalarm/register_xalarm.c +++ b/sysSentry-1.0.2/src/libso/xalarm/register_xalarm.c @@ -18,6 +18,9 @@ #include #include #include +#include +#include +#include #include "register_xalarm.h" @@ -34,6 +37,7 @@ #define ALARM_ENABLED 1 #define RECV_DELAY_MSEC 100 +#define TASK_NAME_MAX_LEN 256 struct alarm_register_info { char alarm_enable_bitmap[MAX_NUM_OF_ALARM_ID]; @@ -44,6 +48,15 @@ struct alarm_register_info { int thread_should_stop; }; +const char *g_result_level_string[] = { + "PASS", + "FAIL", + "SKIP", + "MINOR_ALM", + "MAJOR_ALM", + "CRITICAL_ALM", +}; + struct alarm_register_info g_register_info = {{0}, -1, ULONG_MAX, false, NULL, 1}; static bool id_is_registered(unsigned short alarm_id) @@ -410,3 +423,164 @@ int xalarm_Report(unsigned short usAlarmId, unsigned char ucAlarmLevel, return (ret > 0) ? 0 : -1; } + + +/** + * @brief send data to socket + * + * @param socket_path unix socket file path + * @param message string data to send, must end in '\0' + * @return int success or not, 0 means success, -1 means failure + */ +int send_data_to_socket(const char *socket_path, const char *message) +{ + int sockfd; + int ret; + struct sockaddr_un addr; + + // initialize socket + sockfd = socket(AF_UNIX, SOCK_STREAM, 0); + if (sockfd == -1) { + fprintf(stderr, "failed to create socket\n"); + return RETURE_CODE_FAIL; + } + + // set socket address + ret = memset_s(&addr, sizeof(addr), 0, sizeof(struct sockaddr_un)); + if (ret != 0) { + fprintf(stderr, "%s: memset_s info failed, ret: %d\n", __func__, ret); + return RETURE_CODE_FAIL; + } + + addr.sun_family = AF_UNIX; + ret = strncpy_s(addr.sun_path, sizeof(addr.sun_path), socket_path, sizeof(addr.sun_path) - 1); + if (ret != 0) { + fprintf(stderr, "%s: strncpy_s failed\n", __func__); + return RETURE_CODE_FAIL; + } + // connect socket + if (connect(sockfd, (struct sockaddr *)&addr, sizeof(struct sockaddr_un)) == -1) { + fprintf(stderr, "failed to connect socket %s\n", socket_path); + close(sockfd); + return RETURE_CODE_FAIL; + } + + // write data + if (write(sockfd, message, strlen(message)) == -1) { + fprintf(stderr, "failed to send data to socket %s\n", socket_path); + close(sockfd); + return RETURE_CODE_FAIL; + } + + close(sockfd); + return RETURE_CODE_SUCCESS; +} + + +static bool is_valid_task_name(const char *task_name) +{ + if (task_name == NULL) { + fprintf(stderr, "task_name is null\n"); + return false; + } + + if (!isalpha(task_name[0])) { + fprintf(stderr, "task_name does not start with an English letter\n"); + return false; + } + + if (strlen(task_name) > TASK_NAME_MAX_LEN) { + fprintf(stderr, "task_name is too long\n"); + return false; + } + + int ret; + + const char *pattern_task_name = "^[a-zA-Z][a-zA-Z0-9_]*$"; + regex_t regex_task_name; + + ret = regcomp(®ex_task_name, pattern_task_name, REG_EXTENDED); + if (ret) { + fprintf(stderr, "Could not compile regex\n"); + return false; + } + + ret = regexec(®ex_task_name, task_name, 0, NULL, 0); + if (ret) { + fprintf(stderr, "'task_name' (%s) contains illegal characters\n", task_name); + regfree(®ex_task_name); + return false; + } + + regfree(®ex_task_name); + return true; +} + + +/** + * @brief send result to sysSentry + * + * @param task_name task name, eg. "memory_sentry" + * @param result_level result level, eg. RESULT_LEVEL_PASS + * @param report_data result details info, Character string converted from the JSON format. + * @return int success or not, 0 means success, -1 means failure + */ +int report_result(const char *task_name, enum RESULT_LEVEL result_level, const char *report_data) +{ + if (result_level < 0 || result_level >= RESULT_LEVEL_NUM) { + fprintf(stderr, "result_level (%u) is invaild, it must be in [0-5]\n", result_level); + return RETURE_CODE_FAIL; + } + + if (!is_valid_task_name(task_name)) { + return RETURE_CODE_FAIL; + } + + json_object *send_data = json_object_new_object(); + json_object *result_data = json_object_new_object(); + json_object_object_add(result_data, "result", json_object_new_string(g_result_level_string[result_level])); + // The null pointer does not need to be determined. json_object_new_string () can receive null pointers. + json_object_object_add(result_data, "details", json_object_new_string(report_data)); + json_object_object_add(send_data, "result_data", result_data); + json_object_object_add(send_data, "task_name", json_object_new_string(task_name)); + + const char *result_json_string = json_object_to_json_string(send_data); + if (result_json_string == NULL) { + fprintf(stderr, "%s: json_object_to_json_string return NULL", __func__); + json_object_put(send_data); + return RETURE_CODE_FAIL; + } + + int send_data_len = strlen(result_json_string); + if (send_data_len > RESULT_INFO_MAX_LEN) { + fprintf(stderr, "%s: failed to send result message (%s) to sysSentry! send data is too long (%zu) > (%d)\n", + __func__, result_json_string, send_data_len, RESULT_INFO_MAX_LEN); + json_object_put(send_data); + return RETURE_CODE_FAIL; + } + + char message[RESULT_INFO_HEAD_LEN + RESULT_INFO_MAX_LEN]; + int ret = memset_s(message, sizeof(message), 0, RESULT_INFO_HEAD_LEN + RESULT_INFO_MAX_LEN); + if (ret != 0) { + fprintf(stderr, "%s: memset_s message failed", __func__); + json_object_put(send_data); + return RETURE_CODE_FAIL; + } + + ret = sprintf_s(message, sizeof(message) - 1, "%s%04d%s", RESULT_INFO_HEAD_MAGIC, + send_data_len, result_json_string); + if (ret < 0) { + fprintf(stderr, "%s: failed to send result message (%s) to sysSentry, sprintf_s failed\n", __func__, message); + json_object_put(send_data); + return RETURE_CODE_FAIL; + } + + if (send_data_to_socket(RESULT_REPORT_SOCKET, message)) { + fprintf(stderr, "%s: failed to send result message (%s) to sysSentry!\n", __func__, message); + json_object_put(send_data); + return RETURE_CODE_FAIL; + } + + json_object_put(send_data); + return RETURE_CODE_SUCCESS; +} diff --git a/sysSentry-1.0.2/src/libso/xalarm/register_xalarm.h b/sysSentry-1.0.2/src/libso/xalarm/register_xalarm.h index 8e911a3..f17dbd6 100644 --- a/sysSentry-1.0.2/src/libso/xalarm/register_xalarm.h +++ b/sysSentry-1.0.2/src/libso/xalarm/register_xalarm.h @@ -71,5 +71,31 @@ int xalarm_Report(unsigned short usAlarmId, unsigned char ucAlarmLevel, unsigned char ucAlarmType, char *pucParas); - + +#define RESULT_REPORT_SOCKET "/var/run/sysSentry/result.sock" +#define RESULT_LEVEL_NUM 6 + +enum RESULT_LEVEL { + RESULT_LEVEL_PASS = 0, + RESULT_LEVEL_FAIL = 1, + RESULT_LEVEL_SKIP = 2, + RESULT_LEVEL_MINOR_ALM = 3, + RESULT_LEVEL_MAJOR_ALM = 4, + RESULT_LEVEL_CRITICAL_ALM = 5, +}; + +#define RESULT_INFO_HEAD_LEN 10 +#define RESULT_INFO_HEAD_MAGIC "RESULT" +#define RESULT_INFO_MAX_LEN 4096 +#define RESULT_INFO_LOG_MGS_MAX_LEN 255 + +#define RETURE_CODE_FAIL (-1) +#define RETURE_CODE_SUCCESS 0 + +extern int report_result(const char *task_name, + enum RESULT_LEVEL result_level, + const char *report_data); + +extern int send_data_to_socket(const char *socket_path, const char *message); + #endif diff --git a/sysSentry-1.0.2/src/python/syssentry/result.py b/sysSentry-1.0.2/src/python/syssentry/result.py new file mode 100644 index 0000000..f5e8126 --- /dev/null +++ b/sysSentry-1.0.2/src/python/syssentry/result.py @@ -0,0 +1,113 @@ +# coding: utf-8 +# Copyright (c) 2024 Huawei Technologies Co., Ltd. +# sysSentry is licensed under the Mulan PSL v2. +# You can use this software according to the terms and conditions of the Mulan PSL v2. +# You may obtain a copy of Mulan PSL v2 at: +# http://license.coscl.org.cn/MulanPSL2 +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR +# PURPOSE. +# See the Mulan PSL v2 for more details. + +""" +use for report result +""" +import json +import os +import socket +import re +import logging + +from enum import Enum + + +class ResultLevel(Enum): + """result level for report_result""" + PASS = 0 + FAIL = 1 + SKIP = 2 + MINOR_ALM = 3 + MAJOR_ALM = 4 + CRITICAL_ALM = 5 + +# result-specific socket +RESULT_SOCKET_PATH = "/var/run/sysSentry/result.sock" + +RESULT_MSG_HEAD_LEN = 10 +RESULT_MSG_MAGIC_LEN = 6 # len(RESULT_MAGIC) +RESULT_MAGIC = "RESULT" +RESULT_INFO_MAX_LEN = 4096 + +RESULT_LEVEL_ERR_MSG_DICT = { + ResultLevel.PASS.name : "", + ResultLevel.SKIP.name : "not supported.maybe some rpm package not be installed.", + ResultLevel.FAIL.name : "FAILED. config may be incorrect or the command may be invalid/killed!", + ResultLevel.MINOR_ALM.name : "the command output shows that the status is 'INFO' or 'GENERAL_WARN'.", + ResultLevel.MAJOR_ALM.name : "the command output shows that the status is 'WARN' or 'IMPORTANT_WARN'.", + ResultLevel.CRITICAL_ALM.name : "the command output shows that the status is 'FAIL' or 'EMERGENCY_WARN'.", +} + + +def report_result(task_name: str, result_level : ResultLevel, report_data : str) -> int: + """client socket send and recv message""" + if not os.path.exists(RESULT_SOCKET_PATH): + logging.warning("did not send data to sysSentry.") + return -1 + + if not isinstance(task_name, str) \ + or not isinstance(result_level, ResultLevel) \ + or not isinstance(report_data, str): + logging.error("params type is wrong!") + return -1 + + pattern_name = r"^[a-zA-Z][a-zA-Z0-9_]*$" + if not re.match(pattern_name, task_name): + logging.error("'task_name' (%s) contains illegal characters.", task_name) + return -1 + + send_data_dict = { + "task_name" : task_name, + "result_data": { + "result" : result_level.name, + "details": report_data + } + } + try: + send_data_str = json.dumps(send_data_dict) + except json.decoder.JSONDecodeError: + logging.error("failed dump data to json!") + return -1 + + req_data_len = len(send_data_str) + if req_data_len > RESULT_INFO_MAX_LEN: + logging.error("send data len is too long %d > %d)!", req_data_len, RESULT_INFO_MAX_LEN) + return -1 + + try: + client_socket = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) + except socket.error: + logging.error("sentryctl: client creat socket error") + return -1 + + try: + client_socket.connect(RESULT_SOCKET_PATH) + except OSError: + client_socket.close() + logging.error("sentryctl: client connect error") + return -1 + + request_msg = RESULT_MAGIC + str(req_data_len).zfill(RESULT_MSG_HEAD_LEN-RESULT_MSG_MAGIC_LEN) + send_data_str + request_msg = request_msg.encode() + + try: + client_socket.sendall(request_msg) + server_reponse_info = client_socket.recv(len("SUCCESS")) + server_reponse_info = server_reponse_info.decode().strip() + if server_reponse_info != "SUCCESS": + logging.error("report result to sysSentry, get incorrect response information : %s", server_reponse_info) + except (OSError, UnicodeError): + client_socket.close() + logging.error("sentryctl: client communicate error") + return -1 + client_socket.close() + return 0 -- Gitee