* This file is part of the oGRAC project.
* Copyright (c) 2024 Huawei Technologies Co.,Ltd.
*
* oGRAC is licensed under 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.
* -------------------------------------------------------------------------
*
* cms_cbb.c
*
*
* IDENTIFICATION
* src/cms/cbb/cms_cbb.c
*
* -------------------------------------------------------------------------
*/
#include <stdlib.h>
#include <string.h>
#include "cm_defs.h"
#include "cms_cbb.h"
#include "cbb_disklock.h"
#include "cbb_test_log.h"
#define CM_MAX_RES_NAME_LENGTH 32
#define CM_MAX_INST_COUNTS 64
#define MAX_EXIT_STATUS 128
#define DSS_STAT_MAX_LEN 13
#define JSON_DATA_MAX_LEN 2000
#define NODE_DATA_MAX_LEN 100
#define GCC_DEFAULT_PATH "/dev/gcc-disk"
#define GCC_HOME_ENV "GCC_HOME"
#define DSS_RES_DATA_LOCK_POS (1073741824)
unsigned int g_lock_id = 0;
int CmInit(unsigned int instance_id, const char *res_name, cm_notify_func_t func)
{
const char *gcc_home = getenv(GCC_HOME_ENV);
if (gcc_home == NULL || gcc_home[0] == '\0') {
LOG("GCC_HOME is not set, use default path: /dev/gcc-disk");
gcc_home = GCC_DEFAULT_PATH;
}
int ret = cm_dl_alloc(gcc_home, DSS_RES_DATA_LOCK_POS, instance_id);
if (ret == CM_INVALID_LOCK_ID) {
LOG("cm_dl_alloc failed with ret: %d", ret);
return OG_ERROR;
}
g_lock_id = ret;
LOG("CmInit completed, g_lock_id: %u", g_lock_id);
return OG_SUCCESS;
}
static status_t GetDssStat(dss_res_data *dss_res)
{
FILE *fp = NULL;
char line[DSS_STAT_MAX_LEN];
char cmd_cms_stat[OG_MAX_CMD_LEN] = "cms stat -res dss | awk '{print $1, $3, $6}' | grep -v 'NODE_ID'";
char status[8];
int node_id;
int is_work_member;
fp = popen(cmd_cms_stat, "r");
if (fp == NULL) {
LOG("Fail to get dss stat.");
return OG_ERROR;
}
dss_res->inst_count = 0;
while (fgets(line, sizeof(line), fp) != NULL) {
int result = sscanf_s(line, "%d %7s %d", &node_id, status, (unsigned int)sizeof(status), &is_work_member);
if (result == SSCANF_ERROR) {
LOG("Fail to scan dss stat.");
return OG_ERROR;
}
dss_res->node[dss_res->inst_count].is_work_member = is_work_member;
if (strcmp(status, "UNKNOWN") == 0) {
dss_res->node[dss_res->inst_count].status = DSS_OFFLINE;
} else if (strcmp(status, "ONLINE") == 0) {
dss_res->node[dss_res->inst_count].status = DSS_ONLINE;
} else if (strcmp(status, "OFFLINE") == 0) {
dss_res->node[dss_res->inst_count].status = DSS_OFFLINE;
}
dss_res->inst_count++;
}
pclose(fp);
return OG_SUCCESS;
}
static status_t GetNodeData(dss_res_data *dss_res, char json_data[JSON_DATA_MAX_LEN])
{
for (uint i = 0; i < dss_res->inst_count; i++) {
char node_data[NODE_DATA_MAX_LEN];
int result = snprintf_s(node_data, NODE_DATA_MAX_LEN, NODE_DATA_MAX_LEN, "{"
"\"node_id\": %u,"
"\"res_instance_id\": %u,"
"\"is_work_member\": %u,"
"\"status\": %u"
"}", i, i, dss_res->node[i].is_work_member, dss_res->node[i].status);
if (result == SSPRINTF_ERROR) {
LOG("Fail to use snprintf_s on node_data.");
return OG_ERROR;
}
errno_t error = strcat_s(json_data, JSON_DATA_MAX_LEN, node_data);
if (error != STRCAT_SUCCESS) {
LOG("Fail to use strcat_s on json_data.");
return OG_ERROR;
}
if (i < dss_res->inst_count - 1) {
errno_t error = strcat_s(json_data, JSON_DATA_MAX_LEN, ",");
if (error != STRCAT_SUCCESS) {
LOG("Fail to use strcat_s on json_data.");
return OG_ERROR;
}
}
}
errno_t error = strcat_s(json_data, JSON_DATA_MAX_LEN, "]}");
if (error != STRCAT_SUCCESS) {
LOG("Fail to use strcat_s on json_data.");
return OG_ERROR;
}
return OG_SUCCESS;
}
char* CmGetResStats(void)
{
dss_res_data *dss_res = (dss_res_data*)malloc(sizeof(dss_res_data));
if (dss_res == NULL) {
LOG("Here is no dss node.");
return NULL;
}
memset_s(dss_res, sizeof(dss_res_data), 0, sizeof(dss_res_data));
if (GetDssStat(dss_res) != OG_SUCCESS) {
free(dss_res);
return NULL;
}
char json_data[JSON_DATA_MAX_LEN];
int result = snprintf_s(json_data, JSON_DATA_MAX_LEN, JSON_DATA_MAX_LEN - 1, "{"
"\"res_name\": \"dss\","
"\"version\": 0,"
"\"inst_count\": %u,"
"\"inst_status\": [", dss_res->inst_count);
if (result == SSPRINTF_ERROR) {
LOG("Fail to use snprintf_s on json_data.");
free(dss_res);
return NULL;
}
if (GetNodeData(dss_res, json_data) != OG_SUCCESS) {
LOG("Fail to use GetNodeData for json_data.");
free(dss_res);
return NULL;
}
free(dss_res);
char *malloc_result = (char *)malloc(strlen(json_data) + 1);
if (malloc_result == NULL) {
LOG("Memory allocation failed in CmGetResStats");
return NULL;
}
memset_s(malloc_result, strlen(json_data) + 1, 0, strlen(json_data) + 1);
strcpy_s(malloc_result, strlen(json_data) + 1, json_data);
LOG("CmGetResStats completed, JSON data allocated.");
return malloc_result;
}
void CmFreeResStats(char *res_stat)
{
if (res_stat != NULL) {
free(res_stat);
res_stat = NULL;
LOG("res_stat memory freed.");
}
}
int CmResLock(const char *lock_name)
{
int ret = cm_dl_lock(g_lock_id, 1000);
if (ret == 0) {
LOG("cm_dl_lock succeeded");
return OG_SUCCESS;
}
unsigned long long lockTime = 0;
ret = cm_dl_getlocktime(g_lock_id, &lockTime);
if (ret != 0) {
LOG("cm_dl_getlocktime failed with ret: %d", ret);
return OG_ERROR;
}
int result = (int)(lockTime % MAX_EXIT_STATUS);
LOG("CmResLock completed, lockTime: %llu, result: %d", lockTime, result);
return result == OG_SUCCESS ? OG_ERROR : result;
}
int CmResUnlock(const char *lock_name)
{
int ret = cm_dl_unlock(g_lock_id);
if (ret != 0) {
LOG("CmResUnlock failed with ret: %d", ret);
return OG_ERROR;
}
LOG("CmResUnlock succeeded");
return OG_SUCCESS;
}
int CmResGetLockOwner(const char *lock_name, unsigned int *inst_id)
{
if (inst_id == NULL) {
LOG("CmResGetLockOwner failed due to NULL inst_id pointer");
return OG_ERROR;
}
unsigned long long temp_inst_id;
int ret = cm_dl_getowner(g_lock_id, &temp_inst_id);
if (ret != 0) {
LOG("cm_dl_getowner failed with ret: %d", ret);
return ret;
}
*inst_id = (unsigned int)temp_inst_id;
LOG("CmResGetLockOwner completed, inst_id: %u", *inst_id);
return OG_SUCCESS;
}
int CmResTransLock(const char *lock_name, unsigned int inst_id)
{
int ret = cm_dl_unlock(g_lock_id);
if (ret != 0) {
LOG("CmResTransLock failed to unlock, ret: %d", ret);
return OG_ERROR;
}
LOG("CmResTransLock completed successfully");
return OG_SUCCESS;
}