* Copyright (c) 2022 Huawei Technologies Co.,Ltd.
*
* CM 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.
* -------------------------------------------------------------------------
*
* cm_misc_res.cpp
*
*
* IDENTIFICATION
* src/cm_common/cm_misc_res.cpp
*
* -------------------------------------------------------------------------
*/
#include "cm_json_config.h"
#include "cm_msg.h"
#include "cm_misc.h"
#include "cm_misc_res.h"
bool g_enableSharedStorage = false;
CmResStatList g_resStatus[CM_MAX_RES_COUNT] = {{0}};
static bool8 g_isDnSSMode = CM_FALSE;
static uint32 g_resCount = 0;
static uint32 g_resNode[CM_MAX_RES_NODE_COUNT] = {0};
static uint32 g_resNodeCount = 0;
typedef struct ResConfRangeSt {
const char *param;
int min;
int max;
} ResConfRange;
typedef struct ResConfDefaultSt {
const char *param;
const char *defValue;
} ResConfDefault;
static ResConfRange g_resConfRange[] = {
{"check_interval", 1, 2147483647},
{"time_out", 1, 2147483647},
{"abnormal_timeout", 0, 2147483647},
{"restart_delay", 0, 1800},
{"restart_period", 0, 3600},
{"restart_times", -1, 9999},
{"res_instance_id", 0, 2147483647}
};
static ResConfDefault g_resConfDef[] = {
{"resources_type", "APP"},
{"check_interval", "1"},
{"time_out", "10"},
{"abnormal_timeout", "30"},
{"restart_delay", "1"},
{"restart_period", "1"},
{"restart_times", "-1"},
{"res_instance_id", "0"},
{"one instance res_instance_id", "0"},
{"is_critical", "true"},
{"location_type", "local"},
{"location_attr", ""}
};
typedef status_t (*InitCusRes)(const OneCusResConfJson *oneResJson, OneResStatList *oneResStat);
static status_t InitAllAppResInstStatMain(const OneCusResConfJson *oneResJson, OneResStatList *oneResStat);
static status_t InitAllDnResInstStatMain(const OneCusResConfJson *oneResJson, OneResStatList *oneResStat);
typedef struct InitCusResMapSt {
CusResType type;
InitCusRes initFuc;
} InitCusResMap;
static InitCusResMap g_customResourceType[] = {
{CUSTOM_RESOURCE_APP, InitAllAppResInstStatMain},
{CUSTOM_RESOURCE_DN, InitAllDnResInstStatMain}
};
typedef struct ResIsregStatusMapSt {
ResIsregStatus isreg;
const char isregStr[CM_MAX_RES_NAME];
} ResIsregStatusMap;
const ResIsregStatusMap g_resIsregStatusMap[] = {
{CM_RES_ISREG_INIT, "init"},
{CM_RES_ISREG_REG, "reg"},
{CM_RES_ISREG_UNREG, "unreg"},
{CM_RES_ISREG_PENDING, "pending"},
{CM_RES_ISREG_UNKNOWN, "unknown"},
{CM_RES_ISREG_NOT_SUPPORT, "not_support"},
};
static bool8 IsNodeInResNode(uint32 nodeId)
{
for (uint32 i = 0; i < CM_MAX_RES_NODE_COUNT; ++i) {
if (i >= g_resNodeCount) {
return CM_FALSE;
}
if (g_resNode[i] == nodeId) {
return CM_TRUE;
}
}
return CM_FALSE;
}
static void UpdateResNode(uint32 nodeId)
{
if (IsNodeInResNode(nodeId)) {
return;
}
if (g_resNodeCount < CM_MAX_RES_NODE_COUNT) {
g_resNode[g_resNodeCount] = nodeId;
}
++g_resNodeCount;
}
uint32 GetResNodeCount()
{
return g_resNodeCount;
}
uint32 GetResNodeId(uint32 index)
{
if (index >= CM_MAX_RES_NODE_COUNT) {
return 0;
}
return g_resNode[index];
}
const char *GetIsregStatus(int isreg)
{
uint32 size = (uint32)(sizeof(g_resIsregStatusMap) / sizeof(g_resIsregStatusMap[0]));
for (uint32 i = 0; i < size; ++i) {
if ((int)g_resIsregStatusMap[i].isreg == isreg) {
return g_resIsregStatusMap[i].isregStr;
}
}
return "";
}
bool IsResConfValid(const char *param, int value)
{
uint32 arrLen = (sizeof(g_resConfRange) / sizeof(g_resConfRange[0]));
for (uint32 i = 0; i < arrLen; ++i) {
if (strcmp(param, g_resConfRange[i].param) != 0) {
continue;
}
return (value >= g_resConfRange[i].min && value <= g_resConfRange[i].max);
}
return false;
}
bool IsKeyInRestrictList(const char *key)
{
uint32 arrLen = (sizeof(g_resConfRange) / sizeof(g_resConfRange[0]));
for (uint32 i = 0; i < arrLen; ++i) {
if (strcmp(key, g_resConfRange[i].param) == 0) {
return true;
}
}
return false;
}
int ResConfMaxValue(const char *param)
{
uint32 arrLen = (sizeof(g_resConfRange) / sizeof(g_resConfRange[0]));
for (uint32 i = 0; i < arrLen; ++i) {
if (strcmp(param, g_resConfRange[i].param) == 0) {
return g_resConfRange[i].max;
}
}
return INT32_MAX;
}
int ResConfMinValue(const char *param)
{
uint32 arrLen = (sizeof(g_resConfRange) / sizeof(g_resConfRange[0]));
for (uint32 i = 0; i < arrLen; ++i) {
if (strcmp(param, g_resConfRange[i].param) == 0) {
return g_resConfRange[i].min;
}
}
return INT32_MIN;
}
const char* ResConfDefValue(const char *param)
{
uint32 arrLen = (sizeof(g_resConfDef) / sizeof(g_resConfDef[0]));
for (uint32 i = 0; i < arrLen; ++i) {
if (strcmp(param, g_resConfDef[i].param) == 0) {
return g_resConfDef[i].defValue;
}
}
return "";
}
static inline bool IsCustomResource(CusResType resType)
{
uint32 arrLen = (sizeof(g_customResourceType) / sizeof(g_customResourceType[0]));
for (uint32 i = 0; i < arrLen; ++i) {
if (resType == g_customResourceType[i].type) {
return true;
}
}
return false;
}
static inline void PaddingResStat(const CmResStatList *oneRes)
{
errno_t rc = memcpy_s(&g_resStatus[g_resCount], sizeof(CmResStatList), oneRes, sizeof(CmResStatList));
securec_check_errno(rc, (void)rc);
++g_resCount;
}
static inline void CleanResStat()
{
errno_t rc = memset_s(g_resStatus, sizeof(CmResStatList) * CM_MAX_RES_COUNT,
0, sizeof(CmResStatList) * CM_MAX_RES_COUNT);
securec_check_errno(rc, (void)rc);
g_resCount = 0;
}
static status_t InitResName(const char *jsonResName, char *initResName, size_t maxResNameLen)
{
if (strlen(jsonResName) >= maxResNameLen) {
write_runlog(ERROR, "[InitResStat] res(%s) is longer than %lu.\n", jsonResName, (maxResNameLen - 1));
return CM_ERROR;
}
errno_t rc = strcpy_s(initResName, maxResNameLen, jsonResName);
securec_check_errno(rc, (void)rc);
return CM_SUCCESS;
}
static inline uint32 GetResCmInstId(uint32 nodeId)
{
static uint32 curCmInstId = RES_INSTANCE_ID_MIN;
return curCmInstId + nodeId;
}
static status_t InitOneAppResInstStat(const char *resName, const CusResInstConf *resInst, CmResStatInfo *instStat)
{
if (IsNodeIdValid(resInst->nodeId)) {
instStat->nodeId = (uint32)resInst->nodeId;
UpdateResNode(instStat->nodeId);
} else {
write_runlog(ERROR, "[InitResStat] res(%s), nodeId(%d) is invalid.\n", resName, resInst->nodeId);
return CM_ERROR;
}
instStat->cmInstanceId = GetResCmInstId((uint32)resInst->nodeId);
if (!IsResInstIdValid((int)instStat->cmInstanceId)) {
write_runlog(ERROR, "[InitResStat] res(%s), cmInstId(%u) is invalid.\n", resName, instStat->cmInstanceId);
return CM_ERROR;
}
if (resInst->resInstId >= 0) {
instStat->resInstanceId = (uint32)resInst->resInstId;
} else {
write_runlog(ERROR, "[InitResStat] res(%s), resInstId(%d) is invalid.\n", resName, resInst->resInstId);
return CM_ERROR;
}
instStat->isWorkMember = RES_INST_WORK_STATUS_AVAIL;
instStat->status = (uint32)CM_RES_STAT_UNKNOWN;
return CM_SUCCESS;
}
static status_t InitAllAppResInstStat(const AppCusResConfJson *appRes, OneResStatList *oneResStat)
{
CM_RETURN_IFERR(InitResName(appRes->resName, oneResStat->resName, CM_MAX_RES_NAME));
if (appRes->instance.count > CM_MAX_RES_INST_COUNT) {
write_runlog(ERROR, "[InitResStat] res(%s) instance count(%u) invalid, range[0, %d].\n",
appRes->resName, appRes->instance.count, CM_MAX_RES_INST_COUNT);
return CM_ERROR;
}
oneResStat->instanceCount = appRes->instance.count;
for (uint32 i = 0; i < oneResStat->instanceCount; ++i) {
CM_RETURN_IFERR(InitOneAppResInstStat(appRes->resName, &appRes->instance.conf[i], &oneResStat->resStat[i]));
}
return CM_SUCCESS;
}
static status_t InitAllAppResInstStatMain(const OneCusResConfJson *oneResJson, OneResStatList *oneResStat)
{
CM_RETURN_IFERR(InitAllAppResInstStat(&oneResJson->appResConf, oneResStat));
return CM_SUCCESS;
}
static inline void SetSharedStorageMode(const DnCusResConfJson *dnResJson)
{
if (!CM_IS_EMPTY_STR(dnResJson->resScript)) {
g_enableSharedStorage = true;
}
}
static inline void InitOneDnResInstStatByStaticConfig(const dataNodeInfo *dnInst, CmResStatInfo *instStat)
{
instStat->cmInstanceId = dnInst->datanodeId;
instStat->resInstanceId = dnInst->datanodeId;
instStat->isWorkMember = RES_INST_WORK_STATUS_AVAIL;
instStat->status = (uint32)CM_RES_STAT_UNKNOWN;
}
static status_t InitAllDnResInstStat(const DnCusResConfJson *dnResJson, OneResStatList *oneStat)
{
SetSharedStorageMode(dnResJson);
CM_RETURN_IFERR(InitResName(dnResJson->resName, oneStat->resName, CM_MAX_RES_NAME));
if (g_dn_replication_num > CM_MAX_RES_INST_COUNT) {
write_runlog(ERROR, "[InitResStat] res(%s) instance count(%u) is more than max(%d).\n",
dnResJson->resName, g_dn_replication_num, CM_MAX_RES_INST_COUNT);
return CM_ERROR;
}
oneStat->instanceCount = 0;
for (uint32 i = 0; i < g_node_num; ++i) {
for (uint32 k = 0; k < g_node[i].datanodeCount; ++k) {
InitOneDnResInstStatByStaticConfig(&g_node[i].datanode[k], &oneStat->resStat[oneStat->instanceCount]);
oneStat->resStat[oneStat->instanceCount].nodeId = g_node[i].node;
UpdateResNode(oneStat->resStat[oneStat->instanceCount].nodeId);
++oneStat->instanceCount;
}
}
return CM_SUCCESS;
}
static status_t InitAllDnResInstStatMain(const OneCusResConfJson *oneResJson, OneResStatList *oneResStat)
{
CM_RETURN_IFERR(InitAllDnResInstStat(&oneResJson->dnResConf, oneResStat));
return CM_SUCCESS;
}
static inline void InitOneResStatZero(OneResStatList *oneResStat)
{
errno_t rc = memset_s(oneResStat, sizeof(OneResStatList), 0, sizeof(OneResStatList));
securec_check_errno(rc, (void)rc);
oneResStat->version = 0;
}
static status_t InitOneResStat(const OneCusResConfJson *oneResJson, OneResStatList *oneResStat)
{
InitOneResStatZero(oneResStat);
uint32 arrLen = (sizeof(g_customResourceType) / sizeof(g_customResourceType[0]));
for (uint32 i = 0; i < arrLen; ++i) {
if (oneResJson->resType == g_customResourceType[i].type) {
CM_RETURN_IFERR(g_customResourceType[i].initFuc(oneResJson, oneResStat));
}
}
return CM_SUCCESS;
}
status_t InitAllResStat(int logLevel)
{
if (IsConfJsonEmpty()) {
write_runlog(logLevel, "[InitResStat] no custom resource config.\n");
return CM_SUCCESS;
}
for (uint32 i = 0; i < g_confJson->resource.count; ++i) {
if (!IsCustomResource(g_confJson->resource.conf[i].resType)) {
continue;
}
if (g_confJson->resource.conf[i].resType == CUSTOM_RESOURCE_DN) {
g_isDnSSMode = CM_TRUE;
}
if (g_resCount >= CM_MAX_RES_COUNT) {
write_runlog(ERROR, "[InitResStat] custom resource count overflow, max:%d.\n", CM_MAX_RES_COUNT);
CleanResStat();
return CM_ERROR;
}
CmResStatList newRes;
(void)pthread_rwlock_init(&newRes.rwlock, NULL);
CM_RETURN_IFERR_EX(InitOneResStat(&g_confJson->resource.conf[i], &newRes.status), CleanResStat());
PaddingResStat(&newRes);
}
return CM_SUCCESS;
}
int ReadCmConfJson(void *logFunc)
{
char jsonFile[MAX_PATH_LEN] = {0};
GetCmConfJsonPath(jsonFile, MAX_PATH_LEN);
SetReadJsonConfWriteLog((CmJsonLogOutput)logFunc);
return ReadConfJsonFile(jsonFile);
}
void GetCmConfJsonPath(char *path, uint32 pathLen)
{
int ret = snprintf_s(path, pathLen, pathLen - 1, "%s/cm_agent/cm_resource.json", g_currentNode->cmDataPath);
securec_check_intval(ret, (void)ret);
}
status_t GetGlobalResStatusIndex(const char *resName, uint32 &index)
{
for (uint32 i = 0; i < CusResCount(); ++i) {
if (strcmp(g_resStatus[i].status.resName, resName) == 0) {
index = i;
return CM_SUCCESS;
}
}
return CM_ERROR;
}
bool IsResInstIdValid(int instId)
{
if (instId > MIN_DN_INST_ID && instId < MAX_DN_INST_ID) {
return true;
}
if (instId > RES_INSTANCE_ID_MIN && instId < RES_INSTANCE_ID_MAX) {
return true;
}
return false;
}
bool IsOneResInstWork(const char *resName, uint32 cmInstId)
{
uint32 index = 0;
if (GetGlobalResStatusIndex(resName, index) != CM_SUCCESS) {
write_runlog(ERROR, "%s, unknown resName(%s).\n", __FUNCTION__, resName);
return false;
}
bool isWork = false;
CmResStatList *resStat = &g_resStatus[index];
for (uint32 i = 0; i < resStat->status.instanceCount; ++i) {
if (resStat->status.resStat[i].cmInstanceId == cmInstId) {
(void)pthread_rwlock_rdlock(&resStat->rwlock);
isWork = (resStat->status.resStat[i].isWorkMember == RES_INST_WORK_STATUS_AVAIL);
(void)pthread_rwlock_unlock(&resStat->rwlock);
break;
}
}
return isWork;
}
bool IsReadConfJsonSuccess(int ret)
{
return !CM_IS_READ_JSON_FAIL(ret);
}
const char *ReadConfJsonFailStr(int ret)
{
switch (ret) {
case CM_JSON_NOT_EXIST:
return "conf json not exist";
case CM_JSON_OPEN_ERROR:
return "open conf json file failed";
case CM_JSON_GET_LEN_ERROR:
return "get conf json context's size failed";
case CM_JSON_OUT_OF_MEMORY:
return "malloc failed, out of memory";
case CM_JSON_READ_ERROR:
return "get conf json context failed";
default:
break;
}
return "unknown fail reason";
}
status_t GetResNameByCmInstId(uint32 instId, char *resName, uint32 nameLen)
{
for (uint32 i = 0; i < CusResCount(); ++i) {
for (uint32 j = 0; j < g_resStatus[i].status.instanceCount; ++j) {
if (g_resStatus[i].status.resStat[j].cmInstanceId == instId) {
errno_t rc = strcpy_s(resName, nameLen, g_resStatus[i].status.resName);
securec_check_errno(rc, (void)rc);
return CM_SUCCESS;
}
}
}
write_runlog(LOG, "unknown cm_inst_id %u.\n", instId);
return CM_ERROR;
}
uint32 CusResCount()
{
return g_resCount;
}
bool IsCusResExist()
{
return (g_resCount > 0);
}
void PrintCusInfoResList(const OneResStatList *status, const char *info)
{
write_runlog(LOG, "[CUS_RES] [%s] res(%s), version=%llu, status:\n", info, status->resName, status->version);
for (uint32 i = 0; i < status->instanceCount; ++i) {
write_runlog(LOG, "[CUS_RES] nodeId=%u, cmInstId=%u, resInstId=%u, status=%u, isWork=%u;\n",
status->resStat[i].nodeId,
status->resStat[i].cmInstanceId,
status->resStat[i].resInstanceId,
status->resStat[i].status,
status->resStat[i].isWorkMember);
}
}
bool8 IsDatanodeSSMode()
{
return g_isDnSSMode;
}