diff --git a/src/cm_adapter/cm_sharedisk_adapter/cm_ddb_sharedisk_cmd.cpp b/src/cm_adapter/cm_sharedisk_adapter/cm_ddb_sharedisk_cmd.cpp index 28d8ee7..f10c617 100644 --- a/src/cm_adapter/cm_sharedisk_adapter/cm_ddb_sharedisk_cmd.cpp +++ b/src/cm_adapter/cm_sharedisk_adapter/cm_ddb_sharedisk_cmd.cpp @@ -21,7 +21,7 @@ * ------------------------------------------------------------------------- */ #include "cm/cm_elog.h" -#include "cm_ssl_base.h" +#include "cm_text.h" #include "cm_disk_rw.h" #include "cm_ddb_adapter.h" #include "cm_ddb_sharedisk_cmd.h" diff --git a/src/cm_agent/client_adpts/libpq/cma_datanode.cpp b/src/cm_agent/client_adpts/libpq/cma_datanode.cpp index 8ddd03b..551981d 100644 --- a/src/cm_agent/client_adpts/libpq/cma_datanode.cpp +++ b/src/cm_agent/client_adpts/libpq/cma_datanode.cpp @@ -213,8 +213,7 @@ void ShowPgThreadWaitStatus(cltPqConn_t* Conn, uint32 index, int instanceType) return; } -int DatanodeStatusCheck( - DnStatus *dnStatus, uint32 dataNodeIndex) +int DatanodeStatusCheck(DnStatus *dnStatus, uint32 dataNodeIndex, int32 dnProcess) { static uint32 checkDnSql5Timer = g_check_dn_sql5_interval; checkDnSql5Timer++; @@ -231,7 +230,6 @@ int DatanodeStatusCheck( /* in case we return 0 without set the db_state. */ reportMsg->local_status.db_state = INSTANCE_HA_STATE_UNKONWN; - int dnProcess = check_one_instance_status(GetDnProcessName(), dataPath, NULL); if (g_dnConn[dataNodeIndex] == NULL) { rcs = snprintf_s(gaussdbStatePath, MAXPGPATH, MAXPGPATH - 1, "%s/gaussdb.state", dataPath); securec_check_intval(rcs, (void)rcs); diff --git a/src/cm_agent/client_adpts/libpq/cma_datanode_check.cpp b/src/cm_agent/client_adpts/libpq/cma_datanode_check.cpp new file mode 100644 index 0000000..dc177e3 --- /dev/null +++ b/src/cm_agent/client_adpts/libpq/cma_datanode_check.cpp @@ -0,0 +1,1012 @@ +/* + * 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. + * ------------------------------------------------------------------------- + * + * cma_datanode_check.cpp + * + * IDENTIFICATION + * src/cm_agent/client_adpts/libpq/cma_datanode_check.cpp + * + * ------------------------------------------------------------------------- + */ +#include "cm_msg.h" +#include "cm_text.h" +#include "cm_misc.h" +#include "cm_elog.h" + +#include "cm_config.h" + +#include "cm_misc_res.h" + +#include "cma_global_params.h" +#include "cma_common.h" +#include "cma_libpq_com.h" +#include "cma_network_check.h" +#include "cma_datanode_utils.h" + +#ifdef ENABLE_UT +#define static +#endif + +typedef struct DnResultTextT { + uint32 cnt; // the number of parsed SQL result sets + uint32 maxLen; + uint32 point; // first ip point + char result[0]; +} DnResultText; + +typedef struct DnCmdT { + uint32 maxLen; + char cmd[0]; +} DnCmd; + +typedef struct DnValidateT { + uint32 cnt; + bool8 isReentrant[0]; +} DnValidate; + +typedef struct DnIpTextT { + DnResultText *dnText; + DnCmd *dnCmd; + DnValidate *validate; +} DnIpText; + +static DnIpText g_dnIpText[CM_MAX_DATANODE_PER_NODE] = {{0}}; +static THR_LOCAL DnIpText g_curDnIpText = {0}; + +static const char *const LISTEN_ADDRESSES = "listen_addresses"; +static const char *const MATCH_POINT = "="; +static const char MATCH_POINT_CHAR = '='; +static const char *const ALL_LISTEN_ADDRESSES = "0.0.0.0"; +static const char *const ALL_LISTEN_ADDRESSES_ARRAY[] = {ALL_LISTEN_ADDRESSES, "*"}; +static const char *const LOCAL_HOST_ARRAY[] = {"localhost", "127.0.0.1"}; +static const char INPUT_END_ARRAY[] = {'\n'}; +static const char SEPARATOR_ARRAY[] = {',', '\0'}; + +static const uint32 INIT_DN_IP_LEN = SIZE_K(2); +static const uint32 MAX_DN_IP_LEN = SIZE_K(10); +static const uint32 INVALID_DN_IP_LEN = 0xFFFFFFFF; +static const uint32 ENLARGEMENT = 2; + +static const uint32 INVALID_DN_CMD = 0xFFFFFFFF; +static const uint32 INIT_DN_CMD_LEN = INIT_DN_IP_LEN + MAX_PATH_LEN; +static const uint32 MAX_DN_CMD_LEN = MAX_DN_IP_LEN + MAX_PATH_LEN; + +static uint32 GetCurDnInstId(uint32 dnIdx) +{ + return g_currentNode->datanode[dnIdx].datanodeId; +} + +static const char *GetCurDnDataPath(uint32 dnIdx) +{ + return g_currentNode->datanode[dnIdx].datanodeLocalDataPath; +} + +static DnIpText *GetCurDnIpText() +{ + return &g_curDnIpText; +} + +static status_t CheckIpInputForSecurity(const char *ipInput) +{ + const char *dangerCharList[] = { + "|", ";", "&", "$", "<", ">", "`", "\\", "{", "}", "(", ")", "[", "]", "~", "?", "!", "\n", NULL}; + + for (int32 i = 0; dangerCharList[i] != NULL; i++) { + if (strstr(ipInput, dangerCharList[i]) != NULL) { + write_runlog(ERROR, "invalid token \"%s\" in input_value: (%s)\n", dangerCharList[i], ipInput); + return CM_ERROR; + } + } + return CM_SUCCESS; +} + +static status_t CheckIpInfoDnIdx(uint32 dnIdx, const char *str) +{ + if (dnIdx >= CM_MAX_DATANODE_PER_NODE) { + write_runlog(ERROR, "%s failed to get dnIpInfo, because dnIdx(%u) is beyond the range[0: %d).\n", + str, dnIdx, CM_MAX_DATANODE_PER_NODE); + return CM_ERROR; + } + return CM_SUCCESS; +} + +static void ResetDnText(DnResultText *dnText) +{ + if (dnText == NULL) { + write_runlog(ERROR, "[ResetDnText] dnText is NULL.\n"); + return; + } + uint32 maxLen = dnText->maxLen; + uint32 trueLen = (uint32)sizeof(DnResultText) + maxLen; + errno_t rc = memset_s(dnText, trueLen, 0, trueLen); + securec_check_errno(rc, (void)rc); + dnText->maxLen = maxLen; +} + +static status_t GetDnText(DnIpText *dnIpText, uint32 ipLen = INVALID_DN_IP_LEN) +{ + if (dnIpText == NULL) { + write_runlog(ERROR, "[GetDnText] dnIpText is NULL, cannot Get Dn Text.\n"); + return CM_ERROR; + } + + DnResultText *dnText = dnIpText->dnText; + uint32 tempLen = INIT_DN_IP_LEN; + + if (ipLen != INVALID_DN_IP_LEN) { + uint32 trueLen = CM_MAX(CM_MIN(ipLen, MAX_DN_IP_LEN), INIT_DN_IP_LEN); + tempLen = CM_ALIGN4(trueLen); + } + + if (dnText == NULL || (ipLen != INVALID_DN_IP_LEN && tempLen > dnText->maxLen)) { + FREE_AND_RESET(dnIpText->dnText); + uint32 needLen = tempLen + (uint32)sizeof(DnResultText); + dnIpText->dnText = (DnResultText *)malloc(needLen); + if (dnIpText->dnText == NULL) { + write_runlog(ERROR, "failed to get GetDnText, because failed to malloc memory(%u).\n", needLen); + return CM_ERROR; + } + write_runlog(LOG, "it will GetDnText, needLen=%u, ipLen=%u, maxLen=%u.\n", needLen, ipLen, tempLen); + dnText = dnIpText->dnText; + dnText->maxLen = tempLen; + ResetDnText(dnText); + } + return CM_SUCCESS; +} + +static DnIpText *GetDnIpText(uint32 dnIdx) +{ + CM_RETNULL_IFERR(CheckIpInfoDnIdx(dnIdx, "[GetDnIpText]")); + return &(g_dnIpText[dnIdx]); +} + +static void ResetDnCmd(DnCmd *dnCmd) +{ + if (dnCmd == NULL) { + return; + } + uint32 maxLen = dnCmd->maxLen; + uint32 trueLen = sizeof(DnCmd) + maxLen; + errno_t rc = memset_s(dnCmd, trueLen, 0, trueLen); + securec_check_errno(rc, (void)rc); + dnCmd->maxLen = maxLen; +} + +static status_t GetDnCmd(DnIpText *dnIpText, uint32 cmdLen = INVALID_DN_CMD) +{ + if (dnIpText == NULL) { + write_runlog(ERROR, "[GetDnCmd] dnIpText is NULL, cannot get Dn Cmd.\n"); + return CM_ERROR; + } + DnCmd *dnCmd = dnIpText->dnCmd; + + uint32 tempLen = INIT_DN_CMD_LEN; + if (cmdLen != INVALID_DN_CMD) { + uint32 trueLen = CM_MAX(CM_MIN(cmdLen, MAX_DN_CMD_LEN), INIT_DN_CMD_LEN); + tempLen = CM_ALIGN4(trueLen); + } + + if (dnCmd == NULL || (cmdLen != INVALID_DN_CMD && tempLen > dnCmd->maxLen)) { + FREE_AND_RESET(dnIpText->dnCmd); + uint32 needLen = tempLen + (uint32)sizeof(DnCmd); + dnIpText->dnCmd = (DnCmd *)malloc(needLen); + if (dnIpText->dnCmd == NULL) { + write_runlog(ERROR, "failed to get GetDnCmd, because failed to malloc memory(%u).\n", needLen); + return CM_ERROR; + } + write_runlog(LOG, "it will GetdnCmd, needLen=%u, cmdLen=%u, maxLen=%u.\n", needLen, cmdLen, tempLen); + dnIpText->dnCmd->maxLen = tempLen; + ResetDnCmd(dnIpText->dnCmd); + } + return CM_SUCCESS; +} + +static void ResetDnValidate(const DnIpText *dnIpText) +{ + if (dnIpText == NULL || dnIpText->validate == NULL) { + return; + } + DnValidate *validate = dnIpText->validate; + uint32 cnt = validate->cnt; + uint32 trueLen = sizeof(DnValidate) + cnt * sizeof(bool8); + errno_t rc = memset_s(validate, trueLen, 0, trueLen); + securec_check_errno(rc, (void)rc); + validate->cnt = cnt; +} + +static status_t GetDnValidate(DnIpText *dnIpText, uint32 cnt) +{ + const char *str = "[GetDnValidate]"; + if (dnIpText == NULL || cnt == 0) { + write_runlog(ERROR, "%s dnIpText is NULL or cnt is 0, cannot get Dn validate.\n", str); + return CM_ERROR; + } + if (dnIpText->validate == NULL || dnIpText->validate->cnt < cnt) { + FREE_AND_RESET(dnIpText->validate); + uint32 needLen = (uint32)sizeof(DnValidate) + cnt * (uint32)sizeof(bool8); + dnIpText->validate = (DnValidate*)malloc(needLen); + if (dnIpText->validate == NULL) { + write_runlog(ERROR, "%s failed ot get dn validate, because failed to malloc memory(%u).\n", str, needLen); + return CM_ERROR; + } + dnIpText->validate->cnt = cnt; + ResetDnValidate(dnIpText); + // dnIpText init, may be need to execute dn validate + for (uint32 i = 0; i < dnIpText->validate->cnt; ++i) { + dnIpText->validate->isReentrant[i] = CM_TRUE; + } + } + return CM_SUCCESS; +} + +static void ResetFloatIpDnNetState(DnStatus *dnStatus) +{ + DnFloatIpInfo *dnFloatIp = &(dnStatus->floatIpInfo.info); + for (uint32 i = 0; i < dnFloatIp->count; ++i) { + dnFloatIp->dnNetState[i] = (int32)NETWORK_STATE_UNKNOWN; + } +} + +static status_t DnTextTrim(char *text, char matchPoint, uint32 beginPoint, uint32 *point) +{ + uint32 tempPoint = beginPoint; + uint32 i = tempPoint; + bool8 isMatched = CM_FALSE; + for (; text[i] != '\0'; ++i) { + if (text[i] != matchPoint) { + tempPoint = i; + isMatched = CM_TRUE; + break; + } + } + if (!isMatched) { + write_runlog( + ERROR, "failed to trim text, cannot find the matched, text=[%s], matchPoint=[%c].\n", text, matchPoint); + return CM_ERROR; + } + i = (uint32)strlen(text) - 1; + for (; i > tempPoint; --i) { + if (text[i] == matchPoint) { + text[i] = '\0'; + } else { + break; + } + } + *point = tempPoint; + return CM_SUCCESS; +} + +static status_t GetMatchPoint(char *text, char matchPoint, uint32 *point) +{ + uint32 tempPoint = 0; + uint32 i = 0; + for (; text[i] != '\0'; ++i) { + if (text[i] == matchPoint) { + tempPoint = i + 1; + break; + } + } + if (tempPoint >= (uint32)strlen(text)) { + write_runlog(ERROR, "%d failed to getMatchPoint, bacause text=[%s], point=[%u: %zu].\n", + __LINE__, text, tempPoint, strlen(text)); + return CM_ERROR; + } + + write_runlog(DEBUG1, "%d text[%u]=[\"%c\": \"%s\"].\n", __LINE__, tempPoint, text[tempPoint], &text[tempPoint]); + + if (DnTextTrim(text, ' ', tempPoint, &tempPoint) != CM_SUCCESS) { + return CM_ERROR; + } + + while (CM_IS_QUOTE_CHAR(text[tempPoint])) { + if (text[strlen(text) - 1] == text[tempPoint]) { + text[strlen(text) - 1] = '\0'; + } + if ((tempPoint + 1) >= strlen(text)) { + write_runlog(ERROR, "%d failed to getMatchPoint, bacause text=[%s], point=[%u: %zu].\n", + __LINE__, text, tempPoint, strlen(text)); + return CM_ERROR; + } + ++tempPoint; + if (DnTextTrim(text, ' ', tempPoint, &tempPoint) != CM_SUCCESS) { + return CM_ERROR; + } + } + write_runlog(DEBUG1, "%d text[%u]=[\"%c\": \"%s\"].\n", __LINE__, tempPoint, text[tempPoint], &text[tempPoint]); + *point = tempPoint; + return CM_SUCCESS; +} + +static void PrintDnText(const DnResultText *dnText, uint32 instId, const char *str, int32 logLevel = DEBUG1) +{ + if (GetCmLogMessage() > logLevel) { + return; + } + + char ipInfo[INIT_DN_IP_LEN] = {0}; + uint32 curPoint = dnText->point; + errno_t rc; + const char *curStr; + uint32 curLen; + for (uint32 i = 0; i < dnText->cnt; ++i) { + while (curPoint < dnText->maxLen && dnText->result[curPoint] == '\0') { + ++curPoint; + } + if (curPoint >= dnText->maxLen) { + write_runlog(ERROR, "%s instId(%u) cannot print dn text, when curPoint=[%u: %u].\n", + __FUNCTION__, instId, curPoint, dnText->maxLen); + return; + } + curStr = dnText->result + curPoint; + curLen = (uint32)strlen(ipInfo); + if (curLen >= INIT_DN_IP_LEN) { + write_runlog(DEBUG1, "%s instId(%u) curLen(%u) is more than %u.\n", str, instId, curLen, INIT_DN_IP_LEN); + break; + } + if (i == dnText->cnt - 1) { + rc = snprintf_s(ipInfo + curLen, INIT_DN_IP_LEN - curLen, (INIT_DN_IP_LEN - curLen) - 1, "%s", curStr); + } else { + rc = snprintf_s(ipInfo + curLen, INIT_DN_IP_LEN - curLen, (INIT_DN_IP_LEN - curLen) - 1, "%s, ", curStr); + } + securec_check_intval(rc, (void)rc); + curPoint += (uint32)strlen(curStr); + } + write_runlog(logLevel, "[%s] instId(%u) success to get [cnt=[%u]: ipInfo=[%s]].\n", + str, instId, dnText->cnt, ipInfo); +} + +static bool8 IsCurIpAllListenAddress(const char *ip) +{ + if (CM_IS_EMPTY_STR(ip)) { + return CM_FALSE; + } + uint32 len = ELEMENT_COUNT(ALL_LISTEN_ADDRESSES_ARRAY); + for (uint32 i = 0; i < len; ++i) { + if (cm_str_equal(ip, ALL_LISTEN_ADDRESSES_ARRAY[i])) { + return CM_TRUE; + } + } + return CM_FALSE; +} + +static bool8 IsIpSkipCheck(const char *ip) +{ + if (cm_str_equal(ip, LOCAL_HOST_ARRAY[0])) { + return CM_TRUE; + } + if (IsCurIpAllListenAddress(ip)) { + return CM_TRUE; + } + return CM_FALSE; +} + +static bool8 CheckDnTextValid(const DnResultText *dnText, uint32 instId) +{ + uint32 curPoint = dnText->point; + const char *curIp; + for (uint32 i = 0; i < dnText->cnt; ++i) { + while (curPoint < dnText->maxLen && dnText->result[curPoint] == '\0') { + ++curPoint; + } + if (curPoint >= dnText->maxLen) { + write_runlog(ERROR, "%s instId(%u) cannot check whether dn text is valid , when curPoint=[%u: %u].\n", + __FUNCTION__, instId, curPoint, dnText->maxLen); + return CM_FALSE; + } + curIp = dnText->result + curPoint; + if (!IsIpSkipCheck(curIp) && !CheckIpValid(curIp)) { + write_runlog(ERROR, "instId(%u) find the invalid ip(%s), cannot arbitrate.\n", instId, curIp); + return CM_FALSE; + } + curPoint += (uint32)strlen(curIp); + } + return CM_TRUE; +} + +static status_t ParseDnText(DnResultText *dnText, uint32 instId) +{ + uint32 point = 0; + if (GetMatchPoint(dnText->result, MATCH_POINT_CHAR, &point) != CM_SUCCESS) { + return CM_ERROR; + } + if (point >= (uint32)strlen(dnText->result)) { + write_runlog(ERROR, "instId(%u) failed to parse Dn Text, bacause dnText=[%s], point=[%u: %zu].\n", + instId, dnText->result, point, strlen(dnText->result)); + return CM_ERROR; + } + dnText->point = point; + bool8 isFirst = CM_TRUE; + uint32 cnt = 0; + for (uint32 i = point; dnText->result[i] != '\0'; ++i) { + if (dnText->result[i] == SEPARATOR_ARRAY[0] || dnText->result[i] == ' ') { + dnText->result[i] = '\0'; + isFirst = CM_TRUE; + } else if (isFirst) { + isFirst = CM_FALSE; + ++cnt; + } + } + dnText->cnt = cnt; + PrintDnText(dnText, instId, "ParseDnText"); + if (!CheckDnTextValid(dnText, instId)) { + return CM_ERROR; + } + return CM_SUCCESS; +} + +static bool8 IsLocalHostIp(const char *ip) +{ + uint32 len = ELEMENT_COUNT(LOCAL_HOST_ARRAY); + for (uint32 i = 0; i < len; ++i) { + if (cm_str_equal(ip, LOCAL_HOST_ARRAY[i])) { + return CM_TRUE; + } + } + return CM_FALSE; +} + +static bool8 IsSameIp(const char *srcIp, const char *dstIp) +{ + if (cm_str_equal(srcIp, dstIp)) { + return CM_TRUE; + } + if (IsLocalHostIp(srcIp) && IsLocalHostIp(dstIp)) { + return CM_TRUE; + } + return CM_FALSE; +} + +static bool8 IsFindVipInDnText(const DnResultText *dnText, const char *ip, bool8 isDel, bool8 *isAllListen) +{ + if (CM_IS_EMPTY_STR(dnText->result) || CM_IS_EMPTY_STR(ip)) { + write_runlog(ERROR, "Failed to find the vip in dnText, because DnText or ip is null.\n"); + return CM_FALSE; + } + uint32 curPoint = dnText->point; + const char *curIp; + *isAllListen = CM_FALSE; + for (uint32 i = 0; i < dnText->cnt; ++i) { + while (curPoint < dnText->maxLen && dnText->result[curPoint] == '\0') { + ++curPoint; + } + if (curPoint >= dnText->maxLen) { + write_runlog(ERROR, "%s cannot check whether vip is in DnText, when curPoint=[%u: %u].\n", + __FUNCTION__, curPoint, dnText->maxLen); + return CM_FALSE; + } + curIp = dnText->result + curPoint; + if (IsSameIp(ip, curIp)) { + return CM_TRUE; + } + if (!isDel && IsCurIpAllListenAddress(curIp)) { + *isAllListen = CM_TRUE; + return CM_TRUE; + } + curPoint += (uint32)strlen(curIp); + } + return CM_FALSE; +} + +static bool8 IsResultEnd(const char *result) +{ + uint32 arrLen = ELEMENT_COUNT(INPUT_END_ARRAY); + for (uint32 i = 0; i < arrLen; ++i) { + if (result[strlen(result) - 1] == INPUT_END_ARRAY[i]) { + return CM_TRUE; + } + } + return CM_FALSE; +} + +static status_t GetDnListenAddressesFromFile(DnIpText *dnIpText, uint32 dnIdx) +{ + DnFloatIp *dnFloatIp = GetDnFloatIpByDnIdx(dnIdx); + if (dnFloatIp == NULL || dnFloatIp->dnFloatIpCount == 0) { + return CM_ERROR; + } + const char *str = "[GetDnListenAddressesFromFile]"; + + CM_RETURN_IFERR(GetDnText(dnIpText, INIT_DN_IP_LEN + dnFloatIp->dnFloatIpCount * CM_IP_LENGTH)); + char cmd[MAX_PATH_LEN] = {0}; + errno_t rc = snprintf_s(cmd, MAX_PATH_LEN, MAX_PATH_LEN - 1, "gs_guc check -Z datanode -D %s -c \"%s\" 2>&1 " + "| grep \"gs_guc check\" | awk -F ':' '{print $3}'", GetCurDnDataPath(dnIdx), LISTEN_ADDRESSES); + securec_check_intval(rc, (void)rc); + uint32 instId = GetCurDnInstId(dnIdx); + FILE *cmdFd = popen(cmd, "r"); + if (cmdFd == NULL) { + write_runlog(ERROR, "%s instId(%u) popen %s failed, errno is %d.\n", str, instId, cmd, errno); + return CM_ERROR; + } + write_runlog(DEBUG1, "%s instId(%u) cmd=%s.\n", str, instId, cmd); + DnResultText *dnText = dnIpText->dnText; + bool8 isEnd = CM_FALSE; + while (fgets(dnText->result, (int32)dnText->maxLen, cmdFd) != NULL) { + write_runlog(DEBUG1, "%s instId(%u) success to get dnText(%s).\n", str, instId, dnText->result); + if (cm_str_match(dnText->result, LISTEN_ADDRESSES) && cm_str_match(dnText->result, MATCH_POINT)) { + write_runlog(DEBUG1, "%s instId(%u) success to get dnText(%s).\n", str, instId, dnText->result); + isEnd = IsResultEnd(dnText->result); + break; + } + rc = memset_s(dnText->result, dnText->maxLen, 0, dnText->maxLen); + securec_check_errno(rc, (void)rc); + } + (void)pclose(cmdFd); + + if (!isEnd) { + write_runlog(ERROR, "%s instId(%u) cannot get %s with cmd[%s], because the dnText is not end.\n", + str, instId, LISTEN_ADDRESSES, cmd); + (void)GetDnText(dnIpText, ENLARGEMENT * dnText->maxLen); + return CM_ERROR; + } + + if (CM_IS_EMPTY_STR(dnText->result)) { + write_runlog(ERROR, "%s instId(%u) cannot get %s with cmd[%s], because the result is empty.\n", + str, instId, LISTEN_ADDRESSES, cmd); + return CM_ERROR; + } + + dnText->result[strlen(dnText->result) - 1] = '\0'; + CM_RETURN_IFERR(CheckIpInputForSecurity(dnText->result)); + return ParseDnText(dnText, instId); +} + +static int32 CheckFloatIpListen(const char *ip, uint32 dnIdx) +{ + char cmd[INIT_DN_CMD_LEN] = {0}; + errno_t rc = snprintf_s(cmd, INIT_DN_CMD_LEN, INIT_DN_CMD_LEN - 1, "netstat -anop 2>&1 |grep \"" + "$(ps -ux |grep -w \"%s/%s\"|grep -w \"%s\" |grep -v grep | awk '{print $2}')/%s\" " + "| grep -w \"LISTEN\" | awk '{print $4}'| grep -w \"%s\"", + g_binPath, GetDnProcessName(), GetCurDnDataPath(dnIdx), GetDnProcessName(), ip); + securec_check_intval(rc, (void)rc); + int32 errCode = 0; + int32 res = ExecuteSystemCmd(cmd, DEBUG1, &errCode); + if (res != 0) { + write_runlog(DEBUG1, "instId(%u) failed to execute the cmd(%s), res=%d, errno is %d, errCode is %d.\n", + GetCurDnInstId(dnIdx), cmd, res, errno, errCode); + if (res == ERROR_EXECUTE_CMD) { + return (int32)NETWORK_STATE_UNKNOWN; + } + return (int32)NETWORK_STATE_DOWN; + } + write_runlog(DEBUG1, "instId(%u) success to execute the cmd[%s].\n", GetCurDnInstId(dnIdx), cmd); + return (int32)NETWORK_STATE_UP; +} + +static void GetAllFloatIpNetState(DnStatus *dnStatus, const DnFloatIp *dnFloatIp, uint32 dnIdx, int32 dnRole) +{ + DnFloatIpInfo *floatIpInfo = &(dnStatus->floatIpInfo.info); + bool8 isNeedCheckAllListen = CM_TRUE; + int32 listenRet = 0; + for (uint32 i = 0; i < dnFloatIp->dnFloatIpCount; ++i) { + listenRet = CheckFloatIpListen(dnFloatIp->dnFloatIp[i], dnIdx); + if (listenRet != (int32)NETWORK_STATE_DOWN) { + isNeedCheckAllListen = CM_FALSE; + } + floatIpInfo->dnNetState[i] = listenRet; + } + if (!isNeedCheckAllListen) { + return; + } + + listenRet = CheckFloatIpListen(ALL_LISTEN_ADDRESSES, dnIdx); + if (listenRet == (int32)NETWORK_STATE_DOWN) { + return; + } + + for (uint32 i = 0; i < dnFloatIp->dnFloatIpCount; ++i) { + floatIpInfo->dnNetState[i] = listenRet; + if (listenRet == (int32)NETWORK_STATE_UP) { + floatIpInfo->dnNetState[i] = + (int32)((dnRole == INSTANCE_ROLE_PRIMARY) ? NETWORK_STATE_UP : NETWORK_STATE_DOWN); + } + } +} + +static status_t GetDnNetStateFromFile( + DnIpText *dnIpText, DnFloatIpInfo *floatIpInfo, uint32 dnIdx, int32 role, bool8 isDel) +{ + DnFloatIp *dnFloatIp = GetDnFloatIpByDnIdx(dnIdx); + if (dnFloatIp == NULL || dnFloatIp->dnFloatIpCount == 0) { + return CM_SUCCESS; + } + const char *str = "[GetDnNetStateFromFile]"; + uint32 instId = GetCurDnInstId(dnIdx); + if (GetDnListenAddressesFromFile(dnIpText, dnIdx) != CM_SUCCESS) { + write_runlog(LOG, "%s instId(%u) cannot get DnListAddresses.\n", str, instId); + return CM_ERROR; + } + if (dnIpText->dnText == NULL) { + write_runlog(LOG, "%s instId(%u) cannot find the dnIpText.\n", str, instId); + return CM_ERROR; + } + bool8 isAllListen = CM_FALSE; + for (uint32 i = 0; i < dnFloatIp->dnFloatIpCount; ++i) { + if (isAllListen || IsFindVipInDnText(dnIpText->dnText, dnFloatIp->dnFloatIp[i], isDel, &isAllListen)) { + floatIpInfo->dnNetState[i] = + (role != INSTANCE_ROLE_PRIMARY && isAllListen) ? (int32)NETWORK_STATE_DOWN : (int32)NETWORK_STATE_UP; + } else { + floatIpInfo->dnNetState[i] = (int32)NETWORK_STATE_DOWN; + } + } + return CM_SUCCESS; +} + +static void GetDnAllFloatIp(DnIpText *dnIpText, DnStatus *dnStatus, uint32 dnIdx, bool8 isRunning) +{ + DnFloatIp *dnFloatIp = GetDnFloatIpByDnIdx(dnIdx); + if (dnFloatIp == NULL || dnFloatIp->dnFloatIpCount == 0) { + return; + } + + DnFloatIpInfo *floatIpInfo = &(dnStatus->floatIpInfo.info); + floatIpInfo->count = dnFloatIp->dnFloatIpCount; + NetworkState state[MAX_FLOAT_IP_COUNT]; + GetFloatIpNicStatus(dnFloatIp->instId, CM_INSTANCE_TYPE_DN, state, MAX_FLOAT_IP_COUNT); + for (uint32 i = 0; i < floatIpInfo->count; ++i) { + floatIpInfo->nicNetState[i] = (int32)state[i]; + } + + int32 dnRole = dnStatus->reportMsg.local_status.local_role; + if (isRunning) { + GetAllFloatIpNetState(dnStatus, dnFloatIp, dnIdx, dnRole); + (void)GetDnListenAddressesFromFile(dnIpText, dnIdx); + return; + } + + if (GetDnNetStateFromFile(dnIpText, floatIpInfo, dnIdx, dnRole, CM_FALSE) == CM_SUCCESS) { + return; + } + ResetFloatIpDnNetState(dnStatus); +} + +static bool8 CheckExecuteCmdParam(DnIpText *dnIpText, uint32 dnIdx) +{ + DnFloatIp *dnFloatIp = GetDnFloatIpByDnIdx(dnIdx); + if (dnFloatIp == NULL) { + return CM_FALSE; + } + if (dnIpText->dnText == NULL || CM_IS_EMPTY_STR(dnIpText->dnText->result)) { + write_runlog(ERROR, "instId (%u) dnText is NULL.\n", GetCurDnInstId(dnIdx)); + return CM_FALSE; + } + status_t st = + GetDnCmd(dnIpText, (dnIpText->dnText->maxLen + CM_IP_LENGTH * dnFloatIp->dnFloatIpCount) + MAX_PATH_LEN); + if (st != CM_SUCCESS) { + write_runlog(ERROR, "instId (%u) dnCmd is NULL.\n", GetCurDnInstId(dnIdx)); + return CM_FALSE; + } + return CM_TRUE; +} + +static void SetDnFloatIpCmd(DnCmd *dnCmd, const char *curIp, bool8 *isFirstIp) +{ + uint32 curLen = (uint32)strlen(dnCmd->cmd); + if (curLen >= dnCmd->maxLen) { + write_runlog(ERROR, "cannot set dn floatIpCmd, when curLen=%u, maxLen=%u.\n", curLen, dnCmd->maxLen); + return; + } + errno_t rc; + if (!(*isFirstIp)) { + rc = snprintf_s(dnCmd->cmd + curLen, dnCmd->maxLen - curLen, (dnCmd->maxLen - curLen) - 1, + "%s%s", SEPARATOR_ARRAY, curIp); + } else { + *isFirstIp = CM_FALSE; + rc = snprintf_s(dnCmd->cmd + curLen, dnCmd->maxLen - curLen, (dnCmd->maxLen - curLen) - 1, + "%s", curIp); + } + securec_check_intval(rc, (void)rc); +} + +static void ClearCntIp(bool8 tmpFindCurIp, NetworkOper oper, char *ip, uint32 len, uint32 *clearCnt) +{ + if (tmpFindCurIp && oper == NETWORK_OPER_DOWN) { + errno_t rc = memset_s(ip, len, 0, len); + securec_check_errno(rc, (void)rc); + ++(*clearCnt); + } +} + +static status_t GetDnFloatIpCmd(const char *floatIp, DnIpText *dnIpText, NetworkOper oper, uint32 instId) +{ + DnResultText *dnText = dnIpText->dnText; + DnCmd *dnCmd = dnIpText->dnCmd; + uint32 curPoint = dnText->point; + char *curIp; + bool8 isFirstIp = CM_TRUE; + bool8 isFindCurIp = CM_FALSE; + bool8 tmpFindCurIp; + uint32 clearCnt = 0; + for (uint32 i = 0; i < dnText->cnt; ++i) { + while (curPoint < dnText->maxLen && dnText->result[curPoint] == '\0') { + ++curPoint; + } + + if (curPoint >= dnText->maxLen) { + write_runlog(ERROR, "%s instId(%u) cannot get floatIp cmd, when curPoint=[%u: %u].\n", + __FUNCTION__, instId, curPoint, dnText->maxLen); + return CM_ERROR; + } + + curIp = dnText->result + curPoint; + tmpFindCurIp = CM_FALSE; + if (IsSameIp(floatIp, curIp)) { + isFindCurIp = CM_TRUE; + tmpFindCurIp = CM_TRUE; + } else { + SetDnFloatIpCmd(dnCmd, curIp, &isFirstIp); + } + curPoint += (uint32)strlen(curIp); + ClearCntIp(tmpFindCurIp, oper, curIp, (uint32)strlen(curIp), &clearCnt); + } + + if (oper == NETWORK_OPER_UP) { + SetDnFloatIpCmd(dnCmd, floatIp, &isFirstIp); + if (!isFindCurIp && (curPoint + 1 + strlen(floatIp) < dnText->maxLen)) { + errno_t rc = snprintf_s(dnText->result + curPoint + 1, (dnText->maxLen - curPoint) - 1, + ((dnText->maxLen - curPoint) - 1) - 1, "%s", floatIp); + ++dnText->cnt; + securec_check_intval(rc, (void)rc); + } + } else if (oper == NETWORK_OPER_DOWN) { + dnText->cnt -= clearCnt; + if (isFirstIp) { + write_runlog(ERROR, "instId(%u) ip only has floatIp, cannot del it.\n", instId); + return CM_ERROR; + } + } + PrintDnText(dnText, instId, "[GetDnFloatIpCmd]"); + return CM_SUCCESS; +} + +static bool8 ExecuteFloatIpCmd(const char *floatIp, DnIpText *dnIpText, bool8 isRunning, + uint32 dnIdx, NetworkOper oper) +{ + CM_RETFALSE_IFNOT(CheckExecuteCmdParam(dnIpText, dnIdx)); + ResetDnCmd(dnIpText->dnCmd); + const char *cmdOper = isRunning ? "reload" : "set"; + DnCmd *dnCmd = dnIpText->dnCmd; + errno_t rc = snprintf_s(dnCmd->cmd, dnCmd->maxLen, dnCmd->maxLen - 1, "gs_guc %s " + "-Z datanode -D %s -c \"%s = \'", cmdOper, GetCurDnDataPath(dnIdx), LISTEN_ADDRESSES); + securec_check_intval(rc, (void)rc); + + uint32 instId = GetCurDnInstId(dnIdx); + if (GetDnFloatIpCmd(floatIp, dnIpText, oper, instId) != CM_SUCCESS) { + return CM_FALSE; + } + + uint32 cmdLen = (uint32)strlen(dnCmd->cmd); + if (cmdLen + 1 >= dnCmd->maxLen) { + write_runlog(ERROR, "instId(%u) failed to executeFloatIpCmd, because cmd[%s] is beyond the region[0: %u].\n", + instId, dnCmd->cmd, dnCmd->maxLen); + return CM_FALSE; + } + rc = snprintf_s(dnCmd->cmd + cmdLen, dnCmd->maxLen - cmdLen, (dnCmd->maxLen - cmdLen) - 1, + "\'\" >> \"%s\" 2>&1", system_call_log); + securec_check_intval(rc, (void)rc); + write_runlog(LOG, "[%s] it will execute the cmd[%s].\n", __FUNCTION__, dnCmd->cmd); + int32 res = ExecuteSystemCmd(dnCmd->cmd); + if (res != 0) { + write_runlog(ERROR, "instId(%u) failed to execute the cmd(%s), res=%d, errno is %d.\n", instId, dnCmd->cmd, + res, errno); + return CM_FALSE; + } + return CM_TRUE; +} + +static int32 ClearConn( + CltResultSet set, const cltPqResult_t *nodeResult, const char *sqlCommand, const SqlCond *sqlCond) +{ + const char *str = "[ClearConn]"; + write_runlog(LOG, "[%s: %u] %s sqlCommands[%s] listen_ip validate ok.\n", + sqlCond->str, sqlCond->instId, str, sqlCommand); + return 0; +} + +static int32 ClearDnIpConn(const char *ip, uint32 dnIdx) +{ + const char *str = "[ClearDnIpConn]"; + static cmTime_t lastTime = {0, 0}; + cmTime_t curTime = {0, 0}; + (void)clock_gettime(CLOCK_MONOTONIC, &curTime); + const long printInterval = 30; + // conn may be null for a long time + if (g_dnConn[dnIdx] == NULL) { + int32 logLevel = DEBUG1; + if (curTime.tv_sec - lastTime.tv_sec >= printInterval) { + (void)clock_gettime(CLOCK_MONOTONIC, &lastTime); + logLevel = LOG; + } + write_runlog(logLevel, "%s instId(%u) g_dnConn[%u] is null.\n", str, GetCurDnInstId(dnIdx), dnIdx); + return -1; + } + + char sqlCommand[MAX_PATH_LEN] = {0}; + errno_t rc = snprintf_s(sqlCommand, MAX_PATH_LEN, MAX_PATH_LEN - 1, "select gs_validate_ext_listen_ip('normal', " + "setting::cstring, '%s') from pg_settings where name = 'pgxc_node_name' limit 1;", ip); + securec_check_intval(rc, (void)rc); + SqlCond sqlCond = {.str="[ClearDnIpConn]", .instId = GetCurDnInstId(dnIdx)}; + return ExecDmlSqlCmd(ClearConn, NULL, &(g_dnConn[dnIdx]), sqlCommand, &sqlCond); +} + +static void ResetValidateWithExpect(DnValidate *validate, bool8 value, uint32 index) +{ + if (validate == NULL) { + write_runlog(LOG, "[ResetValidateWithExpect] instId(%u) validate is NULL.\n", GetCurDnInstId(index)); + return; + } + if (index >= validate->cnt) { + write_runlog(ERROR, "[ResetValidateWithExpect] instId(%u) validate cnt=[%u: %u].\n", + GetCurDnInstId(index), index, validate->cnt); + return; + } + validate->isReentrant[index] = value; +} + +static bool8 ExeVipCmdAndValidate(uint32 index, DnIpText *dnIpText, bool8 isRunning, uint32 dnIdx, NetworkOper oper) +{ + DnFloatIp *dnFloatIp = GetDnFloatIpByDnIdx(dnIdx); + if (dnFloatIp == NULL) { + return CM_TRUE; + } + bool8 ret = ExecuteFloatIpCmd(dnFloatIp->dnFloatIp[index], dnIpText, isRunning, dnIdx, oper); + if (oper == NETWORK_OPER_DOWN) { + if (ret && isRunning) { + int32 execRet = ClearDnIpConn(dnFloatIp->dnFloatIp[index], dnIdx); + status_t st = GetDnValidate(dnIpText, dnFloatIp->dnFloatIpCount); + if (st != CM_SUCCESS) { + write_runlog(ERROR, "[DoFloatIpOper] instId(%u) failed to get dn validate.\n", GetCurDnInstId(dnIdx)); + return ret; + } + dnIpText->validate->isReentrant[index] = (execRet == 0) ? CM_FALSE : CM_TRUE; + } else { + ResetValidateWithExpect(dnIpText->validate, CM_TRUE, dnIdx); + } + } else { + ResetDnValidate(dnIpText); + } + return ret; +} + +static void DoFloatIpOper(DnIpText *dnIpText, const DnStatus *dnStatus, uint32 dnIdx, bool8 isRunning) +{ + DnFloatIp *dnFloatIp = GetDnFloatIpByDnIdx(dnIdx); + if (dnFloatIp == NULL) { + return; + } + + NetworkOper oper = GetFloatIpOper(dnIdx); + if (oper != NETWORK_OPER_UP && oper != NETWORK_OPER_DOWN) { + return; + } + if (oper == NETWORK_OPER_UP && dnStatus->reportMsg.local_status.local_role != INSTANCE_ROLE_PRIMARY) { + return; + } + + bool8 isAllFinish = CM_TRUE; + bool8 singleFinish; + for (uint32 i = 0; i < dnFloatIp->dnFloatIpCount; ++i) { + if (IsLocalHostIp(dnFloatIp->dnFloatIp[i])) { + continue; + } + + if (oper == NETWORK_OPER_UP && dnStatus->floatIpInfo.info.nicNetState[i] != (int32)NETWORK_STATE_UP) { + SetNicOper(dnFloatIp->instId, CM_INSTANCE_TYPE_DN, NETWORK_TYPE_FLOATIP, oper); + isAllFinish = CM_FALSE; + continue; + } + singleFinish = ExeVipCmdAndValidate(i, dnIpText, isRunning, dnIdx, oper); + isAllFinish = (bool8)(singleFinish && isAllFinish); + SetNicOper(dnFloatIp->instId, CM_INSTANCE_TYPE_DN, NETWORK_TYPE_FLOATIP, oper); + } + if (isAllFinish) { + SetFloatIpOper(dnIdx, NETWORK_OPER_UNKNOWN, "[DoFloatIpOper]"); + } +} + +static void CheckDownFloatIp(DnIpText *dnIpText, const DnStatus *dnStatus, uint32 dnIdx, bool8 isRunning) +{ + if (dnStatus->reportMsg.local_status.local_role == INSTANCE_ROLE_PRIMARY && isRunning) { + return; + } + DnFloatIp *dnFloatIp = GetDnFloatIpByDnIdx(dnIdx); + if (dnFloatIp == NULL) { + return; + } + SetNicOper(dnFloatIp->instId, CM_INSTANCE_TYPE_DN, NETWORK_TYPE_FLOATIP, NETWORK_OPER_DOWN); + const DnFloatIpInfo *dnInfo = &(dnStatus->floatIpInfo.info); + for (uint32 i = 0; i < dnFloatIp->dnFloatIpCount; ++i) { + if (dnInfo->dnNetState[i] != (int32)NETWORK_STATE_UP) { + continue; + } + (void)ExeVipCmdAndValidate(i, dnIpText, isRunning, dnIdx, NETWORK_OPER_DOWN); + } +} + +static void ClearFloatIpConn(DnIpText *dnIpText, const DnStatus *dnStatus, bool8 isRunning, uint32 dnIdx) +{ + if (dnStatus->reportMsg.local_status.local_role == INSTANCE_ROLE_PRIMARY && isRunning) { + ResetDnValidate(dnIpText); + return; + } + DnFloatIp *dnFloatIp = GetDnFloatIpByDnIdx(dnIdx); + status_t st = GetDnValidate(dnIpText, dnFloatIp->dnFloatIpCount); + if (st != CM_SUCCESS) { + write_runlog(ERROR, "[ClearFloatIpConn] failed to get dn validate.\n"); + return; + } + DnValidate *validate = dnIpText->validate; + if (validate == NULL) { + write_runlog(LOG, "[ClearFloatIpConn] validate is NULL, cannot ClearFloatIpConn.\n"); + return; + } + if (!isRunning) { + return; + } + for (uint32 i = 0; i < validate->cnt && i < dnFloatIp->dnFloatIpCount; ++i) { + if (!validate->isReentrant[i]) { + continue; + } + validate->isReentrant[i] = (ClearDnIpConn(dnFloatIp->dnFloatIp[i], dnIdx) == 0) ? CM_FALSE : CM_TRUE; + } +} + +void DnCheckFloatIp(DnStatus *dnStatus, uint32 dnIdx, bool8 isRunning) +{ + if (!IsNeedCheckFloatIp() || (agent_backup_open != CLUSTER_PRIMARY)) { + return; + } + DnFloatIp *dnFloatIp = GetDnFloatIpByDnIdx(dnIdx); + if (dnFloatIp == NULL || dnFloatIp->dnFloatIpCount == 0) { + return; + } + DnIpText *dnIpText = GetDnIpText(dnIdx); + if (dnIpText == NULL) { + write_runlog(ERROR, "failed to get dn ip text.\n"); + return; + } + ResetDnText(dnIpText->dnText); + GetDnAllFloatIp(dnIpText, dnStatus, dnIdx, isRunning); + DoFloatIpOper(dnIpText, dnStatus, dnIdx, isRunning); + CheckDownFloatIp(dnIpText, dnStatus, dnIdx, isRunning); + ClearFloatIpConn(dnIpText, dnStatus, isRunning, dnIdx); + return; +} + +uint32 DelFloatIpInDatanode(uint32 dnIdx) +{ + if (!IsNeedCheckFloatIp() || (agent_backup_open != CLUSTER_PRIMARY)) { + return 0; + } + DnFloatIp *dnFloatIp = GetDnFloatIpByDnIdx(dnIdx); + if (dnFloatIp == NULL || dnFloatIp->dnFloatIpCount == 0) { + return 0; + } + DnIpText *dnIpText = GetCurDnIpText(); + ResetDnText(dnIpText->dnText); + uint32 cnt = 0; + DnFloatIpInfo floatIpInfo = {0}; + (void)GetDnNetStateFromFile(dnIpText, &floatIpInfo, dnIdx, INSTANCE_ROLE_UNKNOWN, CM_TRUE); + SetNicOper(dnFloatIp->instId, CM_INSTANCE_TYPE_DN, NETWORK_TYPE_FLOATIP, NETWORK_OPER_DOWN); + for (uint32 i = 0; i < dnFloatIp->dnFloatIpCount; ++i) { + if (floatIpInfo.dnNetState[i] != (int32)NETWORK_STATE_UP) { + continue; + } + if (!ExecuteFloatIpCmd(dnFloatIp->dnFloatIp[i], dnIpText, CM_FALSE, dnIdx, NETWORK_OPER_DOWN)) { + ++cnt; + } + } + write_runlog(LOG, "it will del floatIp In datanode, cnt=%u.\n", cnt); + return cnt; +} diff --git a/src/cm_agent/client_adpts/libpq/cma_libpq_com.cpp b/src/cm_agent/client_adpts/libpq/cma_libpq_com.cpp new file mode 100644 index 0000000..cb402de --- /dev/null +++ b/src/cm_agent/client_adpts/libpq/cma_libpq_com.cpp @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2023 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. + * ------------------------------------------------------------------------- + * + * cma_libpq_com.cpp + * + * IDENTIFICATION + * src/cm_agent/client_adpts/libpq/cma_libpq_com.cpp + * + * ------------------------------------------------------------------------- + */ +#include "cma_libpq_com.h" + +#include "cm_elog.h" + +int ExecDmlSqlCmd(ResultSetHandle handle, CltResultSet set, cltPqConn_t **conn, const char *sqlCommand, + const SqlCond *sqlCond) +{ + uint32 instId = 0; + const char *str = "unknown"; + if (sqlCond != NULL) { + instId = sqlCond->instId; + str = sqlCond->str; + } + + if (conn == NULL || (*conn) == NULL) { + write_runlog(ERROR, "[%s: %u] cannot execute sqlCommand[%s], bacause conn is NULL.\n", str, instId, sqlCommand); + return -1; + } + + cltPqResult_t *nodeResult = Exec((*conn), sqlCommand); + if (nodeResult == NULL) { + write_runlog(ERROR, "[%s: %u] sqlCommands[%s] fail return NULL, errmsg is %s.\n", + str, instId, sqlCommand, ErrorMessage(*conn)); + CLOSE_CONNECTION(*conn); + } + + if ((ResultStatus(nodeResult) != CLTPQRES_CMD_OK) && (ResultStatus(nodeResult) != CLTPQRES_TUPLES_OK)) { + write_runlog(ERROR, "[%s: %u] sqlCommand[%s] fail ResultStatus=%d, errmsg is %s.\n", + str, instId, sqlCommand, (int32)ResultStatus(nodeResult), ErrorMessage(*conn)); + CLEAR_AND_CLOSE_CONNECTION(nodeResult, (*conn)); + } + + if (handle != NULL) { + if (handle(set, nodeResult, sqlCommand, sqlCond) != 0) { + CLEAR_AND_CLOSE_CONNECTION(nodeResult, (*conn)); + } + } + Clear(nodeResult); + return 0; +} diff --git a/src/cm_agent/cma_common.cpp b/src/cm_agent/cma_common.cpp index 2f9f1c1..16121df 100644 --- a/src/cm_agent/cma_common.cpp +++ b/src/cm_agent/cma_common.cpp @@ -923,22 +923,28 @@ uint32 CheckDiskForLogPath(void) return percent; } -int ExecuteSystemCmd(const char *cmd) +int ExecuteSystemCmd(const char *cmd, int32 logLevel, int32 *errCode) { int ret = system(cmd); if (ret == -1) { - write_runlog(ERROR, "Fail to execute command %s, and errno=%d.\n", cmd, errno); - return -1; + // shield error codes 10 (no child processes), it may be much + const int32 noChildProcessesErrCode = 10; + int32 tmpLevel = (errno == noChildProcessesErrCode) ? logLevel : ERROR; + write_runlog(tmpLevel, "Fail to execute command %s, and errno=%d.\n", cmd, errno); + return ERROR_EXECUTE_CMD; } if (WIFEXITED(ret)) { if (WEXITSTATUS(ret) == 0) { - return 0; + return SUCCESS_EXECUTE_CMD; } } - write_runlog(ERROR, "Fail to execute command %s, script exit code %d.\n", cmd, WEXITSTATUS(ret)); - return -1; + write_runlog(logLevel, "Fail to execute command %s, script exit code %d.\n", cmd, WEXITSTATUS(ret)); + if (errCode != NULL) { + *errCode = WEXITSTATUS(ret); + } + return FAILED_EXECUTE_CMD; } void CheckDnNicDown(uint32 index) diff --git a/src/cm_agent/cma_connect.cpp b/src/cm_agent/cma_connect.cpp index 6fde8e0..670be54 100644 --- a/src/cm_agent/cma_connect.cpp +++ b/src/cm_agent/cma_connect.cpp @@ -27,6 +27,8 @@ #include "cm/cs_ssl.h" #include "cma_common.h" #include "cma_instance_check.h" +#include "cma_instance_management_res.h" +#include "cma_process_messages_client.h" #include "cma_connect.h" #ifdef ENABLE_MULTIPLE_NODES #include "cma_coordinator.h" @@ -368,6 +370,9 @@ static void CloseConnToCmserver(void) write_runlog(LOG, "close agent to cmserver connection.\n"); } CleanCmsMsgQueue(); + if (IsCusResExistLocal()) { + NotifyClientConnectClose(); + } } static status_t SendCmsMsgMain() diff --git a/src/cm_agent/cma_connect_client.cpp b/src/cm_agent/cma_connect_client.cpp index 5d3daf3..fb3ce7f 100644 --- a/src/cm_agent/cma_connect_client.cpp +++ b/src/cm_agent/cma_connect_client.cpp @@ -317,6 +317,9 @@ static void RecvClientMsgMain(int epollfd, int eventNums, const ListenPort *list void* RecvClientEventsMain(void * const arg) { + thread_name = "RecvClientMsg"; + write_runlog(LOG, "recv msg from client thread begin, threadId:%lu.\n", (unsigned long)pthread_self()); + int epollfd; ListenPort listenfd; struct epoll_event events[MAX_EVENTS]; diff --git a/src/cm_agent/cma_instance_management.cpp b/src/cm_agent/cma_instance_management.cpp index e94ac14..002e4fd 100644 --- a/src/cm_agent/cma_instance_management.cpp +++ b/src/cm_agent/cma_instance_management.cpp @@ -50,6 +50,7 @@ static bool IsCmsReplaceFlagFileExists(); static void StopCmInstance(); static void StopOneZengine(uint32 index); +static bool StopCurDnFloatIp(uint32 index); #ifdef ENABLE_GCOV static const int SIG_TYPE = 2; @@ -680,6 +681,7 @@ void stop_datanode_check(uint32 i) g_isDnFirstStart = true; } + (void)StopCurDnFloatIp(i); } } @@ -732,6 +734,39 @@ static int cmserver_stopped_check(void) return PROCESS_NOT_EXIST; } +static NetworkState CheckCurDnFloatIpStatus(uint32 index) +{ + DnFloatIp *dnFloatIp = GetDnFloatIpByDnIdx(index); + if (dnFloatIp == NULL || dnFloatIp->dnFloatIpCount == 0) { + return NETWORK_STATE_UNKNOWN; + } + NetworkState state[MAX_FLOAT_IP_COUNT]; + GetFloatIpNicStatus(dnFloatIp->instId, CM_INSTANCE_TYPE_DN, state, dnFloatIp->dnFloatIpCount); + for (uint32 i = 0; i < dnFloatIp->dnFloatIpCount; ++i) { + if (state[i] == NETWORK_STATE_UP) { + return NETWORK_STATE_UP; + } + } + return NETWORK_STATE_DOWN; +} + +static int32 CheckFloatIpStateInDn(uint32 index) +{ + uint32 count = DelFloatIpInDatanode(index); + if (count != 0) { + write_runlog( + LOG, "line: %d: datanode(%u) floatIp is running.\n", __LINE__, g_currentNode->datanode[index].datanodeId); + return PROCESS_RUNNING; + } + NetworkState state = CheckCurDnFloatIpStatus(index); + if (state == NETWORK_STATE_UP) { + write_runlog( + LOG, "line: %d: datanode(%u) floatIp is running.\n", __LINE__, g_currentNode->datanode[index].datanodeId); + return PROCESS_RUNNING; + } + return PROCESS_NOT_EXIST; +} + static int datanode_stopped_check(void) { int ret; @@ -756,6 +791,9 @@ static int datanode_stopped_check(void) write_runlog(LOG, "data node is running path is %s\n", g_currentNode->datanode[ii].datanodeLocalDataPath); return PROCESS_RUNNING; } + if (CheckFloatIpStateInDn(ii) == PROCESS_RUNNING) { + return PROCESS_RUNNING; + } } return PROCESS_NOT_EXIST; @@ -1335,6 +1373,7 @@ static void NormalShutdownAllDatanode() } else { NormalShutdownOneDatanode(dnInfo, g_dnReportMsg[i].dnStatus.reportMsg.local_status.local_role); } + DelAndDownFloatIpInDn(i); } } @@ -1402,6 +1441,12 @@ static void ShutdownOneDatanode(const dataNodeInfo *dnInfo) immediate_stop_one_instance(dnInfo->datanodeLocalDataPath, INSTANCE_DN); } +void DelAndDownFloatIpInDn(uint32 index) +{ + (void)DelFloatIpInDatanode(index); + SetNicOper(g_currentNode->datanode[index].datanodeId, CM_INSTANCE_TYPE_DN, NETWORK_TYPE_FLOATIP, NETWORK_OPER_DOWN); +} + static void ImmediateShutdownAllDatanode() { for (uint32 ii = 0; ii < g_currentNode->datanodeCount; ii++) { @@ -1410,6 +1455,7 @@ static void ImmediateShutdownAllDatanode() } else { ShutdownOneDatanode(&g_currentNode->datanode[ii]); } + DelAndDownFloatIpInDn(ii); } } @@ -1455,6 +1501,7 @@ static void FastShutdownAllDatanode() } else { fast_stop_one_instance(g_currentNode->datanode[ii].datanodeLocalDataPath, INSTANCE_DN); } + DelAndDownFloatIpInDn(ii); } } @@ -1553,6 +1600,22 @@ void StopZengineByCmd(uint32 index) immediate_stop_one_instance(g_currentNode->datanode[index].datanodeLocalDataPath, INSTANCE_DN); } +static bool StopCurDnFloatIp(uint32 index) +{ + uint32 count = DelFloatIpInDatanode(index); + if (count != 0) { + return false; + } + NetworkState state = CheckCurDnFloatIpStatus(index); + if (state != NETWORK_STATE_UP) { + return true; + } + write_runlog( + LOG, "instId(%u) FloatIp is running, it need to be stopped.\n", g_currentNode->datanode[index].datanodeId); + SetNicOper(g_currentNode->datanode[index].datanodeId, CM_INSTANCE_TYPE_DN, NETWORK_TYPE_FLOATIP, NETWORK_OPER_DOWN); + return false; +} + static void StopOneZengine(uint32 index) { bool dnManualStop = DnManualStop(index); @@ -1574,6 +1637,11 @@ static void StopOneZengine(uint32 index) StopZengineByCmd(index); return; } + + if (!StopCurDnFloatIp(index)) { + return; + } + write_runlog(LOG, "datanode is not running, no need to shutdown: %s.\n", g_currentNode->datanode[index].datanodeLocalDataPath); diff --git a/src/cm_agent/cma_instance_management_res.cpp b/src/cm_agent/cma_instance_management_res.cpp index 0ae3b04..7043b24 100644 --- a/src/cm_agent/cma_instance_management_res.cpp +++ b/src/cm_agent/cma_instance_management_res.cpp @@ -30,17 +30,29 @@ uint32 g_localResConfCount = 0; -int SystemExecute(const char *scriptPath, const char *oper, uint32 timeout) +static int CusResCmdExecute(const char *scriptPath, const char *oper, uint32 timeout, bool8 needNohup) { char command[MAX_PATH_LEN + MAX_OPTION_LEN] = {0}; - int ret = snprintf_s(command, - MAX_PATH_LEN + MAX_OPTION_LEN, - MAX_PATH_LEN + MAX_OPTION_LEN - 1, - SYSTEMQUOTE "timeout -s SIGKILL %us %s %s > %s" SYSTEMQUOTE, - timeout, - scriptPath, - oper, - CM_DEVNULL); + int ret; + if (needNohup) { + ret = snprintf_s(command, + MAX_PATH_LEN + MAX_OPTION_LEN, + MAX_PATH_LEN + MAX_OPTION_LEN - 1, + SYSTEMQUOTE "nohup timeout -s SIGKILL %us %s %s > %s &" SYSTEMQUOTE, + timeout, + scriptPath, + oper, + CM_DEVNULL); + } else { + ret = snprintf_s(command, + MAX_PATH_LEN + MAX_OPTION_LEN, + MAX_PATH_LEN + MAX_OPTION_LEN - 1, + SYSTEMQUOTE "timeout -s SIGKILL %us %s %s > %s" SYSTEMQUOTE, + timeout, + scriptPath, + oper, + CM_DEVNULL); + } securec_check_intval(ret, (void)ret); int status = system(command); if (status == -1) { @@ -63,7 +75,7 @@ status_t StartOneResInst(const CmResConfList *conf) int ret = snprintf_s(oper, MAX_OPTION_LEN, MAX_OPTION_LEN - 1, "-start %u %s", conf->resInstanceId, conf->arg); securec_check_intval(ret, (void)ret); - ret = SystemExecute(conf->script, oper, (uint32)conf->checkInfo.timeOut); + ret = CusResCmdExecute(conf->script, oper, (uint32)conf->checkInfo.timeOut, CM_FALSE); if (ret == 0) { write_runlog(LOG, "StartOneResInst: run start script (%s %s) successfully.\n", conf->script, oper); } else if (ret == CUS_RES_START_FAIL_DEPEND_NOT_ALIVE) { @@ -83,7 +95,7 @@ void StopOneResInst(const CmResConfList *conf) int ret = snprintf_s(oper, MAX_OPTION_LEN, MAX_OPTION_LEN - 1, "-stop %u %s", conf->resInstanceId, conf->arg); securec_check_intval(ret, (void)ret); - ret = SystemExecute(conf->script, oper, (uint32)conf->checkInfo.timeOut); + ret = CusResCmdExecute(conf->script, oper, (uint32)conf->checkInfo.timeOut, CM_FALSE); if (ret == 0) { write_runlog(LOG, "StopOneResInst: run stop command (%s %s) successfully.\n", conf->script, oper); } else { @@ -112,12 +124,13 @@ status_t RegOneResInst(const CmResConfList *conf, uint32 destInstId) int ret = snprintf_s(oper, MAX_OPTION_LEN, MAX_OPTION_LEN - 1, "-reg %u %s", destInstId, conf->arg); securec_check_intval(ret, (void)ret); - ret = SystemExecute(conf->script, oper, (uint32)conf->checkInfo.timeOut); + ret = CusResCmdExecute(conf->script, oper, (uint32)conf->checkInfo.timeOut, CM_TRUE); if (ret != 0) { - write_runlog(ERROR, "RegOneResInst: reg inst cmd(%s %s) failed, ret=%d\n", conf->script, oper, ret); + write_runlog(ERROR, "[%s]: cmd:(%s %s) execute failed, ret=%d.\n", __FUNCTION__, conf->script, oper, ret); return CM_ERROR; } - write_runlog(LOG, "RegOneResInst: reg inst cmd(%s %s) success\n", conf->script, oper); + + write_runlog(LOG, "[%s]: cmd:(%s %s) is executing.\n", __FUNCTION__, conf->script, oper); return CM_SUCCESS; } @@ -127,12 +140,13 @@ status_t UnregOneResInst(const CmResConfList *conf, uint32 destInstId) int ret = snprintf_s(oper, MAX_OPTION_LEN, MAX_OPTION_LEN - 1, "-unreg %u %s", destInstId, conf->arg); securec_check_intval(ret, (void)ret); - ret = SystemExecute(conf->script, oper, (uint32)conf->checkInfo.timeOut); + ret = CusResCmdExecute(conf->script, oper, (uint32)conf->checkInfo.timeOut, CM_TRUE); if (ret != 0) { - write_runlog(ERROR, "UnregOneResInst: unreg inst cmd:(%s %s) failed, ret=%d\n", conf->script, oper, ret); + write_runlog(ERROR, "[%s]: cmd:(%s %s) execute failed, ret=%d.\n", __FUNCTION__, conf->script, oper, ret); return CM_ERROR; } - write_runlog(LOG, "UnregOneResInst: unreg inst cmd:(%s %s) success\n", conf->script, oper); + + write_runlog(LOG, "[%s]: cmd:(%s %s) is executing.\n", __FUNCTION__, conf->script, oper); return CM_SUCCESS; } @@ -143,7 +157,7 @@ ResIsregStatus IsregOneResInst(const CmResConfList *conf, uint32 destInstId) int ret = snprintf_s(oper, MAX_OPTION_LEN, MAX_OPTION_LEN - 1, "-isreg %u %s", destInstId, conf->arg); securec_check_intval(ret, (void)ret); - ret = SystemExecute(conf->script, oper, (uint32)conf->checkInfo.timeOut); + ret = CusResCmdExecute(conf->script, oper, (uint32)conf->checkInfo.timeOut, CM_FALSE); switch (ret) { case RES_INST_ISREG_UNKNOWN: write_runlog(DEBUG5, "IsregOneResInst: res(%s) inst(%u) get isreg error.\n", conf->resName, destInstId); @@ -175,7 +189,7 @@ status_t CleanOneResInst(const CmResConfList *conf) int ret = snprintf_s(oper, MAX_OPTION_LEN, MAX_OPTION_LEN - 1, "-clean %u %s", conf->resInstanceId, conf->arg); securec_check_intval(ret, (void)ret); - ret = SystemExecute(conf->script, oper, (uint32)conf->checkInfo.timeOut); + ret = CusResCmdExecute(conf->script, oper, (uint32)conf->checkInfo.timeOut, CM_FALSE); if (ret != 0) { write_runlog(ERROR, "CleanOneResInst: clean inst cmd(%s %s) failed, ret=%d\n", conf->script, oper, ret); return CM_ERROR; @@ -184,21 +198,43 @@ status_t CleanOneResInst(const CmResConfList *conf) return CM_SUCCESS; } +static void StopCurNodeFloatIp() +{ + for (uint32 i = 0; i < g_currentNode->datanodeCount; ++i) { + DelAndDownFloatIpInDn(i); + } +} + static inline void CleanOneInstCheckCount(CmResConfList *resConf) { if (resConf->checkInfo.startCount != 0) { - write_runlog(LOG, "res(%s) inst(%u) restart times will clean.\n", resConf->resName, resConf->cmInstanceId); + write_runlog(LOG, "res(%s) inst(%u) restart times clean.\n", resConf->resName, resConf->cmInstanceId); } resConf->checkInfo.startCount = 0; resConf->checkInfo.startTime = 0; resConf->checkInfo.brokeTime = 0; } +static inline void CleanOneInstAbnormalStat(CmResConfList *resConf, int curStat) +{ + if (resConf->checkInfo.abnormalTime != 0) { + write_runlog(LOG, "res(%s) inst(%u) status from abnormal change to %d.\n", + resConf->resName, resConf->cmInstanceId, curStat); + resConf->checkInfo.abnormalTime = 0; + } +} + +static inline void CleanOneInstOnlineTimes(CmResConfList *resConf) +{ + resConf->checkInfo.onlineTimes = 0; +} + void StopAllResInst() { for (uint32 i = 0; i < GetLocalResConfCount(); ++i) { OneResInstClean(&g_resConf[i]); } + StopCurNodeFloatIp(); } int CheckOneResInst(const CmResConfList *conf) @@ -207,8 +243,9 @@ int CheckOneResInst(const CmResConfList *conf) int ret = snprintf_s(oper, MAX_OPTION_LEN, MAX_OPTION_LEN - 1, "-check %u %s", conf->resInstanceId, conf->arg); securec_check_intval(ret, (void)ret); - ret = SystemExecute(conf->script, oper, (uint32)conf->checkInfo.timeOut); - if ((ret != CUS_RES_CHECK_STAT_ONLINE) && (ret != CUS_RES_CHECK_STAT_OFFLINE)) { + ret = CusResCmdExecute(conf->script, oper, (uint32)conf->checkInfo.timeOut, CM_FALSE); + if ((ret != CUS_RES_CHECK_STAT_ONLINE) && (ret != CUS_RES_CHECK_STAT_OFFLINE) && + (ret != CUS_RES_CHECK_STAT_ABNORMAL)) { write_runlog(LOG, "CheckOneResInst, run system command(%s %s) special result=%d\n", conf->script, oper, ret); } return ret; @@ -272,6 +309,8 @@ static inline status_t RestartOneResInst(CmResConfList *conf) static void ProcessOfflineInstance(CmResConfList *conf) { + long curTime = GetCurMonotonicTimeSec(); + if (conf->checkInfo.restartTimes == -1) { if (CanCusInstDoRestart(conf)) { (void)RestartOneResInst(conf); @@ -279,22 +318,22 @@ static void ProcessOfflineInstance(CmResConfList *conf) return; } if (conf->checkInfo.brokeTime == 0) { - conf->checkInfo.brokeTime = time(NULL); + conf->checkInfo.brokeTime = curTime; return; } if (conf->checkInfo.startCount >= conf->checkInfo.restartTimes) { write_runlog(LOG, "res(%s) inst(%u) is offline, but restart times (%d) >= limit (%d), can't do restart again, " - "will do manually stop.\n", conf->resName, conf->resInstanceId, conf->checkInfo.startCount, + "will do manually stop.\n", conf->resName, conf->cmInstanceId, conf->checkInfo.startCount, conf->checkInfo.restartTimes); ManualStopLocalResInst(conf); return; } - if ((time(NULL) - conf->checkInfo.brokeTime) < conf->checkInfo.restartDelay) { + if ((curTime - conf->checkInfo.brokeTime) < conf->checkInfo.restartDelay) { write_runlog(DEBUG5, "[CLIENT] res(%s) inst(%u) curTime=%ld, brokeTime=%ld, restartDelay=%d.\n", - conf->resName, conf->resInstanceId, time(NULL), conf->checkInfo.brokeTime, conf->checkInfo.restartDelay); + conf->resName, conf->resInstanceId, curTime, conf->checkInfo.brokeTime, conf->checkInfo.restartDelay); return; } - if ((time(NULL) - conf->checkInfo.startTime) < conf->checkInfo.restartPeriod) { + if ((curTime - conf->checkInfo.startTime) < conf->checkInfo.restartPeriod) { write_runlog(DEBUG5, "[CLIENT] res(%s) inst(%u) startTime = %ld, restartPeriod = %d.\n", conf->resName, conf->resInstanceId, conf->checkInfo.startTime, conf->checkInfo.restartPeriod); return; @@ -304,11 +343,49 @@ static void ProcessOfflineInstance(CmResConfList *conf) } CM_RETVOID_IFERR(RestartOneResInst(conf)); conf->checkInfo.startCount++; - conf->checkInfo.startTime = time(NULL); + conf->checkInfo.startTime = curTime; write_runlog(LOG, "res(%s) inst(%u) has been restart (%d) times, restart more than (%d) time will manually stop.\n", conf->resName, conf->cmInstanceId, conf->checkInfo.startCount, conf->checkInfo.restartTimes); } +static void ProcessAbnormalInstance(CmResConfList *conf) +{ + long curTime = GetCurMonotonicTimeSec(); + if (conf->checkInfo.abnormalTime == 0) { + conf->checkInfo.abnormalTime = curTime; + } + + const int writeLogInterval = 10; + int duration = (int)(curTime - conf->checkInfo.abnormalTime); + if (duration < conf->checkInfo.abnormalTimeout) { + if ((duration > 0) && (duration % writeLogInterval == 0)) { + write_runlog(LOG, "res(%s) inst(%u) has been abnormal (%d)s, timeout is (%d)s.\n", + conf->resName, conf->cmInstanceId, duration, conf->checkInfo.abnormalTimeout); + } + return; + } + + if ((conf->checkInfo.startCount >= conf->checkInfo.restartTimes) && (conf->checkInfo.restartTimes != -1)) { + write_runlog(LOG, "res(%s) inst(%u) is abnormal, but restart times (%d) >= limit (%d), can't do restart again, " + "will do manually stop.\n", + conf->resName, conf->cmInstanceId, conf->checkInfo.startCount, conf->checkInfo.restartTimes); + ManualStopLocalResInst(conf); + return; + } + + write_runlog(LOG, "res(%s) inst(%u) has been abnormal (%d)s, >= timeout(%d)s, need restart.\n", + conf->resName, conf->cmInstanceId, duration, conf->checkInfo.abnormalTimeout); + + CM_RETVOID_IFERR(RestartOneResInst(conf)); + conf->checkInfo.startCount++; + conf->checkInfo.startTime = curTime; + + if (conf->checkInfo.restartTimes != -1) { + write_runlog(LOG, "res(%s) inst(%u) has been restart (%d) times, restart more (%d) time will manually stop.\n", + conf->resName, conf->cmInstanceId, conf->checkInfo.startCount, conf->checkInfo.restartTimes); + } +} + static inline bool NeedStopResInst(const char *resName, uint32 cmInstId) { return (IsInstManualStopped(cmInstId) || CmFileExist(g_cmManualStartPath) || !IsOneResInstWork(resName, cmInstId) || @@ -333,18 +410,34 @@ void StartResourceCheck() switch (ret) { case CUS_RES_CHECK_STAT_ONLINE: ProcessOnlineInstance(&g_resConf[i]); + CleanOneInstAbnormalStat(&g_resConf[i], CUS_RES_CHECK_STAT_ONLINE); break; case CUS_RES_CHECK_STAT_OFFLINE: - g_resConf[i].checkInfo.onlineTimes = 0; + CleanOneInstOnlineTimes(&g_resConf[i]); + CleanOneInstAbnormalStat(&g_resConf[i], CUS_RES_CHECK_STAT_OFFLINE); if (NeedStopResInst(g_resConf[i].resName, g_resConf[i].cmInstanceId)) { CleanOneInstCheckCount(&g_resConf[i]); break; } ProcessOfflineInstance(&g_resConf[i]); break; - default : + case CUS_RES_CHECK_STAT_ABNORMAL: + CleanOneInstOnlineTimes(&g_resConf[i]); + if (!IsOneResInstWork(g_resConf[i].resName, g_resConf[i].cmInstanceId)) { + write_runlog(LOG, "res(%s) inst(%u) is abnormal, but has been kick out, need stop it.\n", + g_resConf[i].resName, g_resConf[i].cmInstanceId); + (void)CleanOneResInst(&g_resConf[i]); + break; + } + if (IsInstManualStopped(g_resConf[i].cmInstanceId) || CmFileExist(g_cmManualStartPath)) { + CleanOneInstCheckCount(&g_resConf[i]); + break; + } + ProcessAbnormalInstance(&g_resConf[i]); + break; + default: write_runlog(ERROR, "StartResourceCheck, special status(%d).\n", ret); - break ; + break; } } } @@ -381,7 +474,8 @@ void StopResourceCheck() int ResourceStoppedCheck(void) { for (uint32 i = 0; i < GetLocalResConfCount(); ++i) { - if (CheckOneResInst(&g_resConf[i]) == CUS_RES_CHECK_STAT_ONLINE) { + int ret = CheckOneResInst(&g_resConf[i]); + if (ret == CUS_RES_CHECK_STAT_ONLINE || ret == CUS_RES_CHECK_STAT_ABNORMAL) { write_runlog(LOG, "resource is running, script is %s\n", g_resConf[i].script); return PROCESS_RUNNING; } @@ -418,12 +512,14 @@ static status_t InitResNameConf(const char *resNameJson, char *resNameConf) return CM_SUCCESS; } -static inline void InitOneConfOfRes(const char *paraName, int value, int *newValue, int defValue) +static inline void InitOneConfOfRes(const char *paraName, int value, int *newValue) { if (IsResConfValid(paraName, value)) { *newValue = value; } else { - *newValue = defValue; + *newValue = CmAtoi(ResConfDefValue(paraName), 0); + write_runlog(ERROR, "\"%s\":%d out of range, range [%d, %d], use default value(%d).\n", + paraName, value, ResConfMinValue(paraName), ResConfMaxValue(paraName), *newValue); } } @@ -437,16 +533,12 @@ static status_t InitLocalCommConfOfDefRes(const CusResConfJson *resJson, CmResCo securec_check_errno(rc, (void)rc); canonicalize_path(localConf->script); - const int defCheckInterval = 1; - InitOneConfOfRes("check_interval", resJson->checkInterval, &localConf->checkInfo.checkInterval, defCheckInterval); - const int defTimeOut = 10; - InitOneConfOfRes("time_out", resJson->timeOut, &localConf->checkInfo.timeOut, defTimeOut); - const int defRestartDelay = 1; - InitOneConfOfRes("restart_delay", resJson->restartDelay, &localConf->checkInfo.restartDelay, defRestartDelay); - const int defRestartPeriod = 1; - InitOneConfOfRes("restart_period", resJson->restartPeriod, &localConf->checkInfo.restartPeriod, defRestartPeriod); - const int defRestartTimes = -1; - InitOneConfOfRes("restart_times", resJson->restartTimes, &localConf->checkInfo.restartTimes, defRestartTimes); + InitOneConfOfRes("check_interval", resJson->checkInterval, &localConf->checkInfo.checkInterval); + InitOneConfOfRes("time_out", resJson->timeOut, &localConf->checkInfo.timeOut); + InitOneConfOfRes("restart_delay", resJson->restartDelay, &localConf->checkInfo.restartDelay); + InitOneConfOfRes("restart_period", resJson->restartPeriod, &localConf->checkInfo.restartPeriod); + InitOneConfOfRes("restart_times", resJson->restartTimes, &localConf->checkInfo.restartTimes); + InitOneConfOfRes("abnormal_timeout", resJson->abnormalTimeout, &localConf->checkInfo.abnormalTimeout); return CM_SUCCESS; } @@ -569,8 +661,5 @@ uint32 GetLocalResConfCount() bool IsCusResExistLocal() { - if (g_localResConfCount == 0) { - return false; - } - return true; + return (g_localResConfCount > 0); } diff --git a/src/cm_agent/cma_msg_queue.cpp b/src/cm_agent/cma_msg_queue.cpp index 89310a8..600f03e 100644 --- a/src/cm_agent/cma_msg_queue.cpp +++ b/src/cm_agent/cma_msg_queue.cpp @@ -100,6 +100,17 @@ static inline void PushToAgentMsgQue(const AgentMsgPkg *msgPkg, MsgQueue *msgQue (void)pthread_cond_signal(&msgQue->cond); } +void PushMsgToAllClientSendQue(const char *msgPtr, uint32 msgLen) +{ + ClientConn *clientConn = GetClientConnect(); + for (uint32 i = 0; i < CM_MAX_RES_COUNT; ++i) { + if (!clientConn[i].isClosed) { + write_runlog(LOG, "notify inst(%u), CMA disconnect with CMS.\n", clientConn[i].cmInstanceId); + PushMsgToClientSendQue(msgPtr, msgLen, i); + } + } +} + void PushMsgToClientSendQue(const char *msgPtr, uint32 msgLen, uint32 conId) { AgentMsgPkg msgPkg = {0}; diff --git a/src/cm_agent/cma_network_check.cpp b/src/cm_agent/cma_network_check.cpp index 80eaaba..1ea75da 100644 --- a/src/cm_agent/cma_network_check.cpp +++ b/src/cm_agent/cma_network_check.cpp @@ -22,13 +22,17 @@ * ------------------------------------------------------------------------- */ +#include #include #include #include -#include "cjson/cJSON.h" -#include "cma_global_params.h" + #include "cm_util.h" +#include "cm_text.h" #include "cm_json_config.h" +#include "cm_json_parse_floatIp.h" + +#include "cma_global_params.h" #include "cma_common.h" #include "cma_network_check.h" @@ -58,6 +62,7 @@ typedef struct NetworkInfoT { NetworkOper oper; uint32 port; uint32 cnt; + uint32 checkCnt; const char (*ips)[CM_IP_LENGTH]; NetWorkAddr *netAddr; NetworkState *stateCheck; @@ -90,6 +95,10 @@ typedef struct NetworkStateStringMapT { const char *str; } NetworkStateStringMap; +#ifdef ENABLE_UT +#define static +#endif + static bool GetNicstatusByAddrs(const struct ifaddrs *ifList, NetworkInfo *netInfo, int32 logLevel = WARNING, NetworkQuest quest = NETWORK_QUEST_CHECK); static void GetNicDownCmd(char *cmd, uint32 cmdLen, const NetworkInfo *netInfo, uint32 index); @@ -97,6 +106,7 @@ static void GetNicDownCmd(char *cmd, uint32 cmdLen, const NetworkInfo *netInfo, static CmNetworkInfo *g_cmNetWorkInfo = NULL; static uint32 g_instCnt = 0; static CmNetworkByType g_cmNetworkByType[CM_INSTANCE_TYPE_CEIL] = {{0}}; +static ParseFloatIpFunc g_cmaParseFuc = {0}; static NetworkStateOperMap g_stateOperMap[] = {{NETWORK_STATE_UNKNOWN, NETWORK_OPER_UNKNOWN}, {NETWORK_STATE_UP, NETWORK_OPER_UP}, @@ -104,14 +114,20 @@ static NetworkStateOperMap g_stateOperMap[] = {{NETWORK_STATE_UNKNOWN, NETWORK_O {NETWORK_STATE_CEIL, NETWORK_OPER_CEIL}}; static const char *g_ifconfigCmd = "ifconfig"; -static const char *IFCONFIG_CMD_DEFAULT = "ifconfig"; -static const char *IFCONFIG_CMD_SUSE = "/sbin/ifconfig"; -static const char *IFCONFIG_CMD_EULER = "/usr/sbin/ifconfig"; -static const char *ARPING_CMD = "arping -w 1 -A -I"; -static const char *SHOW_IPV6_CMD = "ip addr show | grep"; -static const char *IPV6_TENTATIVE_FLAG = "tentative"; -static const char *IPV6_DADFAILED_FLAG = "dadfailed"; +static const char *const IFCONFIG_CMD_DEFAULT = "ifconfig"; +static const char *const IFCONFIG_CMD_SUSE = "/sbin/ifconfig"; +static const char *const IFCONFIG_CMD_EULER = "/usr/sbin/ifconfig"; +static const char *const ARPING_CMD = "arping -w 1 -A -I"; +static const char *const SHOW_IPV6_CMD = "ip addr show | grep"; +static const char *const IPV6_TENTATIVE_FLAG = "tentative"; +static const char *const IPV6_DADFAILED_FLAG = "dadfailed"; +static const char *const TIMEOUT_MECHA = "timeout -s SIGKILL"; +static const uint32 DEFAULT_CMD_TIMEOUT = 2; +static const char *g_sudoPermCmd = ""; +static const char *const SUDO_PERM_CMD = "sudo"; + +static DnFloatIpMapOper g_floatIpMap = {0}; static NetworkOperStringMap g_operStringMap[NETWORK_OPER_CEIL] = { {NETWORK_OPER_UNKNOWN, "NETWORK_OPER_UNKNOWN"}, {NETWORK_OPER_UP, "NETWORK_OPER_UP"}, @@ -144,6 +160,67 @@ const char *GetOperMapString(NetworkOper oper) return "unknown_oper"; } +void SetFloatIpOper(uint32 dnIdx, NetworkOper oper, const char *str) +{ + if (!IsNeedCheckFloatIp() || (agent_backup_open != CLUSTER_PRIMARY)) { + write_runlog(DEBUG1, "%s agent_backup_open=%d, cannot set floatIp oper.\n", str, (int32)agent_backup_open); + return; + } + if (dnIdx >= CM_MAX_DATANODE_PER_NODE) { + return; + } + g_floatIpMap.oper[dnIdx] = oper; + write_runlog(LOG, "%s set floatIp oper=%d.\n", str, (int32)oper); +} + +NetworkOper GetFloatIpOper(uint32 dnIdx) +{ + if (dnIdx >= CM_MAX_DATANODE_PER_NODE) { + return NETWORK_OPER_UNKNOWN; + } + return g_floatIpMap.oper[dnIdx]; +} + +DnFloatIp *GetDnFloatIpByDnIdx(uint32 dnIdx) +{ + if (dnIdx >= CM_MAX_DATANODE_PER_NODE) { + return NULL; + } + return &(g_floatIpMap.floatIp[dnIdx]); +} + +static bool8 CmaFindNodeInfoByNodeIdx(uint32 instId, uint32 *nodeIdx, uint32 *dnIdx, const char *str) +{ + return (bool8)FindDnIdxInCurNode(instId, dnIdx, str); +} + +static DnFloatIp *CmaGetDnFloatIpByNodeInfo(uint32 nodeIdx, uint32 dnIdx) +{ + return GetDnFloatIpByDnIdx(dnIdx); +} + +static void IncreaseDnFloatIpCnt(uint32 nodeIdx) +{ + ++g_floatIpMap.count; +} + +static void CmaInitParseFloatIpCnt() +{ + g_cmaParseFuc.findNodeInfo = CmaFindNodeInfoByNodeIdx; + g_cmaParseFuc.getFloatIp = CmaGetDnFloatIpByNodeInfo; + g_cmaParseFuc.increaseCnt = IncreaseDnFloatIpCnt; + InitParseFloatIpFunc(&g_cmaParseFuc); +} + +static inline void InitFloatIpMap() +{ + errno_t rc = memset_s(&(g_floatIpMap), sizeof(DnFloatIpMapOper), 0, sizeof(DnFloatIpMapOper)); + securec_check_errno(rc, (void)rc); + CmaInitParseFloatIpCnt(); + ParseVipConf(LOG); + write_runlog(LOG, "success to get g_floatIpMap, and this count is %u.\n", g_floatIpMap.count); +} + NetworkOper ChangeInt2NetworkOper(int32 oper) { if (oper < 0 || oper >= (int32)NETWORK_OPER_CEIL) { @@ -195,7 +272,7 @@ static NetworkInfo *GetNetworkInfo(uint32 instId, CmaInstType instType, NetworkT return NULL; } -bool GetNicStatus(unsigned int instId, CmaInstType instType, NetworkType type) +bool GetNicStatus(uint32 instId, CmaInstType instType, NetworkType type) { NetworkInfo *netInfo = GetNetworkInfo(instId, instType, type); if (netInfo == NULL) { @@ -272,6 +349,51 @@ static uint32 GetCurrentNodeInstNum() return count; } +static void SetNetWorkAddr(NetWorkAddr *netAddr, uint32 cnt, const char (*ips)[CM_IP_LENGTH]) +{ + if (cnt == 0 || ips == NULL || netAddr == NULL) { + return; + } + for (uint32 i = 0; i < cnt; ++i) { + netAddr[i].ip = ips[i]; + } +} + +static bool8 IsCurIpInIpPool(const char **ipPool, uint32 cnt, const char *ip) +{ + if (cnt == 0 || ip == NULL) { + return CM_FALSE; + } + for (uint32 i = 0; i < cnt; ++i) { + if (ipPool[i] == NULL) { + continue; + } + if (cm_str_equal(ipPool[i], ip)) { + return CM_TRUE; + } + } + return CM_FALSE; +} + +static uint32 GetIpCheckCnt(const char (*ips)[CM_IP_LENGTH], uint32 cnt) +{ + const char *ipPool[MAX_FLOAT_IP_COUNT] = {0}; + uint32 checkCnt = 0; + for (uint32 i = 0; i < cnt; ++i) { + if (i >= MAX_FLOAT_IP_COUNT) { + break; + } + if (IsCurIpInIpPool(ipPool, checkCnt, ips[i])) { + continue; + } + if (checkCnt < MAX_FLOAT_IP_COUNT) { + ipPool[checkCnt] = ips[i]; + ++checkCnt; + } + } + return checkCnt; +} + static status_t SetNetWorkInfo( NetworkInfo *info, uint32 cnt, const char (*ips)[CM_IP_LENGTH], NetworkType type, uint32 port) { @@ -285,6 +407,7 @@ static status_t SetNetWorkInfo( cnt, MAX_FLOAT_IP_COUNT); } info->cnt = curCnt; + info->checkCnt = GetIpCheckCnt(ips, cnt); info->oper = NETWORK_OPER_UNKNOWN; info->port = port; if (cnt == 0) { @@ -325,10 +448,17 @@ static status_t SetCmNetWorkInfoDn(CmaInstType type, uint32 *index, const dataNo const dataNodeInfo *dnInfo = &(datanodeInfo[dnIdx]); CmNetworkInfo *cmNetWorkInfo = &(g_cmNetWorkInfo[(*index)]); cmNetWorkInfo->instId = dnInfo->datanodeId; + DnFloatIp *dnFloatIp = GetDnFloatIpByDnIdx(dnIdx); CM_RETURN_IFERR(SetNetWorkInfo(&(cmNetWorkInfo->manaIp[NETWORK_TYPE_LISTEN]), dnInfo->datanodeListenCount, dnInfo->datanodeListenIP, NETWORK_TYPE_LISTEN, dnInfo->datanodePort)); CM_RETURN_IFERR(SetNetWorkInfo(&(cmNetWorkInfo->manaIp[NETWORK_TYPE_HA]), dnInfo->datanodeLocalHAListenCount, dnInfo->datanodeLocalHAIP, NETWORK_TYPE_HA, dnInfo->datanodeLocalHAPort)); + if (dnFloatIp != NULL) { + NetworkInfo *netInfo = &(cmNetWorkInfo->manaIp[NETWORK_TYPE_FLOATIP]); + CM_RETURN_IFERR(SetNetWorkInfo(netInfo, dnFloatIp->dnFloatIpCount, + dnFloatIp->dnFloatIp, NETWORK_TYPE_FLOATIP, dnFloatIp->dnFloatIpPort)); + SetNetWorkAddr(netInfo->netAddr, netInfo->cnt, dnFloatIp->baseIp); + } ++(*index); if (type >= CM_INSTANCE_TYPE_CEIL) { return CM_SUCCESS; @@ -445,9 +575,19 @@ static void InitIfconfigCmd() } } +static void InitSudoPermCmd() +{ + g_sudoPermCmd = ""; + if (g_clusterType != V3SingleInstCluster) { + g_sudoPermCmd = SUDO_PERM_CMD; + } +} + static status_t InitCmNetWorkInfo() { + InitFloatIpMap(); InitIfconfigCmd(); + InitSudoPermCmd(); g_instCnt = GetCurrentNodeInstNum(); write_runlog(LOG, "current node has %u instance.\n", g_instCnt); size_t mallocLen = sizeof(CmNetworkInfo) * g_instCnt; @@ -612,7 +752,7 @@ static bool GetNicstatusByAddrs( return false; } ++validIpCount; - if (validIpCount == netInfo->cnt) { + if (validIpCount == netInfo->checkCnt) { return true; } } @@ -621,7 +761,8 @@ static bool GetNicstatusByAddrs( } char allListenIp[CM_IP_ALL_NUM_LENGTH] = {0}; listen_ip_merge(netInfo->cnt, netInfo->ips, allListenIp, CM_IP_ALL_NUM_LENGTH); - write_runlog(WARNING, "can't find nic related with %s.\n", allListenIp); + write_runlog(WARNING, "can't find nic related with %s, cnt=[%u: %u].\n", + allListenIp, netInfo->cnt, netInfo->checkCnt); return false; } @@ -669,6 +810,25 @@ static bool CheckNetworkStatus() return true; } +bool8 CheckNetworkStatusByIps(const char (*ips)[CM_IP_LENGTH], uint32 cnt) +{ + struct ifaddrs *ifList = NULL; + if (getifaddrs(&ifList) < 0) { + write_runlog(WARNING, "failed to get iflist.\n"); + return CM_FALSE; + } + NetworkInfo netInfo; + errno_t rc = memset_s(&netInfo, sizeof(NetworkInfo), 0, sizeof(NetworkInfo)); + securec_check_errno(rc, (void)rc); + netInfo.ips = ips; + netInfo.cnt = cnt; + netInfo.checkCnt = GetIpCheckCnt(ips, cnt); + netInfo.type = NETWORK_TYPE_HA; + CheckNicStatus(ifList, &netInfo); + freeifaddrs(ifList); + return (bool8)netInfo.networkRes; +} + static bool GetNetworkAddr(NetworkInfo *netInfo, const char *str) { struct ifaddrs *ifList = NULL; @@ -722,16 +882,19 @@ static void GetNicUpCmd(char *cmd, uint32 cmdLen, const NetworkInfo *netInfo, ui if (netInfo->netAddr[index].netMask[0] == '\0' || netInfo->netAddr[index].netName[0] == '\0') { return; } + errno_t rc = 0; if (netInfo->netAddr[index].family == AF_INET) { - rc = snprintf_s(cmd, cmdLen, cmdLen - 1, "%s %s:%u %s netmask %s up", g_ifconfigCmd, netAddr->netName, - netInfo->port, netInfo->ips[index], netAddr->netMask); + rc = snprintf_s(cmd, cmdLen, cmdLen - 1, "%s %us %s %s %s:%u %s netmask %s up", + TIMEOUT_MECHA, DEFAULT_CMD_TIMEOUT, g_sudoPermCmd, g_ifconfigCmd, + netAddr->netName, netInfo->port, netInfo->ips[index], netAddr->netMask); } else if (netInfo->netAddr[index].family == AF_INET6) { if (!CheckIpV6Valid(netInfo, index, "[GetNicUpCmd]", LOG)) { return; } - rc = snprintf_s(cmd, cmdLen, cmdLen - 1, "%s %s inet6 add %s/%s", g_ifconfigCmd, netAddr->netName, - netInfo->ips[index], netAddr->netMask); + rc = snprintf_s(cmd, cmdLen, cmdLen - 1, "%s %us %s %s %s inet6 add %s/%s", + TIMEOUT_MECHA, DEFAULT_CMD_TIMEOUT, g_sudoPermCmd, g_ifconfigCmd, + netAddr->netName, netInfo->ips[index], netAddr->netMask); } securec_check_intval(rc, (void)rc); } @@ -744,11 +907,13 @@ static void GetNicDownCmd(char *cmd, uint32 cmdLen, const NetworkInfo *netInfo, } errno_t rc = 0; if (netInfo->netAddr[index].family == AF_INET) { - rc = snprintf_s(cmd, cmdLen, cmdLen - 1, "%s %s:%u down", g_ifconfigCmd, netAddr->netName, + rc = snprintf_s(cmd, cmdLen, cmdLen - 1, "%s %us %s %s %s:%u down", + TIMEOUT_MECHA, DEFAULT_CMD_TIMEOUT, g_sudoPermCmd, g_ifconfigCmd, netAddr->netName, netInfo->port); } else { - rc = snprintf_s(cmd, cmdLen, cmdLen - 1, "%s %s inet6 del %s/%s", g_ifconfigCmd, netAddr->netName, - netInfo->ips[index], netAddr->netMask); + rc = snprintf_s(cmd, cmdLen, cmdLen - 1, "%s %us %s %s %s inet6 del %s/%s", + TIMEOUT_MECHA, DEFAULT_CMD_TIMEOUT, g_sudoPermCmd, g_ifconfigCmd, + netAddr->netName, netInfo->ips[index], netAddr->netMask); } securec_check_intval(rc, (void)rc); } @@ -772,15 +937,12 @@ static void ExecuteArpingCmd(ArpingCmdRes *arpingCmd, const char *str) static void CheckArpingCmdRes(NetworkInfo *netInfo) { - if (netInfo->oper != NETWORK_OPER_UP) { - return; - } for (uint32 i = 0; i < netInfo->cnt; ++i) { ExecuteArpingCmd(&(netInfo->arpingCmd[i]), "[CheckArpingCmdRes]"); } } -static bool CheckNicStatusMeetsExpect(NetworkInfo *netInfo) +static bool CheckNicStatusMeetsExpect(NetworkInfo *netInfo, bool8 *isExeArping) { if (netInfo->cnt == 0) { return true; @@ -791,7 +953,7 @@ static bool CheckNicStatusMeetsExpect(NetworkInfo *netInfo) } // only float ip is up, it will notify switch if (netInfo->oper == NETWORK_OPER_UP) { - CheckArpingCmdRes(netInfo); + *isExeArping = CM_TRUE; } for (uint32 i = 0; i < netInfo->cnt; ++i) { if (netInfo->stateRecord[i] != state) { @@ -801,7 +963,7 @@ static bool CheckNicStatusMeetsExpect(NetworkInfo *netInfo) return true; } -static void GenArpingCmdAndExecute(NetworkInfo *netInfo, uint32 index) +static void GenArpingCmd(NetworkInfo *netInfo, uint32 index, bool8 *isExeArping) { if (netInfo->oper != NETWORK_OPER_UP) { return; @@ -813,12 +975,12 @@ static void GenArpingCmdAndExecute(NetworkInfo *netInfo, uint32 index) "%s %s %s", ARPING_CMD, netInfo->netAddr[index].netName, netInfo->ips[index]); securec_check_intval(rc, (void)rc); } - ExecuteArpingCmd(&(netInfo->arpingCmd[index]), "[GenArpingCmdAndExecute]"); + *isExeArping = CM_TRUE; } -static void DoUpOrDownNetworkOper(NetworkInfo *netInfo) +static void DoUpOrDownNetworkOper(NetworkInfo *netInfo, bool8 *isExeArping) { - if (CheckNicStatusMeetsExpect(netInfo)) { + if (CheckNicStatusMeetsExpect(netInfo, isExeArping)) { return; } const char *str = (netInfo->oper == NETWORK_OPER_UP) ? "[DoUpNetworkOper]" : "[DoDownNetworkOper]"; @@ -838,6 +1000,7 @@ static void DoUpOrDownNetworkOper(NetworkInfo *netInfo) GetNicDownCmd(cmd, CM_MAX_COMMAND_LONG_LEN, netInfo, i); } if (cmd[0] == '\0') { + GenArpingCmd(netInfo, i, isExeArping); continue; } write_runlog(LOG, "%s Ip: %s oper=[%d: %s], state=[%d: %s], GetNicCmd(%s).\n", str, netInfo->ips[i], @@ -854,20 +1017,38 @@ static void DoUpOrDownNetworkOper(NetworkInfo *netInfo) } else { netInfo->stateRecord[i] = GetNetworkStateByOper(netInfo->oper); write_runlog(LOG, "%s successfully to execute the cmd(%s).\n", str, cmd); - GenArpingCmdAndExecute(netInfo, i); + GenArpingCmd(netInfo, i, isExeArping); } } } +static void CheckAndExecuteArpingCmd() +{ + NetworkInfo *manaIp; + for (uint32 i = 0; i < g_instCnt; ++i) { + manaIp = &(g_cmNetWorkInfo[i].manaIp[NETWORK_TYPE_FLOATIP]); + CheckArpingCmdRes(manaIp); + } +} + static void DoNetworkOper() { + if (!IsNeedCheckFloatIp() || (agent_backup_open != CLUSTER_PRIMARY)) { + write_runlog(DEBUG1, "[DoNetworkOper] agent_backup_open=%d, cannot set floatIp oper.\n", + (int32)agent_backup_open); + return; + } NetworkInfo *manaIp = NULL; + bool8 isExeArping = CM_FALSE; for (uint32 i = 0; i < g_instCnt; ++i) { manaIp = &(g_cmNetWorkInfo[i].manaIp[NETWORK_TYPE_FLOATIP]); if (manaIp->oper == NETWORK_OPER_UNKNOWN) { continue; } - DoUpOrDownNetworkOper(manaIp); + DoUpOrDownNetworkOper(manaIp, &isExeArping); + } + if (isExeArping) { + CheckAndExecuteArpingCmd(); } } @@ -894,6 +1075,31 @@ status_t CreateNetworkResource() return CM_SUCCESS; } +static uint8 CheckSingleFloatIpDown(const NetworkInfo *manaIp) +{ + for (uint32 i = 0; i < manaIp->cnt; ++i) { + if (manaIp->stateRecord[i] == NETWORK_STATE_UP) { + return CM_FALSE; + } + } + return CM_TRUE; +} + +static uint8 IsAllFloatIpDown() +{ + NetworkInfo *manaIp = NULL; + for (uint32 i = 0; i < g_instCnt; ++i) { + manaIp = &(g_cmNetWorkInfo[i].manaIp[NETWORK_TYPE_FLOATIP]); + if (manaIp->cnt == 0) { + continue; + } + if (!CheckSingleFloatIpDown(manaIp)) { + return CM_FALSE; + } + } + return CM_TRUE; +} + void *CmaCheckNetWorkMain(void *arg) { thread_name = "CheckNetWork"; @@ -902,7 +1108,7 @@ void *CmaCheckNetWorkMain(void *arg) uint32 sleepInterval = 1; bool networkRes = false; for (;;) { - if ((g_exitFlag || g_shutdownRequest)) { + if ((g_exitFlag || g_shutdownRequest) && IsAllFloatIpDown()) { cm_sleep(sleepInterval); continue; } diff --git a/src/cm_agent/cma_phony_dead_check.cpp b/src/cm_agent/cma_phony_dead_check.cpp index b4fd910..45d954d 100644 --- a/src/cm_agent/cma_phony_dead_check.cpp +++ b/src/cm_agent/cma_phony_dead_check.cpp @@ -61,8 +61,10 @@ static bool IsDNCoredump(uint32 dnId) static bool DnPhonyDeadProcessE2E(int dnId, int phonyDead) { if (phonyDead == PROCESS_PHONY_DEAD_D) { - /* Verify that the short link to dn is available */ - if (CheckDnStausPhonyDead(dnId, (int)agent_phony_dead_check_interval) != 0) { + if (IsDatanodeSSMode()) { + write_runlog(LOG, "[%s] dn is D status, but in ss mode, can't process the D status.\n", __FUNCTION__); + } else if (CheckDnStausPhonyDead(dnId, (int)agent_phony_dead_check_interval) != 0) { + /* Verify that the short link to dn is available */ g_dnPhonyDeadD[dnId] = true; write_runlog(WARNING, "dn_%u phony dead D\n", g_currentNode->datanode[dnId].datanodeId); return true; @@ -105,7 +107,12 @@ static bool DnPhonyDeadStatusCheck(int dnId, uint32 *agentCheckTimeInterval) return false; } if (phonyDead == PROCESS_PHONY_DEAD_D) { - return true; + if (IsDatanodeSSMode()) { + write_runlog(LOG, "[%s] dn is D status, but in ss mode, can't process the D status.\n", __FUNCTION__); + return false; + } else { + return true; + } } if (phonyDead == PROCESS_PHONY_DEAD_T) { if (g_clusterType != V3SingleInstCluster && g_agentCheckTStatusInterval > agent_phony_dead_check_interval) { @@ -249,4 +256,4 @@ void *FaultDetectMain(void *arg) } return NULL; -} \ No newline at end of file +} diff --git a/src/cm_agent/cma_process_messages.cpp b/src/cm_agent/cma_process_messages.cpp index 8cc0e6f..bdbe51d 100644 --- a/src/cm_agent/cma_process_messages.cpp +++ b/src/cm_agent/cma_process_messages.cpp @@ -24,6 +24,7 @@ #include "securec.h" #include "cm/cm_elog.h" #include "cm/cm_msg.h" +#include "cm/cm_util.h" #include "cma_common.h" #include "cma_global_params.h" #include "cma_client.h" @@ -34,6 +35,7 @@ #include "cma_instance_management_res.h" #include "cma_instance_check.h" #include "cma_mes.h" +#include "cma_instance_management_res.h" #include "cma_process_messages.h" #ifdef ENABLE_MULTIPLE_NODES #include "cma_coordinator.h" @@ -66,6 +68,23 @@ static void InstancesStatusCheckAndReport(void) } } +static void WillSetFloatIpOper(uint32 instId, NetworkOper oper, const char *str) +{ + if (!IsNeedCheckFloatIp() || (agent_backup_open != CLUSTER_PRIMARY)) { + write_runlog(LOG, "%s agent_backup_open=%d, cannot set floatIp oper.\n", str, (int32)agent_backup_open); + return; + } + uint32 dnIdx = 0; + bool ret = FindDnIdxInCurNode(instId, &dnIdx, str); + if (!ret) { + write_runlog(ERROR, "%s cannot do the network oper in instId(%u), because it cannot be found in " + "current node.\n", str, instId); + return; + } + SetNicOper(instId, CM_INSTANCE_TYPE_DN, NETWORK_TYPE_FLOATIP, oper); + SetFloatIpOper(dnIdx, oper, str); +} + static void AgentSendHeartbeat() { agent_to_cm_heartbeat hbMsg = {0}; @@ -473,6 +492,7 @@ static void process_failover_command(const char* dataDir, int instanceType, uint instanceName); /* report the alarm */ ReportCMAEventAlarm(AlarmFailOver, &tempAdditionalParam); + WillSetFloatIpOper(instance_id, NETWORK_OPER_UP, "[process_failover_command]"); break; default: write_runlog(LOG, "node_type is unknown !\n"); @@ -1746,7 +1766,38 @@ static void MsgCmAgentResArbitrate(const AgentMsgPkg *msg, char *dataPath, const if (recvMsg == NULL) { return; } - ProcessResRegFromCms(recvMsg); + + static uint64 processTime = 0; + static const uint64 processInterval = 1000; + uint64 curTime = GetMonotonicTimeMs(); + if ((curTime - processTime) > processInterval) { + ProcessResRegFromCms(recvMsg); + processTime = curTime; + } +} + +static void ProcessFloatIpFromCms(const CmsDnFloatIpAck *recvMsg) +{ + NetworkOper oper = ChangeInt2NetworkOper(recvMsg->oper); + if (oper == NETWORK_OPER_UNKNOWN) { + return; + } + write_runlog(LOG, "receive floatIp oper msg(%d=%s) from cms.\n", (int32)oper, GetOperMapString(oper)); + WillSetFloatIpOper(recvMsg->baseInfo.instId, oper, "[ProcessFloatIpFromCms]"); +} + +static void MsgCmAgentFloatIpAck(const AgentMsgPkg *msg, char *dataPath, const cm_msg_type *msgTypePtr) +{ + const CmsDnFloatIpAck *recvMsg = (const CmsDnFloatIpAck *)CmGetMsgBytesPtr(msg, sizeof(CmsDnFloatIpAck)); + if (recvMsg == NULL) { + return; + } + if (!IsNeedCheckFloatIp() || (agent_backup_open != CLUSTER_PRIMARY)) { + write_runlog(DEBUG1, "[MsgCmAgentFloatIpAck] agent_backup_open=%d, cannot set floatIp oper.\n", + (int32)agent_backup_open); + return; + } + ProcessFloatIpFromCms(recvMsg); } static void MsgCmAgentIsregCheckListChanged(const AgentMsgPkg *msg, char *dataPath, const cm_msg_type *msgTypePtr) @@ -1906,7 +1957,7 @@ void CmServerCmdProcessorInit(void) g_cmsCmdProcessor[MSG_GET_SHARED_STORAGE_INFO_ACK] = MsgCmAgentGetSharedStorageModeAck; g_cmsCmdProcessor[MSG_CM_RES_LOCK_ACK] = MsgCmAgentResLockAck; g_cmsCmdProcessor[MSG_CM_RES_REG] = MsgCmAgentResArbitrate; - g_cmsCmdProcessor[MSG_CM_AGENT_FLOAT_IP_ACK] = NULL; + g_cmsCmdProcessor[MSG_CM_AGENT_FLOAT_IP_ACK] = MsgCmAgentFloatIpAck; g_cmsCmdProcessor[MSG_CM_AGENT_ISREG_CHECK_LIST_CHANGED] = MsgCmAgentIsregCheckListChanged; #ifdef ENABLE_MULTIPLE_NODES g_cmsCmdProcessor[MSG_CM_AGENT_NOTIFY_CN] = MsgCmAgentNotifyCn; @@ -2010,6 +2061,7 @@ void *ProcessSendCmsMsgMain(void *arg) struct timespec lastReportTime = {0, 0}; struct timespec currentTime = {0, 0}; long expiredTime = 0; + const uint32 overLongTime = 1000; (void)clock_gettime(CLOCK_MONOTONIC, &lastReportTime); pthread_t threadId = pthread_self(); thread_name = "SendCmsMsg"; @@ -2029,13 +2081,22 @@ void *ProcessSendCmsMsgMain(void *arg) write_runlog(LOG, "connection to cm_server %u seconds timeout expired .\n", agent_heartbeat_timeout); g_cmServerNeedReconnect = true; } + uint64 t1 = GetMonotonicTimeMs(); + ReportInstanceStatus(); + uint64 t2 = GetMonotonicTimeMs(); + if (etcdTimeReportInterval >= AGENT_REPORT_ETCD_CYCLE || etcdTimeReportInterval == 0) { EtcdCurrentTimeReport(); etcdTimeReportInterval = 0; } etcdTimeReportInterval++; (void)clock_gettime(CLOCK_MONOTONIC, &lastReportTime); + uint64 t3 = GetMonotonicTimeMs(); + if ((t3 - t1) > overLongTime) { + write_runlog(LOG, "[%s] ReportInstanceStatus=%lu, EtcdCurrentTimeReport=%lu.\n", + __FUNCTION__, (t2 - t1), (t3 - t2)); + } } CmUsleep(AGENT_RECV_CYCLE); } @@ -2068,21 +2129,44 @@ void *ProcessRecvCmsMsgMain(void *arg) thread_name = "ProcessCmsMsg"; write_runlog(LOG, "process cms msg thread begin, threadId:%lu.\n", (unsigned long)pthread_self()); + int32 msgType; + const uint32 overLongTime = 3000; for (;;) { if (g_shutdownRequest) { cm_sleep(5); continue; } + msgType = -1; MsgQueue &recvQueue = GetCmsRecvQueue(); + uint64 t1 = GetMonotonicTimeMs(); + (void)pthread_mutex_lock(&recvQueue.lock); + uint64 t2 = GetMonotonicTimeMs(); + while (recvQueue.msg.empty()) { (void)pthread_cond_wait(&recvQueue.cond, &recvQueue.lock); } + uint64 t3 = GetMonotonicTimeMs(); + AgentMsgPkg msgPkg = recvQueue.msg.front(); recvQueue.msg.pop(); + uint64 t4 = GetMonotonicTimeMs(); + (void)pthread_mutex_unlock(&recvQueue.lock); + uint64 t5 = GetMonotonicTimeMs(); + ProcessCmServerCmd(&msgPkg); + if (msgPkg.msgLen >= (sizeof(int32))) { + msgType = *(int *)(msgPkg.msgPtr); + } + uint64 t6 = GetMonotonicTimeMs(); + FreeBufFromMsgPool(msgPkg.msgPtr); + uint64 t7 = GetMonotonicTimeMs(); + if ((t7 - t1) > overLongTime) { + write_runlog(LOG, "[%s] lock=%lu, wait=%lu, pop=%lu, unlock=%lu, process=%lu, free=%lu, msgType=%d.\n", + __FUNCTION__, (t2 - t1), (t3 - t2), (t4 - t3), (t5 - t4), (t6 - t5), (t7 - t6), msgType); + } } return NULL; diff --git a/src/cm_agent/cma_process_messages_client.cpp b/src/cm_agent/cma_process_messages_client.cpp index 914c380..66ae3dd 100644 --- a/src/cm_agent/cma_process_messages_client.cpp +++ b/src/cm_agent/cma_process_messages_client.cpp @@ -31,6 +31,15 @@ #include "cma_instance_management_res.h" #include "cma_process_messages_client.h" +void NotifyClientConnectClose() +{ + AgentToClientNotify cmaMsg = {{0}}; + cmaMsg.head.msgType = (uint32)MSG_AGENT_CLIENT_NOTIFY_CONN_CLOSE; + cmaMsg.notify.isCmaConnClose = CM_TRUE; + + PushMsgToAllClientSendQue((char*)&cmaMsg, sizeof(cmaMsg)); +} + static void SendHeartbeatAckToClient(uint32 conId) { MsgHead hbAck = {0}; @@ -53,19 +62,10 @@ static void SendStatusListToClient(CmResStatList &statList, uint32 conId, bool i (void)pthread_rwlock_rdlock(&(statList.rwlock)); rc = memcpy_s(&sendList.resStatusList, sizeof(OneResStatList), &statList.status, sizeof(OneResStatList)); - (void)pthread_rwlock_unlock(&(statList.rwlock)); securec_check_errno(rc, (void)rc); + (void)pthread_rwlock_unlock(&(statList.rwlock)); - write_runlog(LOG, "[CLIENT] send status list to res(%s), version=%llu.\n", - sendList.resStatusList.resName, sendList.resStatusList.version); - for (uint32 i = 0; i < sendList.resStatusList.instanceCount; ++i) { - write_runlog(LOG, "nodeId=%u,instanceId=%u,resInstanceId=%u,status=%d,isWork=%u\n", - sendList.resStatusList.resStat[i].nodeId, - sendList.resStatusList.resStat[i].cmInstanceId, - sendList.resStatusList.resStat[i].resInstanceId, - (int)sendList.resStatusList.resStat[i].status, - sendList.resStatusList.resStat[i].isWorkMember); - } + PrintCusInfoResList(&sendList.resStatusList, __FUNCTION__); PushMsgToClientSendQue((char*)&sendList, sizeof(AgentToClientResList), conId); } @@ -242,19 +242,6 @@ static void UpdateResStatusList(CmResStatList *resStat, const OneResStatList *ne securec_check_errno(rc, (void)rc); } -static void PrintLatestResStatusList(const OneResStatList *resStat) -{ - write_runlog(LOG, "[CLIENT] res(%s) statList changed, version=%llu.\n", resStat->resName, resStat->version); - for (uint32 i = 0; i < resStat->instanceCount; ++i) { - write_runlog(LOG, "nodeId=%u,cmInstanceId=%u,resInstanceId=%u,status=%u,isWork=%u\n", - resStat->resStat[i].nodeId, - resStat->resStat[i].cmInstanceId, - resStat->resStat[i].resInstanceId, - resStat->resStat[i].status, - resStat->resStat[i].isWorkMember); - } -} - void ProcessResStatusList(const CmsReportResStatList *msg) { if (msg->resList.instanceCount > CM_MAX_RES_INST_COUNT) { @@ -270,7 +257,7 @@ void ProcessResStatusList(const CmsReportResStatList *msg) } UpdateResStatusList(&g_resStatus[index], &msg->resList); - PrintLatestResStatusList(&msg->resList); + PrintCusInfoResList(&msg->resList, __FUNCTION__); } void ProcessResStatusChanged(const CmsReportResStatList *msg) diff --git a/src/cm_agent/cma_status_check.cpp b/src/cm_agent/cma_status_check.cpp index 05afc45..783f67f 100644 --- a/src/cm_agent/cma_status_check.cpp +++ b/src/cm_agent/cma_status_check.cpp @@ -811,9 +811,22 @@ static void SendDiskUsageMsg(const DnStatus *pkgDnStatus, uint32 datanodeId) PushMsgToCmsSendQue((char *)&diskUsageMsg, (uint32)sizeof(AgentToCmDiskUsageStatusReport), "dnDiskUsage"); } +static void SendFloatIpMsg(const CmaDnFloatIpInfo *floatIpInfo, uint32 dnId) +{ + if (!IsNeedCheckFloatIp() || (agent_backup_open != CLUSTER_PRIMARY)) { + return; + } + if (floatIpInfo->info.count == 0) { + return; + } + write_runlog(DEBUG5, "dn(%u) floatIpMsg will send to cms.\n", dnId); + PushMsgToCmsSendQue((const char *)floatIpInfo, (uint32)sizeof(CmaDnFloatIpInfo), "dn floatIpMsg"); +} + static void SendDnReportMsgCore(const DnStatus *pkgDnStatus, uint32 datanodeId, AgentToCmserverDnSyncList *syncListMsg) { SendDnReportMsg(pkgDnStatus, datanodeId); + SendFloatIpMsg(&(pkgDnStatus->floatIpInfo), datanodeId); if (g_clusterType == V3SingleInstCluster) { return; } @@ -961,10 +974,26 @@ void InitDnLocalPeerMsg(AgentCmDnLocalPeer *lpInfo, int32 index) lpInfo->instanceType = INSTANCE_TYPE_DATANODE; } +static void SetDnBaseMsg(BaseInstInfo *baseInfo, int32 index, int32 msgType) +{ + baseInfo->msgType = msgType; + baseInfo->instId = g_currentNode->datanode[index].datanodeId; + baseInfo->node = g_currentNode->node; + baseInfo->instType = INSTANCE_TYPE_DATANODE; +} + +static void InitDnFloatIpMsg(CmaDnFloatIpInfo *ipInfo, int32 index) +{ + errno_t rc = memset_s(ipInfo, sizeof(CmaDnFloatIpInfo), 0, sizeof(CmaDnFloatIpInfo)); + securec_check_errno(rc, (void)rc); + SetDnBaseMsg(&(ipInfo->baseInfo), index, (int32)MSG_AGENT_CM_FLOAT_IP); +} + void InitDNStatus(DnStatus *dnStatus, int i) { InitReportMsg(&dnStatus->reportMsg, i); InitDnLocalPeerMsg(&(dnStatus->lpInfo), i); + InitDnFloatIpMsg(&(dnStatus->floatIpInfo), i); } static void ChangeLocalRoleInBackup(int dnIdx, int *localDnRole) @@ -1071,7 +1100,7 @@ void* DNStatusCheckMain(void *arg) int ret = snprintf_s(instanceName, sizeof(instanceName), sizeof(instanceName) - 1, "%s_%u", "dn", g_currentNode->datanode[i].datanodeId); securec_check_intval(ret, (void)ret); - int runing = PROCESS_UNKNOWN; + int32 running = PROCESS_UNKNOWN; for (;;) { set_thread_state(threadId); @@ -1084,8 +1113,9 @@ void* DNStatusCheckMain(void *arg) } InitDNStatus(&dnStatus, i); + running = check_one_instance_status(GetDnProcessName(), g_currentNode->datanode[i].datanodeLocalDataPath, NULL); if (g_currentNode->datanode[i].datanodeRole != DUMMY_STANDBY_DN) { - ret = DatanodeStatusCheck(&dnStatus, (uint32)i); + ret = DatanodeStatusCheck(&dnStatus, (uint32)i, running); } if (ret < 0 || g_currentNode->datanode[i].datanodeRole == DUMMY_STANDBY_DN) { @@ -1093,13 +1123,11 @@ void* DNStatusCheckMain(void *arg) write_runlog(ERROR, "DatanodeStatusCheck failed, ret=%d\n", ret); } - runing = check_one_instance_status(GetDnProcessName(), g_currentNode->datanode[i].datanodeLocalDataPath, - NULL); if (g_currentNode->datanode[i].datanodeRole == DUMMY_STANDBY_DN && - dnStatus.reportMsg.processStatus != INSTANCE_PROCESS_RUNNING && runing != PROCESS_RUNNING) { + dnStatus.reportMsg.processStatus != INSTANCE_PROCESS_RUNNING && running != PROCESS_RUNNING) { checkDummyTimes = CHECK_DUMMY_STATE_TIMES; } - if (runing == PROCESS_RUNNING) { + if (running == PROCESS_RUNNING) { if (g_currentNode->datanode[i].datanodeRole == DUMMY_STANDBY_DN && checkDummyTimes > 0) { checkDummyTimes--; } @@ -1206,6 +1234,7 @@ void* DNStatusCheckMain(void *arg) write_runlog(DEBUG5, "DatanodeStatusCheck: local role is %d, db state is %d, build reason is %d\n", dnStatus.reportMsg.local_status.local_role, dnStatus.reportMsg.local_status.db_state, dnStatus.reportMsg.local_status.buildReason); + DnCheckFloatIp(&dnStatus, (uint32)i, (bool8)(running == PROCESS_RUNNING)); (void)pthread_rwlock_wrlock(&(g_dnReportMsg[i].lk_lock)); rc = memcpy_s((void *)&(g_dnReportMsg[i].dnStatus.lpInfo), sizeof(AgentCmDnLocalPeer), (void *)&dnStatus.lpInfo, sizeof(AgentCmDnLocalPeer)); @@ -1213,6 +1242,9 @@ void* DNStatusCheckMain(void *arg) rc = memcpy_s((void *)&(g_dnReportMsg[i].dnStatus.reportMsg), sizeof(agent_to_cm_datanode_status_report), (void *)&dnStatus.reportMsg, sizeof(agent_to_cm_datanode_status_report)); securec_check_errno(rc, (void)rc); + rc = memcpy_s((void *)&(g_dnReportMsg[i].dnStatus.floatIpInfo), sizeof(CmaDnFloatIpInfo), + (void *)&dnStatus.floatIpInfo, sizeof(CmaDnFloatIpInfo)); + securec_check_errno(rc, (void)rc); (void)pthread_rwlock_unlock(&(g_dnReportMsg[i].lk_lock)); cm_sleep(agent_report_interval); diff --git a/src/cm_agent/cma_status_check_res.cpp b/src/cm_agent/cma_status_check_res.cpp index 1aca264..e870c02 100644 --- a/src/cm_agent/cma_status_check_res.cpp +++ b/src/cm_agent/cma_status_check_res.cpp @@ -217,19 +217,20 @@ void SendResIsregReportMsg() // check res status static void DoCheckResourceStatus(CmResConfList *resConf, CmResourceStatus *resStat) { + long curTime = GetCurMonotonicTimeSec(); static uint32 latestStat = (uint32)CUS_RES_CHECK_STAT_UNKNOWN; if (resConf->checkInfo.checkTime == 0) { resStat->status = (uint32)CheckOneResInst(resConf); - resConf->checkInfo.checkTime = time(NULL); + resConf->checkInfo.checkTime = curTime; latestStat = resStat->status; return; } - if ((time(NULL) - resConf->checkInfo.checkTime) < resConf->checkInfo.checkInterval) { + if ((curTime - resConf->checkInfo.checkTime) < resConf->checkInfo.checkInterval) { resStat->status = latestStat; return; } resStat->status = (uint32)CheckOneResInst(resConf); - resConf->checkInfo.checkTime = time(NULL); + resConf->checkInfo.checkTime = curTime; latestStat = resStat->status; } diff --git a/src/cm_client/cm_client.cpp b/src/cm_client/cm_client.cpp index f56797f..3381da7 100644 --- a/src/cm_client/cm_client.cpp +++ b/src/cm_client/cm_client.cpp @@ -69,7 +69,7 @@ OneResStatList *GetClientStatusList() static timespec GetMutexTimeout(time_t timeout) { struct timespec releaseTime = { 0, 0 }; - (void)clock_gettime(CLOCK_REALTIME, &releaseTime); + (void)clock_gettime(CLOCK_MONOTONIC, &releaseTime); releaseTime.tv_sec = releaseTime.tv_sec + timeout; return releaseTime; @@ -445,6 +445,31 @@ static status_t RecvResLockAckProcess() return CM_SUCCESS; } +static void SetLockApiFailed() +{ + (void)pthread_mutex_lock(&g_lockFlag->condLock); + g_lockFlag->error = (uint32)CM_RES_CLIENT_CONNECT_ERR; + (void)pthread_mutex_unlock(&g_lockFlag->condLock); + (void)pthread_cond_signal(&g_lockFlag->cond); +} + +static status_t RecvCmaConnClose() +{ + CmaNotifyClient cmaMsg = {0}; + + if (CmClientRecvMsg((char*)&cmaMsg, sizeof(CmaNotifyClient)) != CM_SUCCESS) { + write_runlog(ERROR, "[%s] client recv msg agent fail or timeout.\n", __FUNCTION__); + return CM_ERROR; + } + + if (cmaMsg.isCmaConnClose) { + write_runlog(LOG, "the CMA and CMS are disconnected.\n"); + SetLockApiFailed(); + } + + return CM_SUCCESS; +} + static status_t RecvMsgFromAgent() { MsgHead msgHead = {0}; @@ -468,6 +493,9 @@ static status_t RecvMsgFromAgent() case MSG_CM_RES_LOCK_ACK: CM_RETURN_IFERR(RecvResLockAckProcess()); break; + case MSG_AGENT_CLIENT_NOTIFY_CONN_CLOSE: + CM_RETURN_IFERR(RecvCmaConnClose()); + break; default: write_runlog(ERROR, "recv unknown msg, msgType(%u).\n", msgHead.msgType); return CM_ERROR; @@ -567,17 +595,17 @@ static void InitGlobalVariable(const char *resName) g_initFlag->initSuccess = false; (void)pthread_mutex_init(&g_initFlag->lock, NULL); - (void)pthread_cond_init(&g_initFlag->cond, NULL); + InitPthreadCondMonotonic(&g_initFlag->cond); while (!g_sendMsg->sendQueue.empty()) { g_sendMsg->sendQueue.pop(); } (void)pthread_mutex_init(&g_sendMsg->lock, NULL); - (void)pthread_cond_init(&g_sendMsg->cond, NULL); + InitPthreadCondMonotonic(&g_sendMsg->cond); (void)pthread_mutex_init(&g_lockFlag->condLock, NULL); (void)pthread_mutex_init(&g_lockFlag->optLock, NULL); - (void)pthread_cond_init(&g_lockFlag->cond, NULL); + InitPthreadCondMonotonic(&g_lockFlag->cond); } status_t PreInit(uint32 instanceId, const char *resName, CmNotifyFunc func, bool *isFirstInit) diff --git a/src/cm_common/cm_json_config.cpp b/src/cm_common/cm_json_config.cpp index a694f38..e7deec7 100644 --- a/src/cm_common/cm_json_config.cpp +++ b/src/cm_common/cm_json_config.cpp @@ -21,7 +21,9 @@ * * ------------------------------------------------------------------------- */ +#include "cm_defs.h" #include "elog.h" +#include "cm_text.h" #include "cm_json_config.h" #define CM_SET_READ_JSON_ERR(errPtr, err) \ @@ -35,6 +37,7 @@ typedef void (*ParseCusRes)(const cJSON *resJson, OneCusResConfJson *resConf); static void ParseAppResConfJson(const cJSON *resJson, OneCusResConfJson *resConf); static void ParseDnResConfJson(const cJSON *resJson, OneCusResConfJson *resConf); +static void ParseVipResConfJson(const cJSON *resJson, OneCusResConfJson *resConf); static void EmptyCmJsonWriteLog(int logLevel, const char *format, ...) { @@ -53,6 +56,7 @@ static CmJsonLogOutput CmJsonWriteLog = EmptyCmJsonWriteLog; static ParseCusResMap g_cusResMap[] = { {"APP", CUSTOM_RESOURCE_APP, ParseAppResConfJson}, {"DN", CUSTOM_RESOURCE_DN, ParseDnResConfJson}, + {"VIP", CUSTOM_RESOURCE_VIP, ParseVipResConfJson}, }; static void *CmJsonMalloc(size_t size) @@ -188,6 +192,9 @@ static void ParseAppDnResConfJson(const cJSON *resJson, CusResConfJson *resConf) if (GetValueIntFromJson(&resConf->restartTimes, resJson, "restart_times") != 0) { resConf->restartTimes = defValue; } + if (GetValueIntFromJson(&resConf->abnormalTimeout, resJson, "abnormal_timeout") != 0) { + resConf->abnormalTimeout = defValue; + } } static void ParseAppResConfJson(const cJSON *resJson, OneCusResConfJson *resConf) @@ -202,6 +209,106 @@ static void ParseDnResConfJson(const cJSON *resJson, OneCusResConfJson *resConf) ParseAllCusResInstConfJson(resJson, &resConf->dnResConf); } +int FetchStrFromText(const char *textStr, char *result, uint32 len, char beginPoint) +{ + bool8 isFetch = CM_FALSE; + uint32 point = 0; + for (uint32 i = 0; textStr[i] != '\0'; ++i) { + if (!isFetch) { + if (textStr[i] == beginPoint) { + isFetch = CM_TRUE; + } + continue; + } + if (textStr[i] == SEPARATOR_CHAR) { + break; + } + if (point >= len) { + return -1; + } + result[point] = textStr[i]; + ++point; + } + CmTrimStr(result); + if (result[0] == '\0') { + return -1; + } + return 0; +} + +int GetValueStrFromText(char *result, uint32 resultLen, const char *textStr, const char *expectValue) +{ + const char *point = strstr(textStr, expectValue); + if (point == NULL) { + write_runlog(ERROR, "Failed to get value str from text, when textStr=[%s], expectValue=[%s].\n", + textStr, expectValue); + return -1; + } + if (FetchStrFromText(point, result, resultLen, '=') != 0) { + write_runlog(ERROR, "Failed to fetch text from string, when textStr=[%s], expectValue=[%s].\n", + textStr, expectValue); + return -1; + } + return 0; +} + +static void ParseOneBaseIp(const cJSON *ipJson, BaseIpListConf *ipConf) +{ + if (GetValueIntFromJson(&ipConf->instId, ipJson, "res_instance_id") != 0) { + ipConf->instId = 0; + } + char baseIp[CM_JSON_STR_LEN] = {0}; + if (GetValueStrFromJson(baseIp, CM_JSON_STR_LEN, ipJson, "inst_attr") != 0) { + return; + } + + if (GetValueStrFromText(ipConf->baseIp, CM_JSON_STR_LEN, baseIp, "base_ip") != 0) { + errno_t rc = memset_s(ipConf->baseIp, CM_JSON_STR_LEN, 0, CM_JSON_STR_LEN); + securec_check_errno(rc, (void)rc); + } +} + +static void ParseAllBaseIp(const cJSON *resJson, VipCusResConfJson *resConf) +{ + cJSON *baseIpArray = cJSON_GetObjectItem(resJson, "instances"); + if (!cJSON_IsArray(baseIpArray)) { + if (baseIpArray != NULL) { + CmJsonWriteLog(WARNING, "[ReadConfJson] \"instances\" obj is not an array, can't parse continue.\n"); + } + return; + } + int arrLen = cJSON_GetArraySize(baseIpArray); + if (arrLen <= 0) { + CmJsonWriteLog(WARNING, "[ReadConfJson] baseIp array len invalid, arrLen=%d, can't parse continue.\n", arrLen); + return; + } + + resConf->baseIpList.count = (uint32)arrLen; + resConf->baseIpList.conf = (BaseIpListConf*)CmJsonMalloc((uint32)arrLen * sizeof(BaseIpListConf)); + + for (int i = 0; i < arrLen; ++i) { + cJSON *resItem = cJSON_GetArrayItem(baseIpArray, i); + if (resItem != NULL) { + ParseOneBaseIp(resItem, &resConf->baseIpList.conf[i]); + } + } +} + +static void ParseVipResConfJson(const cJSON *resJson, OneCusResConfJson *resConf) +{ + errno_t rc; + if (GetValueStrFromJson(resConf->vipResConf.resName, CM_JSON_STR_LEN, resJson, "name") != 0) { + rc = memset_s(resConf->vipResConf.resName, CM_JSON_STR_LEN, 0, CM_JSON_STR_LEN); + securec_check_errno(rc, (void)rc); + } + if (GetValueStrFromJson(resConf->vipResConf.floatIp, CM_JSON_STR_LEN, resJson, "float_ip") != 0) { + rc = memset_s(resConf->vipResConf.floatIp, CM_JSON_STR_LEN, 0, CM_JSON_STR_LEN); + securec_check_errno(rc, (void)rc); + } + + ParseAllBaseIp(resJson, &resConf->vipResConf); +} + static void ParseOneCusResConfJson(const cJSON *resItem, OneCusResConfJson *resConf) { char resType[CM_JSON_STR_LEN] = {0}; @@ -211,7 +318,7 @@ static void ParseOneCusResConfJson(const cJSON *resItem, OneCusResConfJson *resC } size_t arrLen = sizeof(g_cusResMap) / sizeof(g_cusResMap[0]); - for (size_t i = 0; i < arrLen; ++i) { + for (size_t i = 0; i < arrLen; ++i) { if (strcmp(resType, g_cusResMap[i].resTypeName) == 0) { resConf->resType = g_cusResMap[i].resType; g_cusResMap[i].parseFunc(resItem, resConf); diff --git a/src/cm_common/cm_json_parse_floatIp.cpp b/src/cm_common/cm_json_parse_floatIp.cpp new file mode 100644 index 0000000..ab98130 --- /dev/null +++ b/src/cm_common/cm_json_parse_floatIp.cpp @@ -0,0 +1,166 @@ +/* +* 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_json_parse_floatIp.cpp +* +* +* IDENTIFICATION +* src/cm_common/cm_json_parse_floatIp.cpp +* +* ------------------------------------------------------------------------- +*/ + +#include "cm_json_parse_floatIp.h" + +#include "cm_elog.h" +#include "cm_misc.h" +#include "cm_json_config.h" + +static const ParseFloatIpFunc *g_parseFuc = NULL; + +static DnFloatIp *CmGetDnFloatIpByDnIdx(uint32 nodeIdx, uint32 dnIdx) +{ + if (g_parseFuc == NULL || g_parseFuc->getFloatIp == NULL) { + return NULL; + } + return g_parseFuc->getFloatIp(nodeIdx, dnIdx); +} + +static bool IsBaseIpInDnFloatIp(const char *baseIp, const char *floatIp, uint32 nodeIdx, uint32 dnIdx) +{ + DnFloatIp *dnFloatIp = CmGetDnFloatIpByDnIdx(nodeIdx, dnIdx); + if (dnFloatIp == NULL) { + return true; + } + for (uint32 i = 0; i < dnFloatIp->dnFloatIpCount; ++i) { + if (strcmp(baseIp, dnFloatIp->baseIp[i]) == 0) { + write_runlog(LOG, "instId(%u) baseIp(%s) may be existed in floatIp.\n", dnFloatIp->instId, baseIp); + return true; + } + if (strcmp(floatIp, dnFloatIp->dnFloatIp[i]) == 0) { + write_runlog(LOG, "instId(%u) floatIp(%s) may be existed in floatIp.\n", dnFloatIp->instId, floatIp); + return true; + } + } + return false; +} + +static void CmIncreaseFloatIpCnt(uint32 nodeIdx) +{ + if (g_parseFuc == NULL || g_parseFuc->increaseCnt == NULL) { + return; + } + g_parseFuc->increaseCnt(nodeIdx); +} + +static void GenDnFloat(uint32 nodeIdx, uint32 dnIdx, const char *baseIp, const char *floatIp, const char *floatIpName) +{ + DnFloatIp *dnFloatIp = CmGetDnFloatIpByDnIdx(nodeIdx, dnIdx); + if (dnFloatIp == NULL) { + return; + } + if (IsBaseIpInDnFloatIp(baseIp, floatIp, nodeIdx, dnIdx)) { + return; + } + dnFloatIp->instId = g_currentNode->datanode[dnIdx].datanodeId; + dnFloatIp->dataPath = g_currentNode->datanode[dnIdx].datanodeLocalDataPath; + dnFloatIp->dnFloatIpPort = g_currentNode->datanode[dnIdx].datanodePort; + uint32 point = dnFloatIp->dnFloatIpCount; + if (point >= MAX_FLOAT_IP_COUNT) { + write_runlog( + LOG, "instId(%u) point(%u) more than maxCount(%u).\n", dnFloatIp->instId, point, MAX_FLOAT_IP_COUNT); + return; + } + if (point == 0) { + CmIncreaseFloatIpCnt(nodeIdx); + } + errno_t rc = strcpy_s(dnFloatIp->baseIp[point], CM_IP_LENGTH, baseIp); + securec_check_errno(rc, (void)rc); + rc = strcpy_s(dnFloatIp->dnFloatIp[point], CM_IP_LENGTH, floatIp); + securec_check_errno(rc, (void)rc); + rc = strncpy_s(dnFloatIp->floatIpName[point], CM_MAX_RES_NAME, floatIpName, CM_MAX_RES_NAME - 1); + securec_check_errno(rc, (void)rc); + ++dnFloatIp->dnFloatIpCount; +} + +static bool8 CmFindNodeInfoByInstId(uint32 instId, uint32 *nodeIdx, uint32 *dnIdx, const char *str) +{ + if (g_parseFuc == NULL || g_parseFuc->findNodeInfo == NULL) { + return CM_FALSE; + } + return g_parseFuc->findNodeInfo(instId, nodeIdx, dnIdx, str); +} + +static void CheckDnInstInItem(const VipCusResConfJson *vipConf, const char *floatIp, const char *floatIpName) +{ + const char *str = "[CheckDnInstInItem]"; + int32 instId; + uint32 nodeIdx; + uint32 dnIdx; + const char *baseIp; + for (uint32 i = 0; i < vipConf->baseIpList.count; ++i) { + instId = vipConf->baseIpList.conf[i].instId; + if (instId < 0) { + write_runlog(ERROR, "find the error insId(%d) in base_ip_list.\n", instId); + continue; + } + if (!CmFindNodeInfoByInstId((uint32)vipConf->baseIpList.conf[i].instId, &nodeIdx, &dnIdx, str)) { + continue; + } + if (CM_IS_EMPTY_STR(vipConf->baseIpList.conf[i].baseIp) || + CheckIpValid(vipConf->baseIpList.conf[i].baseIp) == CM_FALSE) { + continue; + } + baseIp = vipConf->baseIpList.conf[i].baseIp; + check_input_for_security(baseIp); + if (strcmp(baseIp, floatIp) == 0) { + continue; + } + GenDnFloat(nodeIdx, dnIdx, baseIp, floatIp, floatIpName); + } +} + +void ParseVipConf(int32 logLevel) +{ + if (IsConfJsonEmpty()) { + write_runlog(logLevel, "ParseVipConf, no resource exist.\n"); + return; + } + + char floatIp[MAX_PATH_LEN]; + const char *floatIpName; + errno_t rc; + for (uint32 i = 0; i < g_confJson->resource.count; ++i) { + if (g_confJson->resource.conf[i].resType != CUSTOM_RESOURCE_VIP) { + continue; + } + if (CM_IS_EMPTY_STR(g_confJson->resource.conf[i].vipResConf.floatIp) || + CheckIpValid(g_confJson->resource.conf[i].vipResConf.floatIp) == CM_FALSE) { + continue; + } + rc = memset_s(floatIp, MAX_PATH_LEN, 0, MAX_PATH_LEN); + securec_check_errno(rc, (void)rc); + rc = strcpy_s(floatIp, MAX_PATH_LEN, g_confJson->resource.conf[i].vipResConf.floatIp); + securec_check_errno(rc, (void)rc); + floatIpName = g_confJson->resource.conf[i].vipResConf.resName; + check_input_for_security(floatIpName); + CheckDnInstInItem(&g_confJson->resource.conf[i].vipResConf, floatIp, floatIpName); + } +} + +void InitParseFloatIpFunc(const ParseFloatIpFunc *parseFuc) +{ + g_parseFuc = parseFuc; +} diff --git a/src/cm_common/cm_misc.cpp b/src/cm_common/cm_misc.cpp index 85093a6..54c1133 100644 --- a/src/cm_common/cm_misc.cpp +++ b/src/cm_common/cm_misc.cpp @@ -782,7 +782,7 @@ cluster_msg_string cluster_msg_map_string[] = { {"MSG_AGENT_CLIENT_HEARTBEAT_ACK", MSG_AGENT_CLIENT_HEARTBEAT_ACK}, {"MSG_AGENT_CLIENT_RES_STATUS_LIST", MSG_AGENT_CLIENT_RES_STATUS_LIST}, {"MSG_AGENT_CLIENT_RES_STATUS_CHANGE", MSG_AGENT_CLIENT_RES_STATUS_CHANGE}, - {"MSG_AGENT_CLIENT_SET_RES_DATA_STATUS", MSG_AGENT_CLIENT_SET_RES_DATA_STATUS}, + {"MSG_AGENT_CLIENT_NOTIFY_CONN_CLOSE", MSG_AGENT_CLIENT_NOTIFY_CONN_CLOSE}, {"MSG_AGENT_CLIENT_REPORT_RES_DATA", MSG_AGENT_CLIENT_REPORT_RES_DATA}, {"MSG_EXEC_DDB_COMMAND", MSG_EXEC_DDB_COMMAND}, {"EXEC_DDB_COMMAND_ACK", EXEC_DDB_COMMAND_ACK}, @@ -810,6 +810,7 @@ cluster_msg_string cluster_msg_map_string[] = { {"MSG_CTL_CM_NODE_DISK_STATUS_REQ", (int32)MSG_CTL_CM_NODE_DISK_STATUS_REQ}, {"MSG_CTL_CM_NODE_DISK_STATUS_ACK", (int32)MSG_CTL_CM_NODE_DISK_STATUS_ACK}, {"MSG_AGENT_CM_FLOAT_IP", (int32)MSG_AGENT_CM_FLOAT_IP}, + {"MSG_CTL_CM_FLOAT_IP_REQ", (int32)MSG_CTL_CM_FLOAT_IP_REQ}, {"MSG_CM_AGENT_FLOAT_IP_ACK", (int32)MSG_CM_AGENT_FLOAT_IP_ACK}, {"MSG_AGENT_CM_ISREG_REPORT", (int32)MSG_AGENT_CM_ISREG_REPORT}, {"MSG_CM_AGENT_ISREG_CHECK_LIST_CHANGED", (int32)MSG_CM_AGENT_ISREG_CHECK_LIST_CHANGED}, @@ -1310,3 +1311,11 @@ bool IsNodeIdValid(int nodeId) } return false; } + +bool IsNeedCheckFloatIp() +{ + if (g_clusterType == SingleInstCluster) { + return true; + } + return false; +} diff --git a/src/cm_common/cm_misc_base.cpp b/src/cm_common/cm_misc_base.cpp index 3f447a4..0734ca8 100644 --- a/src/cm_common/cm_misc_base.cpp +++ b/src/cm_common/cm_misc_base.cpp @@ -186,8 +186,18 @@ int GetHomePath(char *outputEnvValue, uint32 envValueLen, int32 logLevel) bool IsBoolCmParamTrue(const char *param) { - return (strcmp(param, "on") == 0) || (strcmp(param, "yes") == 0) || - (strcmp(param, "true") == 0) || (strcmp(param, "1") == 0); + return (strcasecmp(param, "on") == 0) || (strcasecmp(param, "yes") == 0) || (strcasecmp(param, "true") == 0) || + (strcasecmp(param, "1") == 0); +} + +bool CheckBoolConfigParam(const char* value) +{ + if (strcasecmp(value, "on") == 0 || strcasecmp(value, "yes") == 0 || strcasecmp(value, "true") == 0 || + strcasecmp(value, "1") == 0 || strcasecmp(value, "off") == 0 || strcasecmp(value, "no") == 0 || + strcasecmp(value, "false") == 0 || strcasecmp(value, "0") == 0) { + return true; + } + return false; } bool IsSharedStorageMode() @@ -283,3 +293,19 @@ status_t TcpRecvMsg(int socket, char *buf, size_t remainSize, uint32 timeout) return CM_SUCCESS; } + +long GetCurMonotonicTimeSec() +{ + struct timespec curTime = {0, 0}; + (void)clock_gettime(CLOCK_MONOTONIC, &curTime); + return curTime.tv_sec; +} + +void InitPthreadCondMonotonic(pthread_cond_t *cond) +{ + pthread_condattr_t attr; + (void)pthread_condattr_init(&attr); + (void)pthread_condattr_setclock(&attr, CLOCK_MONOTONIC); + (void)pthread_cond_init(cond, &attr); + (void)pthread_condattr_destroy(&attr); +} diff --git a/src/cm_common/cm_misc_res.cpp b/src/cm_common/cm_misc_res.cpp index 9dbc4a1..f335ba3 100644 --- a/src/cm_common/cm_misc_res.cpp +++ b/src/cm_common/cm_misc_res.cpp @@ -28,7 +28,18 @@ bool g_enableSharedStorage = false; CmResStatList g_resStatus[CM_MAX_RES_COUNT] = {{0}}; -uint32 g_resCount = 0; + +static uint32 g_resCount = 0; +static bool8 g_isDnSSMode = CM_FALSE; + +typedef enum IpTypeEn { + IP_TYPE_INIT = 0, + IP_TYPE_UNKNOWN = 1, + IP_TYPE_IPV4, + IP_TYPE_IPV6, + IP_TYPE_NEITHER, + IP_TYPE_CEIL, +} IpType; typedef struct ResConfRangeSt { const char *param; @@ -36,13 +47,34 @@ typedef struct ResConfRangeSt { 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}, - {"instance_id", 1, 2147483647} + {"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); @@ -92,18 +124,44 @@ bool IsResConfValid(const char *param, int value) if (strcmp(param, g_resConfRange[i].param) != 0) { continue; } - int minValue = g_resConfRange[i].min; - int maxValue = g_resConfRange[i].max; - if (value >= minValue && value <= maxValue) { - return true; - } else { - write_runlog(ERROR, "\"%s\":%d invalid, range [%d, %d].\n", param, value, minValue, maxValue); - return false; - } + return (value >= g_resConfRange[i].min && value <= g_resConfRange[i].max); } 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])); @@ -275,6 +333,9 @@ status_t InitAllResStat(int logLevel) 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(); @@ -398,6 +459,107 @@ status_t GetResNameByCmInstId(uint32 instId, char *resName, uint32 nameLen) return CM_ERROR; } +static IpType GetIpType(const char *ip) +{ + if (CM_IS_EMPTY_STR(ip)) { + return IP_TYPE_NEITHER; + } + int32 ip4Cnt = 0; + int32 ip6Cnt = 0; + const int32 ip4CntTotal = 3; + const int32 ip6CntMax = 7; + const int32 ip6CntMin = 2; + uint32 ipLen = (uint32)strlen(ip); + for (uint32 i = 0; i < ipLen; ++i) { + if (ip[i] == '.') { + ++ip4Cnt; + } else if (ip[i] == ':') { + ++ip6Cnt; + } + } + if (ip6Cnt == 0 && ip4Cnt == ip4CntTotal) { + return IP_TYPE_IPV4; + } + if (ip4Cnt == 0 && (ip6Cnt >= ip6CntMin && ip6Cnt <= ip6CntMax)) { + return IP_TYPE_IPV6; + } + write_runlog(ERROR, "ip(%s) is invalid, and ip4Cnt=%d, ip6Cnd=%d.\n", ip, ip4Cnt, ip6Cnt); + return IP_TYPE_NEITHER; +} + +static uint8 CheckIpV4PartlyValid(const char *ipPart) +{ + if (CM_is_str_all_digit(ipPart) != 0) { + write_runlog(ERROR, "ip(%s) is not digital.\n", ipPart); + return CM_FALSE; + } + const uint32 maxLen = 3; + uint32 ipLen = (uint32)strlen(ipPart); + if (ipLen > maxLen) { + return CM_FALSE; + } + if (ipPart[0] == '0' && ipLen > 1) { + write_runlog(ERROR, "ip(%s) first is 0.\n", ipPart); + return CM_FALSE; + } + const int32 maxValue = 255; + int32 value = (int32)CmAtoi(ipPart, 0); + if (value < 0 || value > maxValue) { + write_runlog(ERROR, "ip(%s) value(%d) is not in [%d: %d].\n", ipPart, value, 0, maxValue); + return CM_FALSE; + } + return CM_TRUE; +} + +static uint8 CheckIpV4Valid(char *ip, uint32 ipLen) +{ + if (CM_IS_EMPTY_STR(ip)) { + return CM_FALSE; + } + char baseIp[CM_IP_LENGTH] = {0}; + errno_t rc = strncpy_s(baseIp, CM_IP_LENGTH, ip, ipLen); + securec_check_errno(rc, (void)rc); + + const char *ipPoint = "."; + char *savePtr = NULL; + // first + char *subStr = strtok_r(ip, ipPoint, &savePtr); + CM_RETFALSE_IFNOT(CheckIpV4PartlyValid(subStr)); + + int cnt = 1; + while (!CM_IS_EMPTY_STR(savePtr)) { + subStr = strtok_r(NULL, ipPoint, &savePtr); + CM_RETFALSE_IFNOT(CheckIpV4PartlyValid(subStr)); + ++cnt; + } + const int maxIpv4Part = 4; + if (cnt != maxIpv4Part) { + write_runlog(ERROR, "ip(%s) is invalid, cnt=%d.\n", baseIp, cnt); + return CM_FALSE; + } + + return CM_TRUE; +} + +uint8 CheckIpValid(const char *ip) +{ + char tempIp[CM_IP_LENGTH] = {0}; + errno_t rc = strcpy_s(tempIp, CM_IP_LENGTH, ip); + securec_check_errno(rc, (void)rc); + + if (GetIpType(tempIp) != IP_TYPE_IPV4) { + write_runlog(ERROR, "ip(%s) is invalid, not ipV4.\n", ip); + return CM_FALSE; + } + + if (CheckIpV4Valid(tempIp, CM_IP_LENGTH) == CM_FALSE) { + write_runlog(ERROR, "ipV4(%s) is invalid.\n", ip); + return CM_FALSE; + } + + return CM_TRUE; +} + uint32 CusResCount() { return g_resCount; @@ -405,8 +567,23 @@ uint32 CusResCount() bool IsCusResExist() { - if (g_resCount == 0) { - return false; - } - return true; + 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; } diff --git a/src/cm_common/cm_text.cpp b/src/cm_common/cm_text.cpp new file mode 100644 index 0000000..282abd7 --- /dev/null +++ b/src/cm_common/cm_text.cpp @@ -0,0 +1,267 @@ +/* + * 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_text.cpp + * + * IDENTIFICATION + * src/cm_common/cm_text.cpp + * + * ------------------------------------------------------------------------- + */ +#include +#include "cm_text.h" + +#include "securec.h" +#include "cm_debug.h" + +#include "cm_elog.h" + +bool8 IsCmBracketText(const text_t *text) +{ + bool8 inString = CM_FALSE; + uint32 depth; + const int minLen = 2; + + if (text->len < minLen) { + return CM_FALSE; + } + + bool8 flag = (bool8)(CM_TEXT_BEGIN(text) != '(' || CM_TEXT_END(text) != ')'); + if (flag) { + return CM_FALSE; + } + + depth = 1; + for (uint32 i = 1; i < text->len; i++) { + if (text->str[i] == '\'') { + inString = (bool8)(!inString); + continue; + } + + if (inString) { + continue; + } else if (text->str[i] == '(') { + depth++; + } else if (text->str[i] == ')') { + depth--; + if (depth == 0) { + return (bool8)(i == text->len - 1); + } + } + } + + return CM_FALSE; +} + +void CmRtrimText(text_t *text) +{ + int32 index; + + if (text->str == NULL) { + text->len = 0; + return; + } else if (text->len == 0) { + return; + } + + index = (int32)text->len - 1; + while (index >= 0) { + if ((unsigned char)text->str[index] > (unsigned char)' ') { + text->len = (uint32)(index + 1); + return; + } + + --index; + } +} + +void CmLtrimText(text_t *text) +{ + if (text->str == NULL) { + text->len = 0; + return; + } else if (text->len == 0) { + return; + } + + while (text->len > 0) { + if ((unsigned char)*text->str > ' ') { + break; + } + text->str++; + text->len--; + } +} + +void CmTrimText(text_t *text) +{ + CmLtrimText(text); + CmRtrimText(text); +} + +static void CmRTrimStr(char *str) +{ + int32 strLen = (int32)strlen(str); + int32 i = strLen - 1; + for (; i >= 0; --i) { + if (!isspace(str[i])) { + if (i < strLen - 1) { + str[i + 1] = '\0'; + } + break; + } + } +} + +static void CmLTrimStr(char *str) +{ + uint32 index = 0; + uint32 strLen = (uint32)strlen(str); + for (uint32 i = 0; i < strLen; ++i) { + if (isspace(str[i])) { + ++index; + } else { + break; + } + } + if (index == 0) { + return; + } + char *tempStr = str + index; + uint32 curLen = (uint32)strlen(tempStr); + if (curLen == 0) { + str[0] = '\0'; + return; + } + errno_t rc = memmove_s(str, strlen(str), tempStr, curLen); + securec_check_errno(rc, (void)rc); + str[curLen] = '\0'; +} + +void CmTrimStr(char *str) +{ + if (CM_IS_EMPTY_STR(str)) { + return; + } + CmRTrimStr(str); + CmLTrimStr(str); +} + +void CmRemoveBrackets(text_t *text) +{ + const int lenReduce = 2; + while (IsCmBracketText(text)) { + text->str++; + text->len -= lenReduce; + CmTrimText(text); + } +} + +void CmSplitText(const text_t *text, char splitChar, char encloseChar, text_t *left, text_t *right) +{ + uint32 i; + bool8 isEnclosed = CM_FALSE; + + left->str = text->str; + + for (i = 0; i < text->len; i++) { + if (encloseChar != 0 && text->str[i] == encloseChar) { + isEnclosed = (bool8)(!isEnclosed); + continue; + } + + if (isEnclosed) { + continue; + } + + if (text->str[i] == splitChar) { + left->len = i; + right->str = text->str + i + 1; + right->len = text->len - (i + 1); + return; + } + } + /* if the split_char is not found */ + left->len = text->len; + right->len = 0; + right->str = NULL; +} + +bool8 CmFetchText(text_t *text, char splitChar, char encloseChar, text_t *sub) +{ + text_t remain; + if (text->len == 0) { + CM_TEXT_CLEAR(sub); + return CM_FALSE; + } + + CmSplitText(text, splitChar, encloseChar, sub, &remain); + + text->len = remain.len; + text->str = remain.str; + return CM_TRUE; +} + +bool8 CmTextStrEqualIns(const text_t *text, const char *str) +{ + uint32 i; + + for (i = 0; i < text->len; i++) { + if (UPPER(text->str[i]) != UPPER(str[i]) || str[i] == '\0') { + return CM_FALSE; + } + } + + return (bool8)(str[text->len] == '\0'); +} + +void CmFetchFileName(text_t *files, text_t *name) +{ + if (!CmFetchText(files, ',', '\0', name)) { + return; + } + + CmTrimText(name); + const uint32 quotaionLen = 2; + if (name->str[0] == '\'') { + name->str++; + if (name->len >= quotaionLen) { + name->len -= quotaionLen; + } else { + name->len = 0; + } + + CmTrimText(name); + } +} + +status_t CmText2Str(const text_t *text, char *buf, uint32 bufSize) +{ + if (buf == NULL) { + return CM_ERROR; + } + uint32 copy_size; + CM_ASSERT(bufSize > 1); + copy_size = (text->len >= bufSize) ? bufSize - 1 : text->len; + if (copy_size > 0) { + int res = memcpy_s(buf, bufSize, text->str, copy_size); + if (res != 0) { + return CM_ERROR; + } + } + + buf[copy_size] = '\0'; + return CM_SUCCESS; +} diff --git a/src/cm_communication/cm_protocol/cm_error.cpp b/src/cm_communication/cm_protocol/cm_error.cpp index 489782e..f9077ae 100644 --- a/src/cm_communication/cm_protocol/cm_error.cpp +++ b/src/cm_communication/cm_protocol/cm_error.cpp @@ -23,6 +23,7 @@ */ #include "cm_error.h" #include "cm/cm_elog.h" +#include "cm_text.h" #ifdef __cplusplus extern "C" { diff --git a/src/cm_communication/cm_protocol/cs_ssl.cpp b/src/cm_communication/cm_protocol/cs_ssl.cpp index f2c64a6..56b0287 100644 --- a/src/cm_communication/cm_protocol/cs_ssl.cpp +++ b/src/cm_communication/cm_protocol/cs_ssl.cpp @@ -34,6 +34,8 @@ #include "cm_cipher.h" #include "cm_elog.h" #include "cm_misc_base.h" +#include "cm_text.h" +#include "cm_debug.h" #ifdef __cplusplus extern "C" { @@ -162,25 +164,6 @@ time_t CmCurrentTime() return time(NULL); } -status_t CmText2Str(const text_t *text, char *buf, uint32 buf_size) -{ - if (buf == NULL) { - return CM_ERROR; - } - uint32 copy_size; - CM_ASSERT(buf_size > 1); - copy_size = (text->len >= buf_size) ? buf_size - 1 : text->len; - if (copy_size > 0) { - int res = memcpy_sp(buf, buf_size, text->str, copy_size); - if (res != 0) { - return CM_ERROR; - } - } - - buf[copy_size] = '\0'; - return CM_SUCCESS; -} - static const char *cm_cs_ssl_init_err_string(ssl_init_error_t err) { if (err > SSL_INITERR_NONE && err < SSL_INITERR_LASTERR) { @@ -189,19 +172,6 @@ static const char *cm_cs_ssl_init_err_string(ssl_init_error_t err) return g_ssl_error_string[0]; } -static inline bool cm_text_str_equal_ins(const text_t *text, const char *str) -{ - uint32 i; - - for (i = 0; i < text->len; i++) { - if (UPPER(text->str[i]) != UPPER(str[i]) || str[i] == '\0') { - return false; - } - } - - return (str[text->len] == '\0'); -} - /* Get the last SSL error code and reason */ @@ -772,7 +742,7 @@ static status_t cm_cs_ssl_match_cipher(const text_t *left, char *cipher, uint32_ } for (i = 0; i < count; i++) { - if (!cm_text_str_equal_ins(left, cipher_list[i])) { + if (!CmTextStrEqualIns(left, cipher_list[i])) { continue; } *support = true; @@ -796,59 +766,14 @@ static status_t cm_cs_ssl_match_cipher(const text_t *left, char *cipher, uint32_ return CM_SUCCESS; } -static void cm_split_text(const text_t *text, char split_char, char enclose_char, text_t *left, text_t *right) -{ - uint32 i; - bool is_enclosed = false; - - left->str = text->str; - - for (i = 0; i < text->len; i++) { - if (enclose_char != 0 && text->str[i] == enclose_char) { - is_enclosed = !is_enclosed; - continue; - } - - if (is_enclosed) { - continue; - } - - if (text->str[i] == split_char) { - left->len = i; - right->str = text->str + i + 1; - right->len = text->len - (i + 1); - return; - } - } - /* if the split_char is not found */ - left->len = text->len; - right->len = 0; - right->str = NULL; -} - -static bool cm_fetch_text(text_t *text, char split_char, char enclose_char, text_t *sub) -{ - text_t remain; - if (text->len == 0) { - CM_TEXT_CLEAR(sub); - return false; - } - - cm_split_text(text, split_char, enclose_char, sub, &remain); - - text->len = remain.len; - text->str = remain.str; - return true; -} - static status_t cm_cs_ssl_distinguish_cipher(const char *cipher, char *tls12_cipher, uint32_t *tls12_offset, char *tls13_cipher, uint32_t *tls13_offset) { bool support = false; text_t text, left, right; - cm_str2text((char *)cipher, &text); - cm_split_text(&text, ':', '\0', &left, &right); + CmStr2Text((char *)cipher, &text); + CmSplitText(&text, ':', '\0', &left, &right); text = right; while (left.len > 0) { @@ -870,7 +795,7 @@ static status_t cm_cs_ssl_distinguish_cipher(const char *cipher, char *tls12_cip return CM_ERROR; } - cm_split_text(&text, ':', '\0', &left, &right); + CmSplitText(&text, ':', '\0', &left, &right); text = right; } @@ -922,106 +847,13 @@ static status_t cm_cs_ssl_set_cipher(SSL_CTX *ctx, const ssl_config_t *config, b return CM_SUCCESS; } -static void cm_rtrim_text(text_t *text) -{ - int32 index; - - if (text->str == NULL) { - text->len = 0; - return; - } else if (text->len == 0) { - return; - } - - index = (int32)text->len - 1; - while (index >= 0) { - if ((unsigned char)text->str[index] > (unsigned char)' ') { - text->len = (uint32)(index + 1); - return; - } - - --index; - } -} - -static bool cm_is_bracket_text(const text_t *text) -{ - bool in_string = false; - uint32 depth; - const int minLen = 2; - - if (text->len < minLen) { - return false; - } - - bool flag = CM_TEXT_BEGIN(text) != '(' || CM_TEXT_END(text) != ')'; - if (flag) { - return false; - } - - depth = 1; - for (uint32 i = 1; i < text->len; i++) { - if (text->str[i] == '\'') { - in_string = !in_string; - continue; - } - - if (in_string) { - continue; - } else if (text->str[i] == '(') { - depth++; - } else if (text->str[i] == ')') { - depth--; - if (depth == 0) { - return (i == text->len - 1); - } - } - } - - return false; -} - -static void cm_ltrim_text(text_t *text) -{ - if (text->str == NULL) { - text->len = 0; - return; - } else if (text->len == 0) { - return; - } - - while (text->len > 0) { - if ((unsigned char)*text->str > ' ') { - break; - } - text->str++; - text->len--; - } -} - -static inline void cm_trim_text(text_t *text) -{ - cm_ltrim_text(text); - cm_rtrim_text(text); -} - -static inline void cm_remove_brackets(text_t *text) -{ - const int lenReduce = 2; - while (cm_is_bracket_text(text)) { - text->str++; - text->len -= lenReduce; - cm_trim_text(text); - } -} - static inline void cm_cs_ssl_fetch_file_name(text_t *files, text_t *name) { - if (!cm_fetch_text(files, ',', '\0', name)) { + if (!CmFetchText(files, ',', '\0', name)) { return; } - cm_trim_text(name); + CmTrimText(name); if (name->str[0] == '\'') { name->str++; if (name->len >= 2) { @@ -1030,7 +862,7 @@ static inline void cm_cs_ssl_fetch_file_name(text_t *files, text_t *name) name->len = 0; } - cm_trim_text(name); + CmTrimText(name); } } @@ -1042,8 +874,8 @@ static status_t cm_cs_ssl_set_ca_chain(SSL_CTX *ctx, ssl_config_t *config, bool if (config->ca_file == NULL) { return CM_SUCCESS; } - cm_str2text((char *)config->ca_file, &file_list); - cm_remove_brackets(&file_list); + CmStr2Text((char *)config->ca_file, &file_list); + CmRemoveBrackets(&file_list); cm_cs_ssl_fetch_file_name(&file_list, &file_name); while (file_name.len > 0) { @@ -1102,8 +934,8 @@ static status_t cm_cs_ssl_set_crl_file(SSL_CTX *ctx, ssl_config_t *config) char filepath[CM_FILE_NAME_BUFFER_SIZE]; if (config->crl_file != NULL) { - cm_str2text((char *)config->crl_file, &file_list); - cm_remove_brackets(&file_list); + CmStr2Text((char *)config->crl_file, &file_list); + CmRemoveBrackets(&file_list); cm_cs_ssl_fetch_file_name(&file_list, &file_name); while (file_name.len > 0) { @@ -1225,7 +1057,7 @@ static status_t cm_cs_ssl_resolve_file_name(const char *filename, char *buf, uin *res_buf = filename; return CM_SUCCESS; } - cm_str2text((char *)filename, &text); + CmStr2Text((char *)filename, &text); CM_REMOVE_ENCLOSED_CHAR(&text); CM_RETURN_IFERR(CmText2Str(&text, buf, buf_len)); *res_buf = buf; diff --git a/src/cm_ctl/cm_ctl.cpp b/src/cm_ctl/cm_ctl.cpp index 34443f7..c91305a 100644 --- a/src/cm_ctl/cm_ctl.cpp +++ b/src/cm_ctl/cm_ctl.cpp @@ -39,6 +39,7 @@ #include "hotpatch/hotpatch_client.h" #include "ctl_common.h" +#include "ctl_global_params.h" #include "config.h" #include "cm_util.h" #include "ctl_help.h" @@ -91,9 +92,6 @@ uint32 g_normal_cm_server_node_index = PG_UINT32_MAX; time_t CHECK_BUILDING_DN_TIMEOUT = 60; // in seconds bool is_check_building_dn = true; -CM_Conn* CmServer_conn = NULL; -CM_Conn* CmServer_conn1 = NULL; -CM_Conn* CmServer_conn2 = NULL; char g_appPath[MAXPGPATH] = {0}; const char* g_progname; static char* pgdata_opt = NULL; @@ -112,7 +110,6 @@ char *g_cmsPromoteMode = NULL; bool g_gtmBalance = true; bool g_datanodesBalance = true; cm_to_ctl_central_node_status g_centralNode; -FILE* g_logFilePtr = NULL; #if ((defined(ENABLE_MULTIPLE_NODES)) || (defined(ENABLE_PRIVATEGAUSS))) static char* hotpatch_exec = NULL; @@ -184,12 +181,15 @@ const int DCF_PRIORITY = 17; const int RES_ADD = 18; const int RES_EDIT = 19; const int RES_DEL = 20; -const int RES_CONF_CHECK = 21; -const int RES_NAME = 22; -const int RES_ATTR = 23; -const int RES_ADD_INST = 24; -const int RES_DEL_INST = 25; -const int RES_TYPE = 26; +const int RES_CHECK = 21; +const int RES_NAME_INPUT = 22; +const int RES_ATTR_INPUT = 23; +const int RES_ADD_INST_INPUT = 24; +const int RES_DEL_INST_INPUT = 25; +const int RES_EDIT_INST_INPUT = 27; +const int RES_INST_ATTR_INPUT = 28; +const int RES_LIST = 29; +const int RES_LIST_INST_INPUT = 30; const int ErrorCode = -2; unordered_map g_optToCommand { @@ -1729,18 +1729,6 @@ static void MatchCmdArgCmsPmode(void) } } -static void MatchCmdArgResType(CtlOption *ctlCtx) -{ - for (int32 i = 0; i < (int32)RES_TYPE_CEIL; ++i) { - if (strcmp(optarg, g_resTypeMap[i].typeStr) == 0) { - ctlCtx->resOpt.type = g_resTypeMap[i].type; - return; - } - } - ctlCtx->resOpt.type = RES_TYPE_APP; - write_runlog(WARNING, "cannot find the --res_type(%s).\n", optarg); -} - static void ParseCmdArgsCore(int cmd, bool *setDataPath, CtlOption *ctlCtx) { switch (cmd) { @@ -1928,34 +1916,43 @@ static void ParseCmdArgsCore(int cmd, bool *setDataPath, CtlOption *ctlCtx) MatchCmdArgDcfPriority(ctlCtx); break; case RES_ADD: - ctlCtx->resOpt.mode = RES_ADD_CONF; + ctlCtx->resOpt.mode = RES_OP_ADD; break; case RES_EDIT: - ctlCtx->resOpt.mode = RES_EDIT_CONF; + ctlCtx->resOpt.mode = RES_OP_EDIT; break; case RES_DEL: - ctlCtx->resOpt.mode = RES_DEL_CONF; + ctlCtx->resOpt.mode = RES_OP_DEL; break; - case RES_CONF_CHECK: - ctlCtx->resOpt.mode = RES_CHECK_CONF; + case RES_CHECK: + ctlCtx->resOpt.mode = RES_OP_CHECK; break; - case RES_NAME: + case RES_NAME_INPUT: ctlCtx->resOpt.resName = xstrdup(optarg); break; - case RES_ATTR: + case RES_ATTR_INPUT: ctlCtx->resOpt.resAttr = xstrdup(optarg); - ctlCtx->resOpt.editMode = RES_EDIT_RES_CONF; break; - case RES_ADD_INST: - ctlCtx->resOpt.addInstStr = xstrdup(optarg); - ctlCtx->resOpt.editMode = RES_ADD_INST_CONF; + case RES_ADD_INST_INPUT: + ctlCtx->resOpt.inst.instName = xstrdup(optarg); + ctlCtx->resOpt.inst.mode = RES_OP_ADD; break; - case RES_DEL_INST: - ctlCtx->resOpt.delInstStr = xstrdup(optarg); - ctlCtx->resOpt.editMode = RES_DEL_INST_CONF; + case RES_DEL_INST_INPUT: + ctlCtx->resOpt.inst.instName = xstrdup(optarg); + ctlCtx->resOpt.inst.mode = RES_OP_DEL; break; - case RES_TYPE: - MatchCmdArgResType(ctlCtx); + case RES_EDIT_INST_INPUT: + ctlCtx->resOpt.inst.instName = xstrdup(optarg); + ctlCtx->resOpt.inst.mode = RES_OP_EDIT; + break; + case RES_INST_ATTR_INPUT: + ctlCtx->resOpt.inst.instAttr = xstrdup(optarg); + break; + case RES_LIST: + ctlCtx->resOpt.mode = RES_OP_LIST; + break; + case RES_LIST_INST_INPUT: + ctlCtx->resOpt.inst.mode = RES_OP_LIST; break; default: /* getopt_long already issued a suitable error message */ @@ -2202,7 +2199,7 @@ static void CtlCommandProcessCore(int *status, CtlOption *ctlCtx) *status = DoSwitch(ctlCtx); break; case CM_RES_COMMAND: - *status = DoResCommand(ctlCtx); + *status = DoResCommand(&(ctlCtx->resOpt)); break; case CM_SHOW_COMMAND: *status = DoShowCommand(); @@ -2264,7 +2261,8 @@ int main(int argc, char** argv) /* support --help and --version even if invoked as root */ CheckArgcType(argc, argv); - static struct option longOptions[] = {{"help", no_argument, NULL, '?'}, + static struct option longOptions[] = { + {"help", no_argument, NULL, '?'}, {"version", no_argument, NULL, 'V'}, {"log", required_argument, NULL, 'l'}, {"log_level", optional_argument, NULL, 1}, @@ -2303,14 +2301,18 @@ int main(int argc, char** argv) {"add", no_argument, NULL, RES_ADD}, {"edit", no_argument, NULL, RES_EDIT}, {"del", no_argument, NULL, RES_DEL}, - {"check", no_argument, NULL, RES_CONF_CHECK}, - {"res_name", required_argument, NULL, RES_NAME}, - {"res_attr", required_argument, NULL, RES_ATTR}, - {"add_inst", required_argument, NULL, RES_ADD_INST}, - {"del_inst", required_argument, NULL, RES_DEL_INST}, - {"res_type", required_argument, NULL, RES_TYPE}, + {"check", no_argument, NULL, RES_CHECK}, + {"list", no_argument, NULL, RES_LIST}, + {"res_name", required_argument, NULL, RES_NAME_INPUT}, + {"res_attr", required_argument, NULL, RES_ATTR_INPUT}, + {"add_inst", required_argument, NULL, RES_ADD_INST_INPUT}, + {"del_inst", required_argument, NULL, RES_DEL_INST_INPUT}, + {"edit_inst", required_argument, NULL, RES_EDIT_INST_INPUT}, + {"inst_attr", required_argument, NULL, RES_INST_ATTR_INPUT}, + {"list_inst", no_argument, NULL, RES_LIST_INST_INPUT}, - {NULL, 0, NULL, 0}}; + {NULL, 0, NULL, 0} + }; int optionIndex; int c; diff --git a/src/cm_ctl/ctl_common.cpp b/src/cm_ctl/ctl_common.cpp index e2595ee..260e1b9 100644 --- a/src/cm_ctl/ctl_common.cpp +++ b/src/cm_ctl/ctl_common.cpp @@ -172,7 +172,7 @@ int FindInstanceIdAndType(uint32 node, const char *dataPath, uint32 *instanceId, * ssh_exec * exec command in remote host. */ -int ssh_exec(const staticNodeConfig* node, const char* cmd) +int ssh_exec(const staticNodeConfig* node, const char* cmd, int32 logLevel) { #define MAXLINE 1024 char actualCmd[MAXLINE]; @@ -194,7 +194,7 @@ int ssh_exec(const staticNodeConfig* node, const char* cmd) } rc = system(actualCmd); if (rc != 0) { - write_runlog(ERROR, "ssh failed at \"%s\".\n", node->sshChannel[ii]); + write_runlog(logLevel, "ssh failed at \"%s\".\n", node->sshChannel[ii]); write_runlog(DEBUG1, "cmd is %s, rc=%d, errno=%d.\n", actualCmd, WEXITSTATUS(rc), errno); } } @@ -1870,72 +1870,3 @@ void CtlGetCmJsonConf() write_runlog(DEBUG1, "init res status failed.\n"); } } - -static void OutPutCmdResult(const char *option, const ExecDdbCmdAckMsg *ackPtr) -{ - if (ackPtr->isSuccess) { - if (ackPtr->outputLen < DCC_CMD_MAX_OUTPUT_LEN) { - write_runlog(LOG, "exec ddb %s command success.\n", option); - write_runlog(LOG, "%s\n", ackPtr->output); - } else { - write_runlog(LOG, "exec ddb %s command failed, error msg's buf is smaller(%d/%d).\n", - option, DCC_CMD_MAX_OUTPUT_LEN, ackPtr->outputLen); - write_runlog(LOG, "part result is:\n %s\n", ackPtr->output); - } - } else { - write_runlog(LOG, "exec ddb %s command failed, err msg:\n%s\n", option, ackPtr->errMsg); - } -} - -void GetExecCmdResult(const char *option, int expCmd) -{ - int ret; - int recvTimeOut = EXEC_DDC_CMD_TIMEOUT; - char *receiveMsg = NULL; - cm_msg_type *rcvCmd = NULL; - - for (;;) { - ret = cm_client_flush_msg(CmServer_conn); - if (ret == TCP_SOCKET_ERROR_EPIPE) { - FINISH_CONNECTION_WITHOUT_EXIT(); - } - - receiveMsg = recv_cm_server_cmd(CmServer_conn); - if (receiveMsg != NULL) { - rcvCmd = (cm_msg_type*)receiveMsg; - if (rcvCmd->msg_type == expCmd) { - switch (rcvCmd->msg_type) { - case EXEC_DDB_COMMAND_ACK: { - ExecDdbCmdAckMsg *ackPtr = (ExecDdbCmdAckMsg*)(receiveMsg); - OutPutCmdResult(option, ackPtr); - break; - } - case MSG_CTL_CM_RHB_STATUS_ACK: { - CmRhbStatAck *ackPtr = (CmRhbStatAck*)(receiveMsg); - HandleRhbAck(ackPtr); - break; - } - case MSG_CTL_CM_NODE_DISK_STATUS_ACK: { - CmNodeDiskStatAck *ackPtr = (CmNodeDiskStatAck*)(receiveMsg); - HandleNodeDiskAck(ackPtr); - break; - } - default: - break; - } - } - } - recvTimeOut--; - if (recvTimeOut <= 0 || (rcvCmd != NULL && rcvCmd->msg_type == expCmd)) { - break; - } - cm_sleep(1); - } - - if (recvTimeOut <= 0) { - write_runlog(LOG, "command timeout.\n"); - return; - } - - return; -} diff --git a/src/cm_ctl/ctl_global_params.cpp b/src/cm_ctl/ctl_global_params.cpp new file mode 100644 index 0000000..8d7ae42 --- /dev/null +++ b/src/cm_ctl/ctl_global_params.cpp @@ -0,0 +1,40 @@ +/* + * 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. + * ------------------------------------------------------------------------- + * + * ctl_global_params.cpp + * cm_ctl finishredo functions + * + * IDENTIFICATION + * src/cm_ctl/ctl_global_params.cpp + * + * ------------------------------------------------------------------------- + */ +#include "ctl_global_params.h" + +#include "cm/libpq-fe.h" +#include "cm/libpq-int.h" + +// connect to cms +CM_Conn *CmServer_conn = NULL; +CM_Conn *CmServer_conn1 = NULL; +CM_Conn *CmServer_conn2 = NULL; + +// the fd of fprintf +FILE *g_logFilePtr = stdout; + +CM_Conn *GetCmsConn() +{ + return CmServer_conn; +} diff --git a/src/cm_ctl/ctl_help.cpp b/src/cm_ctl/ctl_help.cpp index 9a0a7e8..0dcd1e7 100644 --- a/src/cm_ctl/ctl_help.cpp +++ b/src/cm_ctl/ctl_help.cpp @@ -93,8 +93,10 @@ static void UsageHelp(const char *projectName) (void)printf(_(" %s encrypt [-M MODE] -D DATADIR\n"), projectName); (void)printf(_(" %s ddb DDB_CMD\n"), projectName); (void)printf(_(" %s switch [--ddb_type=[DDB]] [--commit] [--rollback]\n"), projectName); - (void)printf(_(" %s res [--add | --edit | --del | --check] --res_name=\"NAME\" [--res_type=\"RES_TYPE\" " - "--res_attr=\"RES_INFO\" | --add_inst=\"INST_INFO\" | --del_inst=\"INST_INFO\"]\n"), projectName); + (void)printf(_(" %s res {--add --res_name=\"NAME\" --res_attr=\"RES_INFO\" | " + "--del --res_name=\"NAME\" | --edit --res_name=\"NAME\" | --list {--res_name=\"NAME\"} " + "{--res_attr=\"RES_INFO\" | --add_inst=\"INST_INFO\" | --del_inst=\"INST_INFO\" | --edit_inst=\"INST_INFO\" " + "{--inst_attr=\"INST_ATTR\"} | --list_inst} | --check }\n"), projectName); (void)printf(_(" %s show\n"), projectName); (void)printf(_(" %s pause\n"), projectName); (void)printf(_(" %s resume\n"), projectName); @@ -387,12 +389,14 @@ static void ResCmdHelp() (void)printf(_(" --edit edit one resource or resource instances configuration information.\n")); (void)printf(_(" --del delete one resource or resource instances configuration information.\n")); (void)printf(_(" --check check whether the resource configuration information regular.\n")); + (void)printf(_(" --list list one resource or resource instances configuration information.\n")); (void)printf(_(" --res_name specifies the name of the resource to be operated.\n")); - (void)printf(_(" --res_type specifies the type of the resource to be operated, it can be \"APP\", " - "\"DN\".\n")); (void)printf(_(" --res_attr common resource configuration information.\n")); + (void)printf(_(" --inst_attr common instances configuration information.\n")); (void)printf(_(" --add_inst add instances configuration information of one resource.\n")); (void)printf(_(" --del_inst delete instances configuration information of one resource.\n")); + (void)printf(_(" --edit_inst edit instances configuration information of one resource.\n")); + (void)printf(_(" --list_inst list instances configuration information of one resource.\n")); } void DoHelp(const char *projectName) diff --git a/src/cm_ctl/ctl_misc.cpp b/src/cm_ctl/ctl_misc.cpp index bf7e3d5..9a29491 100644 --- a/src/cm_ctl/ctl_misc.cpp +++ b/src/cm_ctl/ctl_misc.cpp @@ -32,6 +32,7 @@ #include "cm/libpq-fe.h" #include "cm/cm_misc.h" #include "ctl_common.h" +#include "ctl_process_message.h" #include "cm/cm_msg.h" #include "cm/libpq-int.h" #include "cm/cm_agent/cma_main.h" @@ -1811,6 +1812,12 @@ int DoReload() return 0; } +static void SetNodeInstBaseInfo(NodeInstBaseInfo *info, uint32 nodeIdx, uint32 instIdx) +{ + info->nodeIdx = nodeIdx; + info->instIdx = instIdx; +} + int FindInstanceByInstId(uint32 instId, Instance *inst) { for (uint32 nodeIdx = 0; nodeIdx < g_node_num; nodeIdx++) { @@ -1820,6 +1827,7 @@ int FindInstanceByInstId(uint32 instId, Instance *inst) inst->instType = INST_TYPE_GTM; inst->node = curNode->node; inst->InstNode = curNode; + SetNodeInstBaseInfo(&(inst->baseInfo), nodeIdx, 0); return 0; } } @@ -1829,6 +1837,7 @@ int FindInstanceByInstId(uint32 instId, Instance *inst) inst->instType = INST_TYPE_CN; inst->node = curNode->node; inst->InstNode = curNode; + SetNodeInstBaseInfo(&(inst->baseInfo), nodeIdx, 0); return 0; } } @@ -1838,6 +1847,7 @@ int FindInstanceByInstId(uint32 instId, Instance *inst) inst->instType = INST_TYPE_CMSERVER; inst->node = curNode->node; inst->InstNode = curNode; + SetNodeInstBaseInfo(&(inst->baseInfo), nodeIdx, 0); return 0; } } @@ -1847,6 +1857,7 @@ int FindInstanceByInstId(uint32 instId, Instance *inst) inst->instType = INST_TYPE_DN; inst->node = curNode->node; inst->dnInst = &curNode->datanode[i]; + SetNodeInstBaseInfo(&(inst->baseInfo), nodeIdx, i); return 0; } } @@ -2016,6 +2027,7 @@ void DoDccCmd(int argc, char **argv) write_runlog(ERROR, "exec ddb command without param.\n"); return; } + InitDdbCmdMsgFunc(); for (int i = OPTION_POS; i < argc; ++i) { size_t optionLen = strlen(argv[i]); if (optionLen > CM_PATH_LENGTH) { diff --git a/src/cm_ctl/ctl_process_message.cpp b/src/cm_ctl/ctl_process_message.cpp new file mode 100644 index 0000000..a029fd1 --- /dev/null +++ b/src/cm_ctl/ctl_process_message.cpp @@ -0,0 +1,127 @@ +/* + * 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. + * ------------------------------------------------------------------------- + * + * ctl_process_message.cpp + * + * IDENTIFICATION + * src/cm_ctl/ctl_process_message.cpp + * + * ------------------------------------------------------------------------- + */ +#include "ctl_process_message.h" + +#include "cm_msg.h" +#include "cm/libpq-fe.h" +#include "cm/libpq-int.h" + +#include "ctl_common.h" +#include "ctl_show.h" + +static CtlDealCmdFunc g_ctlFunc[MSG_CM_TYPE_CEIL] = {0}; + +static status_t OutPutCmdResult(const char *option, char *recvMsg) +{ + const ExecDdbCmdAckMsg *ackPtr = (const ExecDdbCmdAckMsg *)recvMsg; + if (ackPtr->isSuccess) { + if (ackPtr->outputLen < DCC_CMD_MAX_OUTPUT_LEN) { + write_runlog(LOG, "exec ddb %s command success.\n", option); + write_runlog(LOG, "%s\n", ackPtr->output); + } else { + write_runlog(LOG, "exec ddb %s command failed, error msg's buf is smaller(%d/%d).\n", + option, DCC_CMD_MAX_OUTPUT_LEN, ackPtr->outputLen); + write_runlog(LOG, "part result is:\n %s\n", ackPtr->output); + } + return CM_SUCCESS; + } else { + write_runlog(LOG, "exec ddb %s command failed, err msg:\n%s\n", option, ackPtr->errMsg); + } + return CM_ERROR; +} + +static bool8 RecvAndDealCmd(status_t *cmStatus, CM_Conn *conn, const char *option, int32 expCmd) +{ + char *receiveMsg = (char *)recv_cm_server_cmd(conn); + if (receiveMsg == NULL) { + return CM_FALSE; + } + int32 msgType = ((cm_msg_type *)receiveMsg)->msg_type; + if (expCmd != INVALID_EXPECT_CMD && msgType != expCmd) { + return CM_FALSE; + } + if (msgType < 0 || msgType >= (int32)MSG_CM_TYPE_CEIL) { + write_runlog(ERROR, "invalid msgType(%d).\n", msgType); + return CM_FALSE; + } + CtlDealCmdFunc ctlFunc = g_ctlFunc[msgType]; + if (ctlFunc != NULL) { + *cmStatus = ctlFunc(option, receiveMsg); + return CM_TRUE; + } + write_runlog(DEBUG1, "msgType is %d, but ctlFunc is NULL.\n", msgType); + *cmStatus = CM_ERROR; + if (expCmd != INVALID_EXPECT_CMD) { + return CM_TRUE; + } + return CM_FALSE; +} + +status_t GetExecCmdResult(const char *option, int32 expCmd, CM_Conn *conn) +{ + int ret; + int recvTimeOut = EXEC_DDC_CMD_TIMEOUT; + bool8 dealRet; + status_t cmStatus; + for (;;) { + ret = cm_client_flush_msg(conn); + if (ret == TCP_SOCKET_ERROR_EPIPE) { + FINISH_CONNECTION_WITHOUT_EXIT(); + write_runlog(ERROR, "failed to execute cmd(%d), tcp socket error epipe.\n", expCmd); + return CM_ERROR; + } + dealRet = RecvAndDealCmd(&cmStatus, conn, option, expCmd); + recvTimeOut--; + if (dealRet || recvTimeOut <= 0) { + break; + } + cm_sleep(1); + } + + if (recvTimeOut <= 0) { + write_runlog(LOG, "command timeout.\n"); + return CM_TIMEDOUT; + } + + return cmStatus; +} + +static void ResetCtlFunc() +{ + errno_t rc = memset_s(g_ctlFunc, sizeof(g_ctlFunc), 0, sizeof(g_ctlFunc)); + securec_check_errno(rc, (void)rc); +} + +void InitDdbCmdMsgFunc() +{ + ResetCtlFunc(); + g_ctlFunc[EXEC_DDB_COMMAND_ACK] = OutPutCmdResult; +} + +void InitCtlShowMsgFunc() +{ + ResetCtlFunc(); + g_ctlFunc[MSG_CTL_CM_RHB_STATUS_ACK] = HandleRhbAck; + g_ctlFunc[MSG_CTL_CM_NODE_DISK_STATUS_ACK] = HandleNodeDiskAck; + g_ctlFunc[MSG_CTL_CM_FLOAT_IP_ACK] = HandleFloatIpAck; +} diff --git a/src/cm_ctl/ctl_res.cpp b/src/cm_ctl/ctl_res.cpp index 23bd055..deb4748 100644 --- a/src/cm_ctl/ctl_res.cpp +++ b/src/cm_ctl/ctl_res.cpp @@ -24,53 +24,106 @@ * ------------------------------------------------------------------------- */ #include "cjson/cJSON.h" -#include "cm/libpq-fe.h" + +#include "ctl_res.h" + +#include "c.h" +#include "cm_defs.h" + +#include "cm_text.h" #include "cm_json_config.h" + #include "ctl_common.h" +#include "ctl_res_list.h" static char g_jsonFile[CM_PATH_LENGTH] = {0}; -typedef void (*ProcessConfJson)(cJSON * const confObj, const char *key, const char *value); -typedef status_t (*DelArrayFuc)(cJSON *array, char *instAttr); -typedef status_t (*AddRes)(const ResOption *resCtx); -typedef status_t (*EditRes)(const ResOption *resCtx); -typedef status_t (*DelRes)(const ResOption *resCtx); -typedef status_t (*CheckRes)(); +// res +static const char *g_resSkipMap[] = {RES_NAME, RESOURCE_TYPE, INSTANCES}; +static KvRestrict g_resKv[] = {{RES_KV_TYPE_STRING, RES_NAME}, + {RES_KV_TYPE_STRING, RESOURCE_TYPE}, + {RES_KV_TYPE_ARRAY, INSTANCES}}; -typedef struct ResOperMapT { - ResType type; - AddRes add; - EditRes edit; - DelRes del; - CheckRes check; -} ResOperMap; +// inst +static KvRestrict g_instKv[] = {{RES_KV_TYPE_INTEGER, INST_NODE_ID}, {RES_KV_TYPE_INTEGER, INST_RES_INST_ID}}; +static KvRestrict g_instUniqueKey[] = {{RES_KV_TYPE_INTEGER, INST_RES_INST_ID}}; +static const char *g_instCriticalKey[] = {INST_NODE_ID, INST_RES_INST_ID}; -// APP, DN -static status_t AddResToJsonCore(const ResOption *resCtx); -static status_t EditResInJsonCore(const ResOption *resCtx); -static status_t DelResInJsonCore(const ResOption *resCtx); -static status_t CheckResInJsonCore(); +typedef status_t (*ProcessConfJson)( + const ResOption *resCtx, cJSON *const confObj, ResOpMode mode, const char *key, const char *value); +typedef status_t (*OperateRes)(cJSON *resArray, const ResOption *resCtx); -static void ProcessInstAttrConfJson(cJSON * const confObj, const char *key, const char *value); -static status_t DelInstFromArrayJson(cJSON *array, char *instAttr); -static status_t ResAddInst( - const ResOption *resCtx, const char *resName, ProcessConfJson processFuc = ProcessInstAttrConfJson); -static status_t ResDelInst(const ResOption *resCtx, const char *resName, DelArrayFuc fuc = DelInstFromArrayJson); -static status_t CheckAppResInfo(cJSON *resItem, const char *resName); -static status_t CheckDnResInfo(cJSON *resItem, const char *resName); +typedef bool8 (*CjsonTypeCheck)(const ResOption *resCtx, const cJSON *objValue, const char *key); +typedef bool8 (*CjsonUniqueCheck)( + const ResOption *resCtx, const cJSON *objValue, const cJSON *instArray, const char *key); +typedef status_t (*EditJson)(const ResOption *resCtx, cJSON *root, const char *key, const char *value, ResOpMode mode); -ResTypeMap g_resTypeMap[RES_TYPE_CEIL] = {{RES_TYPE_UNKOWN, "APP", "instances", CheckAppResInfo}, - {RES_TYPE_APP, "APP", "instances", CheckAppResInfo}, - {RES_TYPE_DN, "DN", NULL, CheckDnResInfo}, +typedef void (*printRet)(int32 ret, const char *resName); + +static const char *g_resOperStrMap[] = { + [RES_OP_INIT] = "", + [RES_OP_UNKNOWN] = "[RES_UNKNOWN]", + [RES_OP_ADD] = "[RES_ADD]", + [RES_OP_DEL] = "[RES_DEL]", + [RES_OP_EDIT] = "[RES_EDIT]", + [RES_OP_CHECK] = "[RES_CHECK]", + [RES_OP_LIST] = "[RES_LIST]" }; -static ResOperMap g_resOperMap[RES_TYPE_CEIL] = { - {RES_TYPE_UNKOWN, AddResToJsonCore, EditResInJsonCore, DelResInJsonCore, CheckResInJsonCore}, - {RES_TYPE_APP, AddResToJsonCore, EditResInJsonCore, DelResInJsonCore, CheckResInJsonCore}, - {RES_TYPE_DN, AddResToJsonCore, EditResInJsonCore, DelResInJsonCore, CheckResInJsonCore}, +static const char *g_instOperStrMap[] = { + [RES_OP_INIT] = "", + [RES_OP_UNKNOWN] = "[INST_UNKNOWN]", + [RES_OP_ADD] = "[INST_ADD]", + [RES_OP_DEL] = "[INST_DEL]", + [RES_OP_EDIT] = "[INST_EDIT]", + [RES_OP_CHECK] = "[INST_CHECK]", + [RES_OP_LIST] = "[INST_LIST]" }; -static const char *g_editModeStr[RES_EDIT_CEIL] = {"unkown edit", "add res inst", "del res inst", "add edit inst"}; +static ResTypeStr g_resTypeStrMap[] = {{RES_TYPE_APP, "APP"}, {RES_TYPE_DN, "DN"}, {RES_TYPE_VIP, "VIP"}}; + +static CjsonTypeCheck g_typeCheck[RES_KV_TYPE_CEIL]; +static CjsonUniqueCheck g_uniqueCheck[RES_KV_TYPE_CEIL]; +static EditJson g_editJson[RES_KV_TYPE_CEIL]; + +static OperateRes g_operResMap[RES_OP_CEIL]; +static OperateRes g_operInstMap[RES_OP_CEIL]; +static printRet g_printRet[RES_OP_CEIL]; + +static const char *const *GetOperPoint(ResLevel level) +{ + switch (level) { + case RES_LEVEL_RES: + return g_resOperStrMap; + case RES_LEVEL_INST: + return g_instOperStrMap; + default:; + } + return NULL; +} + +static const char *GetOperStr(ResOpMode opMode, ResLevel level = RES_LEVEL_RES) +{ + const char *const *map = GetOperPoint(level); + if (map == NULL) { + write_runlog(DEBUG1, "cannot find the oper point.\n"); + return "unknown"; + } + if ((int32)opMode < 0 || opMode >= RES_OP_CEIL) { + return map[RES_OP_UNKNOWN]; + } + return map[opMode]; +} + +const char *GetResOperStr(ResOpMode opMode) +{ + return GetOperStr(opMode, RES_LEVEL_RES); +} + +const char *GetInstOperStr(ResOpMode opMode) +{ + return GetOperStr(opMode, RES_LEVEL_INST); +} static bool IsValueNumber(const char *value) { @@ -146,129 +199,168 @@ static status_t WriteJsonFile(const cJSON *root, char *jsonPath) return CM_SUCCESS; } -static status_t SplitKeyAndValue(cJSON *obj, char *str, ProcessConfJson processFuc) +static status_t SplitKeyAndValue( + const ResOption *resCtx, cJSON *obj, char *str, ResOpMode opMode, ProcessConfJson processFuc) { + CmTrimStr(str); if (CM_IS_EMPTY_STR(str)) { - write_runlog(WARNING, "res_attr exist null kv pair, please check.\n"); + write_runlog(WARNING, "%s%s Res(%s) res_attr exist null kv pair, please check.\n", + GetResOperStr(resCtx->mode), GetInstOperStr(resCtx->inst.mode), resCtx->resName); return CM_SUCCESS; } - char *left = NULL; - char *para = strtok_r(str, "=", &left); - if (CM_IS_EMPTY_STR(para)) { - write_runlog(ERROR, "res_attr irregular, parameter is null, please check.\n"); + char *value = NULL; + char *key = strtok_r(str, KEY_VALUE_SPLIT_ARRAY, &value); + CmTrimStr(key); + CmTrimStr(value); + if (CM_IS_EMPTY_STR(key) || (opMode != RES_OP_EDIT && CM_IS_EMPTY_STR(value))) { + write_runlog(ERROR, "%s%s Res(%s) res_attr irregular, key or value may be empty, please check.\n", + GetResOperStr(resCtx->mode), GetInstOperStr(resCtx->inst.mode), resCtx->resName); return CM_ERROR; } - char *value = strtok_r(NULL, "=", &left); - if (CM_IS_EMPTY_STR(value)) { - write_runlog(ERROR, "res_attr irregular, lost \'=\' or value is null, please check.\n"); - return CM_ERROR; - } - processFuc(obj, para, value); - return CM_SUCCESS; + return processFuc(resCtx, obj, opMode, key, value); } -static status_t SplitResAttr(cJSON *obj, char *resAttr, ProcessConfJson fuc) +static status_t SplitResAttr(const ResOption *resCtx, cJSON *obj, char *resAttr, ResOpMode opMode, ProcessConfJson fuc) { char *left = NULL; - char *oneAttr = strtok_r(resAttr, ",", &left); - CM_RETURN_IFERR(SplitKeyAndValue(obj, oneAttr, fuc)); + char *oneAttr = strtok_r(resAttr, SEPARATOR_ARRAY, &left); + CM_RETURN_IFERR(SplitKeyAndValue(resCtx, obj, oneAttr, opMode, fuc)); while (!CM_IS_EMPTY_STR(left)) { - oneAttr = strtok_r(NULL, ",", &left); - CM_RETURN_IFERR(SplitKeyAndValue(obj, oneAttr, fuc)); + oneAttr = strtok_r(NULL, SEPARATOR_ARRAY, &left); + CM_RETURN_IFERR(SplitKeyAndValue(resCtx, obj, oneAttr, opMode, fuc)); } - + return CM_SUCCESS; } -static bool CompareResType(const char *value, uint32 *index) +static ResKvType GetResKvTypeByKey(ResLevel level, const char *key) { - if (value == NULL) { - write_runlog(ERROR, "value is NULL.\n"); - return false; + KvRestrict *kv = NULL; + uint32 len = 0; + if (level == RES_LEVEL_RES) { + kv = g_resKv; + len = ELEMENT_COUNT(g_resKv); + } else if (level == RES_LEVEL_INST) { + kv = g_instKv; + len = ELEMENT_COUNT(g_instKv); } - char resTypeStr[MAX_PATH_LEN] = {0}; - errno_t rc; - uint32 arrLen = (uint32)(sizeof(g_resTypeMap) / sizeof(g_resTypeMap[0])); - char tmpStr[MAX_PATH_LEN] = {0}; - for (uint32 i = 0; i < arrLen; ++i) { - if (strcmp(value, g_resTypeMap[i].typeStr) == 0) { - *index = i; - return true; - } - if (i == 0) { - rc = snprintf_s( - tmpStr, MAX_PATH_LEN, MAX_PATH_LEN - 1, "%s-%s", g_resTypeMap[i].typeStr, g_resTypeMap[i].value); - } else { - rc = snprintf_s( - tmpStr, MAX_PATH_LEN, MAX_PATH_LEN - 1, ", %s-%s", g_resTypeMap[i].typeStr, g_resTypeMap[i].value); - } - securec_check_intval(rc, (void)rc); - rc = strcat_s(resTypeStr, MAX_PATH_LEN, tmpStr); - securec_check_errno(rc, (void)rc); + if (kv == NULL || len == 0) { + return RES_KV_TYPE_OBJECT; } - write_runlog(DEBUG1, "cannot find resType[%s] in g_resTypeMap[%s].\n", value, resTypeStr); - return false; + for (uint32 i = 0; i < len; ++i) { + if (cm_str_equal(kv[i].key, key)) { + return kv[i].type; + } + } + return RES_KV_TYPE_OBJECT; } -void ProcessResAttrConfJson(cJSON * const confObj, const char *key, const char *value) +static EditJson GetEditJson(const ResOption *resCtx, ResLevel level, const char *key, const char *value) { - if (IsValueNumber(value)) { - (void)cJSON_AddNumberToObject(confObj, key, (const double)CmAtol(value, -1)); + ResKvType type = GetResKvTypeByKey(level, key); + if (type < RES_KV_TYPE_INIT || type >= RES_KV_TYPE_CEIL) { + write_runlog(ERROR, "%s%s Res(%s) fails to edit item to Object, when key=[%s], value=[%s].\n", + GetResOperStr(resCtx->mode), GetInstOperStr(resCtx->inst.mode), resCtx->resName, key, value); + return NULL; + } + EditJson add2Json = g_editJson[type]; + if (add2Json == NULL) { + write_runlog(ERROR, "%s%s Res(%s) fails to edit item to Object, when key=[%s], value=[%s], add2Json is NULL.\n", + GetResOperStr(resCtx->mode), GetInstOperStr(resCtx->inst.mode), resCtx->resName, key, value); + return NULL; + } + return add2Json; +} + +static status_t AddItemToObject( + const ResOption *resCtx, cJSON *const confObj, const char *key, const char *value, ResLevel level) +{ + cJSON *obj = cJSON_GetObjectItem(confObj, key); + if (obj != NULL) { + write_runlog(ERROR, "%s%s key(%s) may has exited in Res(%s).\n", GetResOperStr(resCtx->mode), + GetInstOperStr(resCtx->inst.mode), key, resCtx->resName); + return CM_ERROR; + } + + EditJson add2Json = GetEditJson(resCtx, level, key, value); + if (add2Json == NULL) { + return CM_ERROR; + } + return add2Json(resCtx, confObj, key, value, RES_OP_ADD); +} + +static status_t ReplaceItemInObject( + const ResOption *resCtx, cJSON *const confObj, const char *key, const char *value, ResLevel level) +{ + cJSON *obj = cJSON_GetObjectItem(confObj, key); + if (obj == NULL) { + write_runlog(DEBUG1, "%s%s key(%s) may hasn't exited in Res(%s).\n", GetResOperStr(resCtx->mode), + GetInstOperStr(resCtx->inst.mode), key, resCtx->resName); + return AddItemToObject(resCtx, confObj, key, value, level); + } + EditJson add2Json = GetEditJson(resCtx, level, key, value); + if (add2Json == NULL) { + return CM_ERROR; + } + return add2Json(resCtx, confObj, key, value, RES_OP_EDIT); +} + +static status_t EditArrayToJson( + const ResOption *resCtx, cJSON *root, const char *key, const char *value, ResOpMode mode) +{ + if (CM_IS_EMPTY_STR(key)) { + write_runlog(ERROR, "%s%s Res(%s) fails to add array to json, when key is empty.\n", + GetResOperStr(resCtx->mode), GetInstOperStr(resCtx->inst.mode), resCtx->resName); + return CM_ERROR; + } + if (mode != RES_OP_EDIT) { + (void)cJSON_AddArrayToObject(root, key); + return CM_SUCCESS; } else { - (void)cJSON_AddStringToObject(confObj, key, value); - } - uint32 index; - if ((strcmp(key, "resources_type") == 0) && CompareResType(value, &index)) { - if (g_resTypeMap[index].value == NULL) { - return; - } - (void)cJSON_AddArrayToObject(confObj, g_resTypeMap[index].value); + write_runlog(ERROR, "%s%s Res(%s) fails to edit array to json, when mode is replace.\n", + GetResOperStr(resCtx->mode), GetInstOperStr(resCtx->inst.mode), resCtx->resName); + return CM_ERROR; } } -cJSON *ParseResAttr(const char *resName, char *resAttr) +status_t ProcessResAttrConfJson( + const ResOption *resCtx, cJSON *const confObj, ResOpMode mode, const char *key, const char *value) +{ + CM_RETURN_IFERR(AddItemToObject(resCtx, confObj, key, value, RES_LEVEL_RES)); + uint32 index; + if (cm_str_equal(key, RESOURCE_TYPE) && CompareResType(value, &index)) { + if (GetResTypeValue(index) == NULL) { + return CM_SUCCESS; + } + return EditArrayToJson(resCtx, confObj, GetResTypeValue(index), NULL, mode); + } + return CM_SUCCESS; +} + +cJSON *ParseResAttr(const ResOption *resCtx, const char *resName, char *resAttr) { cJSON *resObj = cJSON_CreateObject(); if (!cJSON_IsObject(resObj)) { - write_runlog(ERROR, "create new res json obj failed, add res failed.\n"); + write_runlog(ERROR, "%s Res(%s) create new res json obj failed, add res failed.\n", + GetResOperStr(resCtx->mode), resName); cJSON_Delete(resObj); return NULL; } - if (cJSON_AddStringToObject(resObj, "name", resName) == NULL) { - write_runlog(ERROR, "add name info to new res json obj failed, add res failed.\n"); + if (cJSON_AddStringToObject(resObj, RES_NAME, resName) == NULL) { + write_runlog(ERROR, "%s Res(%s) add name info to new res json obj failed, add res failed.\n", + GetResOperStr(resCtx->mode), resName); cJSON_Delete(resObj); return NULL; } - if (SplitResAttr(resObj, resAttr, ProcessResAttrConfJson) != CM_SUCCESS) { - write_runlog(ERROR, "parse res attr failed, add res failed.\n"); + if (SplitResAttr(resCtx, resObj, resAttr, resCtx->mode, ProcessResAttrConfJson) != CM_SUCCESS) { + write_runlog(ERROR, "%s Res(%s) parse res attr failed, add res failed.\n", + GetResOperStr(resCtx->mode), resName); cJSON_Delete(resObj); return NULL; } return resObj; } -static status_t CanDoAddRes(const ResOption *resCtx) -{ - if (CM_IS_EMPTY_STR(resCtx->resName)) { - write_runlog(ERROR, "res_name is null, cannot do add res.\n"); - return CM_ERROR; - } - if (CM_IS_EMPTY_STR(resCtx->resAttr)) { - write_runlog(ERROR, "res_attr is null, cannot do add res.\n"); - return CM_ERROR; - } - return CM_SUCCESS; -} - -static status_t CanDoDelRes(const ResOption *resCtx) -{ - if (CM_IS_EMPTY_STR(resCtx->resName)) { - write_runlog(ERROR, "res_name is null, cannot do del res.\n"); - return CM_ERROR; - } - return CM_SUCCESS; -} - static cJSON *CreateNewResJsonObj() { cJSON *root = cJSON_CreateObject(); @@ -277,7 +369,7 @@ static cJSON *CreateNewResJsonObj() cJSON_Delete(root); return NULL; } - cJSON *resArray = cJSON_AddArrayToObject(root, "resources"); + cJSON *resArray = cJSON_AddArrayToObject(root, RESOURCES); if (!cJSON_IsArray(resArray)) { write_runlog(ERROR, "create new res json array failed.\n"); cJSON_Delete(root); @@ -286,20 +378,19 @@ static cJSON *CreateNewResJsonObj() return root; } -static status_t AddNewResToJsonObj(const cJSON * const root, cJSON *newRes) +static status_t AddNewResToJsonObj(cJSON *const resArray, cJSON *newRes) { - CM_RETURN_IF_FALSE(cJSON_IsObject(root)); CM_RETURN_IF_FALSE(cJSON_IsObject(newRes)); - cJSON *resArray = cJSON_GetObjectItem(root, "resources"); if (!cJSON_IsArray(resArray)) { write_runlog(ERROR, "json obj in \"%s\" incorrect format.\n", g_jsonFile); return CM_ERROR; } + if (!cJSON_AddItemToArray(resArray, newRes)) { write_runlog(ERROR, "add new res info to json failed.\n"); return CM_ERROR; } - + return CM_SUCCESS; } @@ -321,73 +412,32 @@ static cJSON *GetResJsonFromFile(const char *jsonFile, bool canCreateFile) return root; } -static inline void DeleteAllJson(cJSON *root, cJSON *res) -{ - cJSON_Delete(root); - cJSON_Delete(res); -} - -// command: cm_ctl --add --res_name --res_attr -static status_t AddResToJsonCore(const ResOption *resCtx) -{ - cJSON *root = GetResJsonFromFile(g_jsonFile, true); - CM_RETERR_IF_NULL(root); - cJSON *newRes = ParseResAttr(resCtx->resName, resCtx->resAttr); - CM_RETERR_IF_NULL_EX(newRes, cJSON_Delete(root)); - CM_RETURN_IFERR_EX(AddNewResToJsonObj(root, newRes), DeleteAllJson(root, newRes)); - CM_RETURN_IFERR_EX(WriteJsonFile(root, g_jsonFile), cJSON_Delete(root)); - cJSON_Delete(root); - return CM_SUCCESS; -} - -static status_t CanDoEditResInst(const ResOption *resCtx) -{ - const char *editMode = g_editModeStr[resCtx->editMode]; - const char *editAttr = NULL; - switch (resCtx->editMode) { - case RES_ADD_INST_CONF: - editAttr = resCtx->addInstStr; - break; - case RES_DEL_INST_CONF: - editAttr = resCtx->delInstStr; - break; - case RES_EDIT_RES_CONF: - editAttr = resCtx->resAttr; - break; - default:; - } - if (editAttr == NULL) { - write_runlog(ERROR, "attr is null, cannot do %s.\n", editMode); - return CM_ERROR; - } - return CM_SUCCESS; -} - -static int GetValueIntFromCJson(const cJSON *object, const char *infoKey) +int GetValueIntFromCJson(const cJSON *object, const char *infoKey, int32 logLevel) { cJSON *objValue = cJSON_GetObjectItem(object, infoKey); if (!cJSON_IsNumber(objValue)) { - write_runlog(ERROR, "(%s) object is not number.\n", infoKey); + write_runlog(logLevel, "(%s) object is not number.\n", infoKey); return -1; } if (objValue->valueint < 0) { - write_runlog(ERROR, "get invalid objValue(%d) from cJson, by key(%s).\n", objValue->valueint, infoKey); + write_runlog(logLevel, "get invalid objValue(%d) from cJson, by key(%s).\n", objValue->valueint, infoKey); return -1; } return objValue->valueint; } -static char *GetValueStrFromCJson(const cJSON *object, const char *infoKey) +char *GetValueStrFromCJson(const cJSON *object, const char *infoKey, int32 logLevel) { cJSON *objValue = cJSON_GetObjectItem(object, infoKey); if (!cJSON_IsString(objValue)) { - write_runlog(ERROR, "(%s) object is not string.\n", infoKey); + write_runlog(logLevel, "(%s) object is not string.\n", infoKey); return NULL; } - if (objValue->valuestring == NULL || objValue->valuestring[0] == '\0') { - write_runlog(ERROR, "(%s) object is null.\n", infoKey); + if (CM_IS_EMPTY_STR(objValue->valuestring)) { + write_runlog(logLevel, "(%s) object is null.\n", infoKey); return NULL; } + check_input_for_security(objValue->valuestring); return objValue->valuestring; } @@ -405,11 +455,11 @@ cJSON *GetResFromArray(cJSON *resArray, const char *resName) { cJSON *resItem; cJSON_ArrayForEach(resItem, resArray) { - char *valueStr = GetValueStrFromCJson(resItem, "name"); + char *valueStr = GetValueStrFromCJson(resItem, RES_NAME); if (valueStr == NULL) { continue; } - if (strcmp(valueStr, resName) == 0) { + if (cm_str_equal(valueStr, resName)) { break; } } @@ -420,544 +470,854 @@ cJSON *GetResFromArray(cJSON *resArray, const char *resName) return resItem; } -static void ProcessInstAttrConfJson(cJSON * const confObj, const char *key, const char *value) +// command: cm_ctl res --check +static status_t CheckResInJson(cJSON *resArray, const ResOption *resCtx) { - if ((strcmp(key, "node_id") == 0 || strcmp(key, "res_instance_id") == 0) && IsValueNumber(value)) { - (void)cJSON_AddNumberToObject(confObj, key, (const double)CmAtol(value, -1)); - } else if (strcmp(key, "res_args") == 0) { - (void)cJSON_AddStringToObject(confObj, key, value); - } else { - write_runlog(WARNING, "\"%s=%s\" is invalid for inst json conf, cannot edit json file.\n", key, value); - } + return CheckResFromArray(resArray); } -void ProcessEditAttrConfJson(cJSON *const confObj, const char *key, const char *value) +static bool8 CheckParam(const ResOption *resCtx) { - if (IsValueNumber(value)) { - (void)cJSON_ReplaceItemInObject(confObj, key, cJSON_CreateNumber((const double)CmAtol(value, -1))); - } else { - (void)cJSON_ReplaceItemInObject(confObj, key, cJSON_CreateString(value)); + if (CM_IS_EMPTY_STR(resCtx->resName)) { + write_runlog( + ERROR, "%s%s resName is NULL.\n", GetResOperStr(resCtx->mode), GetInstOperStr(resCtx->inst.mode)); + return CM_FALSE; } + return CM_TRUE; } -static cJSON *ParseInstAttr(char *instAttr, ProcessConfJson processFuc) +static bool8 CheckAddResParam(const ResOption *resCtx) { - cJSON *instObj = cJSON_CreateObject(); - if (!cJSON_IsObject(instObj)) { - write_runlog(ERROR, "create new res inst json obj failed, edit res failed.\n"); - cJSON_Delete(instObj); - return NULL; + CM_RETFALSE_IFNOT(CheckParam(resCtx)); + if (resCtx->resAttr != NULL && resCtx->resAttr[0] == '\0') { + write_runlog(ERROR, "%s Res(%s)'s resAttr is empty.\n", GetResOperStr(resCtx->mode), resCtx->resName); + return CM_FALSE; } - if (SplitResAttr(instObj, instAttr, processFuc) != CM_SUCCESS) { - write_runlog(ERROR, "parse res attr failed, edit res failed.\n"); - cJSON_Delete(instObj); - return NULL; - } - return instObj; + return CM_TRUE; } -static status_t AddNewInstToArrayJson(cJSON *array, cJSON *newInst) +cJSON *GetCurResInArray(cJSON *resArray, const char *resName, const ResOption *resCtx, int32 *resIdx) { - CM_RETURN_IF_FALSE(cJSON_IsArray(array)); - CM_RETURN_IF_FALSE(cJSON_IsObject(newInst)); - if (!cJSON_AddItemToArray(array, newInst)) { - write_runlog(ERROR, "add new newInst info to json failed.\n"); - return CM_ERROR; - } - - return CM_SUCCESS; -} - -static status_t DelInstFromArrayJson(cJSON *array, char *instAttr) -{ - CM_RETURN_IF_FALSE(cJSON_IsArray(array)); - cJSON *delInst = ParseInstAttr(instAttr, ProcessInstAttrConfJson); - if (!cJSON_IsObject(delInst)) { - write_runlog(ERROR, "\"%s\" is invalid for inst json conf.\n", instAttr); - cJSON_Delete(delInst); - return CM_ERROR; - } - int delNodeId = GetValueIntFromCJson(delInst, "node_id"); - int delResInstId = GetValueIntFromCJson(delInst, "res_instance_id"); - - for (int i = 0; i < cJSON_GetArraySize(array); ++i) { - cJSON *resItem = cJSON_GetArrayItem(array, i); - int nodeId = GetValueIntFromCJson(resItem, "node_id"); - int resInstId = GetValueIntFromCJson(resItem, "res_instance_id"); - if (nodeId == delNodeId && resInstId == delResInstId) { - cJSON_DeleteItemFromArray(array, i); - cJSON_Delete(delInst); - return CM_SUCCESS; - } - } - write_runlog(ERROR, "res inst(%s) info do not exist, delete inst info from json failed.\n", instAttr); - cJSON_Delete(delInst); - return CM_ERROR; -} - -static status_t DelResFromJsonObj(const cJSON *const root, const char *resName) -{ - CM_RETURN_IF_FALSE(cJSON_IsObject(root)); - cJSON *resArray = cJSON_GetObjectItem(root, "resources"); if (!cJSON_IsArray(resArray)) { - write_runlog(ERROR, "json obj in \"%s\" incorrect format.\n", g_jsonFile); - return CM_ERROR; + write_runlog(ERROR, "%s%s Res(%s) cannot find resource from JsonFile.\n", GetResOperStr(resCtx->mode), + GetInstOperStr(resCtx->inst.mode), resName); + return NULL; } + + cJSON *resObj; + char *curResName; int32 arraySize = cJSON_GetArraySize(resArray); - for (int32 i = 0; i < arraySize; i++) { - cJSON *resItem = cJSON_GetArrayItem(resArray, i); - char *valueStr = GetValueStrFromCJson(resItem, "name"); - if (valueStr == NULL) { + for (int32 i = 0; i < arraySize; ++i) { + resObj = cJSON_GetArrayItem(resArray, i); + if (!cJSON_IsObject(resObj)) { continue; } - if (strcmp(valueStr, resName) == 0) { - cJSON_DeleteItemFromArray(resArray, i); - return CM_SUCCESS; + curResName = GetValueStrFromCJson(resObj, RES_NAME); + if (curResName != NULL && cm_str_equal(curResName, resName)) { + if (resIdx != NULL) { + *resIdx = i; + } + return resObj; } } - write_runlog(ERROR, "res info(\"name = %s\") do not exist, delete res info from json failed.\n", resName); - return CM_ERROR; + return NULL; } -static status_t GetNumberFromJson(const cJSON * const resItem, const char *resName, const char *checkKey, int32 *value) +static bool8 ResKvTypeCheck(const ResOption *resCtx, const cJSON *resItem, const char *key, ResKvType type) { - cJSON *objValue = cJSON_GetObjectItem(resItem, checkKey); - if (objValue != NULL) { - if (!cJSON_IsNumber(objValue)) { - write_runlog(WARNING, "res(%s) %s object is not a number.\n", resName, checkKey); - return CM_ERROR; - } - } else { - write_runlog(WARNING, "res(%s) has no %s object.\n", resName, checkKey); - return CM_ERROR; + if (type < RES_KV_TYPE_INIT || type >= RES_KV_TYPE_CEIL) { + return g_typeCheck[RES_KV_TYPE_OBJECT](resCtx, resItem, key); } - - if (!IsResConfValid(checkKey, objValue->valueint)) { - write_runlog(WARNING, "res(%s) \"%s\" is valid.\n", resName, checkKey); - return CM_ERROR; + CjsonTypeCheck check = g_typeCheck[type]; + if (check == NULL) { + return g_typeCheck[RES_KV_TYPE_OBJECT](resCtx, resItem, key); } - if (value != NULL) { - *value = objValue->valueint; - } - return CM_SUCCESS; + return check(resCtx, resItem, key); } -void CheckResOptionalInfo(cJSON *resItem, const char *resName, const char *checkKey) +static bool8 CheckKvTypeValid( + const ResOption *resCtx, const cJSON *resItem, const KvRestrict *kvRes, uint32 kvLen, const char *key) { - (void)GetNumberFromJson(resItem, resName, checkKey, NULL); -} - -static status_t CheckResInst(cJSON *instItem, const char *resName) -{ - cJSON *nodeId = cJSON_GetObjectItem(instItem, "node_id"); - if (!cJSON_IsNumber(nodeId)) { - write_runlog(ERROR, "(%s) instances node_id is not number.\n", resName); - return CM_ERROR; + if (CM_IS_EMPTY_STR(key)) { + write_runlog(ERROR, "%s%s Res(%s) cannot check kv type, when key is empty.\n", GetResOperStr(resCtx->mode), + GetInstOperStr(resCtx->inst.mode), resCtx->resName); + return CM_FALSE; } - bool isValid = false; - for (uint32 i = 0; i < g_node_num; i++) { - if (nodeId->valueint == (int)g_node[i].node) { - isValid = true; - break; + + for (uint32 i = 0; i < kvLen; ++i) { + if (cm_str_equal(kvRes[i].key, key)) { + return ResKvTypeCheck(resCtx, resItem, key, kvRes[i].type); } } - if (!isValid) { - write_runlog(ERROR, "(%s) instances node_id is not valid.\n", resName); - return CM_ERROR; - } - cJSON *resInstValue = cJSON_GetObjectItem(instItem, "res_instance_id"); - if (!cJSON_IsNumber(resInstValue) || resInstValue->valueint < 0) { - write_runlog(ERROR, "(%s) res_instance_id object is not valid number.\n", resName); - return CM_ERROR; - } - resInstValue = cJSON_GetObjectItem(instItem, "res_args"); - if (!cJSON_IsString(resInstValue)) { - write_runlog(ERROR, "(%s) res_args object is not string.\n", resName); - return CM_ERROR; - } - check_input_for_security(resInstValue->valuestring); - - return CM_SUCCESS; + return ResKvTypeCheck(resCtx, resItem, key, RES_KV_TYPE_OBJECT); } -static status_t CheckResName( - const cJSON *resItem, char (*resName)[CM_MAX_RES_NAME], uint32 maxCnt, uint32 *curCnt, const char **curResName) +ResType GetResTypeInJson(const ResOption *resCtx, const cJSON *resObj) { - cJSON *objName = cJSON_GetObjectItem(resItem, "name"); - if (!cJSON_IsString(objName)) { - write_runlog(ERROR, "res name(%s) object is not string.\n", objName->valuestring); - return CM_ERROR; + if (!cJSON_IsObject(resObj)) { + write_runlog(DEBUG1, "%s%s Res(%s) cannot find the resType in json, when resObj is not object.\n", + GetResOperStr(resCtx->mode), GetInstOperStr(resCtx->inst.mode), resCtx->resName); + return RES_TYPE_UNKNOWN; } - if (strlen(objName->valuestring) >= CM_MAX_RES_NAME) { - write_runlog(ERROR, - "res name(%s) length exceeds the maximuml, maximuml length is (%d).\n", - objName->valuestring, - CM_MAX_RES_NAME); - return CM_ERROR; + const char *value = GetValueStrFromCJson(resObj, RESOURCE_TYPE); + if (CM_IS_EMPTY_STR(value)) { + write_runlog(DEBUG1, "%s%s Res(%s) cannot find the resType in json, when value is empty.\n", + GetResOperStr(resCtx->mode), GetInstOperStr(resCtx->inst.mode), resCtx->resName); + return RES_TYPE_UNKNOWN; } - uint32 resNameCount = *curCnt; - if (resNameCount >= maxCnt) { - write_runlog(ERROR, "res count exceeds the maximuml, maximuml count is (%u).\n", maxCnt); - return CM_ERROR; + uint32 len = ELEMENT_COUNT(g_resTypeStrMap); + for (uint32 i = 0; i < len; ++i) { + if (cm_str_equal(value, g_resTypeStrMap[i].str)) { + return g_resTypeStrMap[i].type; + } } - errno_t rc = strcpy_s(resName[resNameCount], CM_MAX_RES_NAME, objName->valuestring); - securec_check_errno(rc, (void)rc); - *curResName = resName[resNameCount]; - for (uint32 i = 0; i < resNameCount; i++) { - if (strcmp(resName[resNameCount], resName[i]) == 0) { - write_runlog(ERROR, "res name(%s) object already exists.\n", objName->valuestring); + return RES_TYPE_UNKNOWN; +} + +static bool8 IsCurResCheckInstances(const ResOption *resCtx, const cJSON *resObj) +{ + ResType type = GetResTypeInJson(resCtx, resObj); + return IsResCheckInstances(type); +} + +static status_t CheckResJsonInAdd(const ResOption *resCtx, const cJSON *resObj, const char *resName) +{ + uint32 len = ELEMENT_COUNT(g_resKv); + const cJSON *resItem; + bool8 isCheckInstances = IsCurResCheckInstances(resCtx, resObj); + for (uint32 i = 0; i < len; ++i) { + if (!isCheckInstances && cm_str_equal(g_resKv[i].key, INSTANCES)) { + continue; + } + resItem = cJSON_GetObjectItem(resObj, g_resKv[i].key); + if (!CheckKvTypeValid(resCtx, resItem, g_resKv, len, g_resKv[i].key)) { + write_runlog(ERROR, "%s%s Res(%s) cannot find the item(%s).\n", GetResOperStr(resCtx->mode), + GetInstOperStr(resCtx->inst.mode), resCtx->resName, g_resKv[i].key); return CM_ERROR; } } - ++(*curCnt); return CM_SUCCESS; } -static void GetAllRestypeStr(char *typeStr, uint32 maxlen) +static status_t AddResToJson(cJSON *resArray, const ResOption *resCtx) { - errno_t rc; - uint32 arrLen = (uint32)(sizeof(g_resTypeMap) / sizeof(g_resTypeMap[0])); - char tmpStr[MAX_PATH_LEN] = {0}; - for (uint32 i = 0; i < arrLen; ++i) { - if (g_resTypeMap[i].type == RES_TYPE_UNKOWN) { - continue; - } - if (strlen(typeStr) + strlen(g_resTypeMap[i].typeStr) >= maxlen) { - return; - } - if (i == 0) { - rc = snprintf_s(tmpStr, MAX_PATH_LEN, MAX_PATH_LEN - 1, "\"%s\"", g_resTypeMap[i].typeStr); - } else { - rc = snprintf_s(tmpStr, MAX_PATH_LEN, MAX_PATH_LEN - 1, ", \"%s\"", g_resTypeMap[i].typeStr); - } - securec_check_intval(rc, (void)rc); - rc = strcat_s(typeStr, maxlen, tmpStr); - securec_check_errno(rc, (void)rc); - } -} - -static status_t GetResTypeIndex(const cJSON * const resItem, const char *resName, uint32 *index) -{ - cJSON *objValue = cJSON_GetObjectItem(resItem, "resources_type"); - if (!cJSON_IsString(objValue)) { - write_runlog(ERROR, "(%s) resources_type object is not string.\n", resName); + if (!CheckAddResParam(resCtx)) { return CM_ERROR; } - if (CompareResType(objValue->valuestring, index)) { + const char *str = GetResOperStr(resCtx->mode); + cJSON *resObj = GetCurResInArray(resArray, resCtx->resName, resCtx); + if (resObj != NULL) { + write_runlog(ERROR, "%s Res(%s) may be existed in json.\n", str, resCtx->resName); + return CM_ERROR; + } + cJSON *newRes = ParseResAttr(resCtx, resCtx->resName, resCtx->resAttr); + CM_RETERR_IF_NULL(newRes); + CM_RETURN_IFERR_EX(CheckResJsonInAdd(resCtx, newRes, resCtx->resName), cJSON_Delete(newRes)); + CM_RETURN_IFERR_EX(AddNewResToJsonObj(resArray, newRes), cJSON_Delete(newRes)); + return CM_SUCCESS; +} + +static status_t DelResInJson(cJSON *resArray, const ResOption *resCtx) +{ + const char *str = GetResOperStr(resCtx->mode); + CM_RETURN_IF_FALSE(CheckParam(resCtx)); + int32 resIdx; + cJSON *resObj = GetCurResInArray(resArray, resCtx->resName, resCtx, &resIdx); + if (resObj == NULL) { + write_runlog(ERROR, "%s Res(%s) may be not existed in json.\n", str, resCtx->resName); + return CM_ERROR; + } + cJSON_DeleteItemFromArray(resArray, resIdx); + return CM_SUCCESS; +} + +static void TrimAllRes(ResOption *resCtx) +{ + CmTrimStr(resCtx->resName); + CmTrimStr(resCtx->resAttr); + CmTrimStr(resCtx->inst.instName); + CmTrimStr(resCtx->inst.instAttr); +} + +static status_t DelItemInObjectByKey( + const ResOption *resCtx, cJSON *const confObj, const char *key, const char **skipMap, uint32 mapLen) +{ + if (CM_IS_EMPTY_STR(key)) { return CM_SUCCESS; } - char allResName[MAX_PATH_LEN] = {0}; - GetAllRestypeStr(allResName, MAX_PATH_LEN); - write_runlog(ERROR, "(%s) resources_type object(%s) is not in %s.\n", resName, objValue->string, allResName); - return CM_ERROR; -} - -static status_t CheckStringValidInJson(const cJSON * const resItem, const char *key, const char *resName, int logLevel) -{ - cJSON *objValue = cJSON_GetObjectItem(resItem, key); - if (!cJSON_IsString(objValue)) { - write_runlog(logLevel, "(%s) %s object is not string.\n", resName, key); - return CM_ERROR; - } - check_input_for_security(objValue->valuestring); - return CM_SUCCESS; -} - -static status_t CheckAppDnCommResInfo(cJSON *resItem, const char *resName) -{ - (void)CheckStringValidInJson(resItem, "script", resName, DEBUG1); - - CheckResOptionalInfo(resItem, resName, "check_interval"); - CheckResOptionalInfo(resItem, resName, "time_out"); - CheckResOptionalInfo(resItem, resName, "restart_delay"); - CheckResOptionalInfo(resItem, resName, "restart_period"); - CheckResOptionalInfo(resItem, resName, "restart_times"); - - return CM_SUCCESS; -} - -static status_t CheckAppResInfo(cJSON *resItem, const char *resName) -{ - cJSON *instArray = cJSON_GetObjectItem(resItem, "instances"); - if (!cJSON_IsArray(instArray)) { - write_runlog(ERROR, "(%s) resource_type=\"APP\", \"instances\" doest not exists.\n", resName); - return CM_ERROR; - } - cJSON *instItem; - cJSON_ArrayForEach(instItem, instArray) { - CM_RETURN_IFERR(CheckResInst(instItem, resName)); - } - return CheckAppDnCommResInfo(resItem, resName); -} - -static status_t CheckDnResInfo(cJSON *resItem, const char *resName) -{ - cJSON *instArray = cJSON_GetObjectItem(resItem, "instances"); - if (cJSON_IsArray(instArray)) { - cJSON *instItem; - cJSON_ArrayForEach(instItem, instArray) { - CM_RETURN_IFERR(CheckResInst(instItem, resName)); + for (uint32 i = 0; i < mapLen; ++i) { + if (cm_str_equal(key, skipMap[i])) { + write_runlog(ERROR, "%s%s Res(%s) cannot del the item(%s).\n", GetResOperStr(resCtx->mode), + GetInstOperStr(resCtx->inst.mode), resCtx->resName, key); + return CM_ERROR; } } - return CheckAppDnCommResInfo(resItem, resName); + cJSON_DeleteItemFromObject(confObj, key); + return CM_SUCCESS; } -static status_t CheckResFromArray(cJSON *resArray) +static status_t EditResAttrConfJson( + const ResOption *resCtx, cJSON *const confObj, ResOpMode mode, const char *key, const char *value) { - cJSON *resItem; - const uint32 maxResCnt = CM_MAX_RES_COUNT + CM_MAX_VIP_COUNT; - char resName[maxResCnt][CM_MAX_RES_NAME]; - uint32 resNameCount = 0; - const char *curResName; - uint32 curIndex = 0; - CheckResInfo check; - cJSON_ArrayForEach(resItem, resArray) { - CM_RETURN_IFERR(CheckResName(resItem, resName, maxResCnt, &resNameCount, &curResName)); + if (CM_IS_EMPTY_STR(value)) { + return DelItemInObjectByKey(resCtx, confObj, key, g_resSkipMap, ELEMENT_COUNT(g_resSkipMap)); + } + if (mode != RES_OP_EDIT) { + return AddItemToObject(resCtx, confObj, key, value, RES_LEVEL_RES); + } else { + return ReplaceItemInObject(resCtx, confObj, key, value, RES_LEVEL_RES); + } +} - CM_RETURN_IFERR(GetResTypeIndex(resItem, curResName, &curIndex)); +static status_t EditResAddr(cJSON *resObj, const ResOption *resCtx) +{ + if (CM_IS_EMPTY_STR(resCtx->resAttr)) { + return CM_SUCCESS; + } + if (SplitResAttr(resCtx, resObj, resCtx->resAttr, resCtx->mode, EditResAttrConfJson) != CM_SUCCESS) { + write_runlog(ERROR, "%s%s Res(%s) failed to edit res addr.\n", GetOperStr(resCtx->mode), + GetInstOperStr(resCtx->inst.mode), resCtx->resName); + return CM_ERROR; + } + return CM_SUCCESS; +} - check = g_resTypeMap[curIndex].check; +static bool8 CheckEditParam(const ResOption *resCtx) +{ + CM_RETFALSE_IFNOT(CheckParam(resCtx)); + if (CM_IS_EMPTY_STR(resCtx->resAttr) && CM_IS_EMPTY_STR(resCtx->inst.instName)) { + write_runlog(ERROR, "%s%s Res(%s) failed to edit res, when resAtrr is NULL, and inst is NULL.\n", + GetOperStr(resCtx->mode), GetInstOperStr(resCtx->inst.mode), resCtx->resName); + return CM_FALSE; + } + return CM_TRUE; +} - // resource may not be checked. - if (check == NULL) { +static status_t GetInstanceArray(cJSON **instArray, const ResOption *resCtx, cJSON *resObj) +{ + if (IsCurNotCheckInstances(resCtx, resObj)) { + return CM_SUCCESS; + } + cJSON *tempInstArray = cJSON_GetObjectItem(resObj, INSTANCES); + if (tempInstArray != NULL) { + if (!cJSON_IsArray(tempInstArray)) { + write_runlog(ERROR, "%s%s Res(%s) cannot find the array(%s).\n", GetResOperStr(resCtx->mode), + GetInstOperStr(resCtx->inst.mode), resCtx->resName, INSTANCES); + return CM_ERROR; + } else { + *instArray = tempInstArray; + return CM_SUCCESS; + } + } + if (EditArrayToJson(resCtx, resObj, INSTANCES, NULL, RES_OP_ADD) != CM_SUCCESS) { + return CM_ERROR; + } + tempInstArray = cJSON_GetObjectItem(resObj, INSTANCES); + if (!cJSON_IsArray(tempInstArray)) { + write_runlog(ERROR, "%s%s Res(%s) cannot get the array(%s) from json.\n", GetResOperStr(resCtx->mode), + GetInstOperStr(resCtx->inst.mode), resCtx->resName, INSTANCES); + return CM_ERROR; + } + *instArray = tempInstArray; + return CM_SUCCESS; +} + +static status_t EditResInJson(cJSON *resArray, const ResOption *resCtx) +{ + const char *editStr = GetResOperStr(resCtx->mode); + const char *instStr = GetInstOperStr(resCtx->inst.mode); + CM_RETURN_IF_FALSE(CheckEditParam(resCtx)); + cJSON *resObj = GetCurResInArray(resArray, resCtx->resName, resCtx, NULL); + if (resObj == NULL) { + write_runlog(ERROR, "%s%s Res(%s) may be not existed in json.\n", editStr, instStr, resCtx->resName); + return CM_ERROR; + } + CM_RETURN_IFERR(EditResAddr(resObj, resCtx)); + if (CM_IS_EMPTY_STR(resCtx->inst.instName)) { + write_runlog(DEBUG1, "%s%s Res(%s) inst may be empty.\n", GetResOperStr(resCtx->mode), + GetInstOperStr(resCtx->inst.mode), resCtx->resName); + return CM_SUCCESS; + } + if (resCtx->inst.mode < RES_OP_INIT || resCtx->inst.mode >= RES_OP_CEIL) { + write_runlog(ERROR, "%s Res(%s) instMode(%d) is unknown.\n", GetResOperStr(resCtx->mode), resCtx->resName, + (int32)resCtx->inst.mode); + return CM_ERROR; + } + OperateRes operInstMap = g_operInstMap[resCtx->inst.mode]; + if (operInstMap == NULL) { + write_runlog(ERROR, "%s Res(%s) instMode%s may not supprot.\n", GetResOperStr(resCtx->mode), resCtx->resName, + GetInstOperStr(resCtx->inst.mode)); + return CM_ERROR; + } + cJSON *instArray = NULL; + if (GetInstanceArray(&instArray, resCtx, resObj) != CM_SUCCESS) { + write_runlog(ERROR, "%s%s Res(%s) cannot find the array(%s).\n", GetResOperStr(resCtx->mode), + GetInstOperStr(resCtx->inst.mode), resCtx->resName, INSTANCES); + return CM_ERROR; + } + return operInstMap(instArray, resCtx); +} + +static bool8 CheckInstParam(const ResOption *resCtx) +{ + if (CM_IS_EMPTY_STR(resCtx->inst.instName)) { + write_runlog(ERROR, "%s%s Res(%s) inst is empty.\n", GetResOperStr(resCtx->mode), + GetInstOperStr(resCtx->inst.mode), resCtx->resName); + return CM_FALSE; + } + return CM_TRUE; +} + +static bool8 IsUniqueKey(const KvRestrict *uniqueKey, uint32 len, const char *key) +{ + for (uint32 i = 0; i < len; ++i) { + if (cm_str_equal(uniqueKey[i].key, key)) { + return CM_TRUE; + } + } + return CM_FALSE; +} + +static status_t EditInstAttrConfJson( + const ResOption *resCtx, cJSON *const confObj, ResOpMode mode, const char *key, const char *value) +{ + if (CM_IS_EMPTY_STR(value)) { + return DelItemInObjectByKey(resCtx, confObj, key, g_instCriticalKey, ELEMENT_COUNT(g_instCriticalKey)); + } + if (mode != RES_OP_EDIT) { + return AddItemToObject(resCtx, confObj, key, value, RES_LEVEL_INST); + } else { + if (IsUniqueKey(g_instUniqueKey, ELEMENT_COUNT(g_instUniqueKey), key)) { + return CM_SUCCESS; + } + return ReplaceItemInObject(resCtx, confObj, key, value, RES_LEVEL_INST); + } +} + +static bool8 CheckUniqueInArray( + const ResOption *resCtx, const cJSON *resArray, const cJSON *resObj, const char *key, ResKvType type) +{ + if (CM_IS_EMPTY_STR(key)) { + write_runlog(ERROR, "%s%s Res(%s) cannot check unique, when key is empty.\n", GetResOperStr(resCtx->mode), + GetInstOperStr(resCtx->inst.mode), resCtx->resName); + return CM_FALSE; + } + if (type < RES_KV_TYPE_INIT || type >= RES_KV_TYPE_CEIL) { + write_runlog(ERROR, "%s%s Res(%s) cannot check unique, when type is %d.\n", GetResOperStr(resCtx->mode), + GetInstOperStr(resCtx->inst.mode), resCtx->resName, (int32)type); + return CM_FALSE; + } + + CjsonUniqueCheck check = g_uniqueCheck[type]; + if (check == NULL) { + write_runlog(ERROR, "%s%s Res(%s) cannot check unique, when type=%d, and check is NULL.\n", + GetResOperStr(resCtx->mode), GetInstOperStr(resCtx->inst.mode), resCtx->resName, (int32)type); + return CM_FALSE; + } + return check(resCtx, resObj, resArray, key); +} + +static status_t CheckCjsonObjInAdd(const ResOption *resCtx, const cJSON *resArray, const cJSON *resObj) +{ + uint32 len = ELEMENT_COUNT(g_instCriticalKey); + const cJSON *resItem; + for (uint32 i = 0; i < len; ++i) { + resItem = cJSON_GetObjectItem(resObj, g_instCriticalKey[i]); + if (!CheckKvTypeValid(resCtx, resItem, g_instKv, ELEMENT_COUNT(g_instKv), g_instCriticalKey[i])) { + write_runlog(ERROR, "%s%s Res(%s) cannot find the item(%s).\n", GetResOperStr(resCtx->mode), + GetInstOperStr(resCtx->inst.mode), resCtx->resName, g_instCriticalKey[i]); + return CM_ERROR; + } + } + len = ELEMENT_COUNT(g_instUniqueKey); + for (uint32 i = 0; i < len; ++i) { + if (!CheckUniqueInArray(resCtx, resArray, resObj, g_instUniqueKey[i].key, g_instUniqueKey[i].type)) { + return CM_ERROR; + } + } + return CM_SUCCESS; +} + +status_t GetIntFromText(const ResOption *resCtx, const char *str, const char *expectValue, int32 *value, int32 logLevel) +{ + const char *point = strstr(str, expectValue); + if (point == NULL) { + write_runlog(logLevel, "%s%s Res(%s) failed to get %s from text, when %s doesn't exist in inst.\n", + GetResOperStr(resCtx->mode), GetInstOperStr(resCtx->inst.mode), resCtx->resName, expectValue, expectValue); + return CM_ERROR; + } + char valueStr[MAX_PATH_LEN] = {0}; + if (FetchStrFromText(point, valueStr, MAX_PATH_LEN, '=') != 0) { + write_runlog(logLevel, "%s%s Res(%s) failed to get %s from text, when %s cannot be find in inst.\n", + GetResOperStr(resCtx->mode), GetInstOperStr(resCtx->inst.mode), resCtx->resName, expectValue, expectValue); + return CM_ERROR; + } + if (!IsValueNumber(valueStr)) { + write_runlog(logLevel, "%s%s Res(%s) failed to get %s from text, when %s may be not integer.\n", + GetResOperStr(resCtx->mode), GetInstOperStr(resCtx->inst.mode), resCtx->resName, expectValue, expectValue); + return CM_ERROR; + } + *value = CmAtoi(valueStr, -1); + return CM_SUCCESS; +} + +static status_t FindInstIdInInstName(const ResOption *resCtx, ResInstInfo *instInfo) +{ + instInfo->instId = -1; + instInfo->nodeId = -1; + + if (CM_IS_EMPTY_STR(resCtx->inst.instName)) { + write_runlog(ERROR, "%s%s Res(%s) failed to get inst from array, when inst is NULL.\n", + GetResOperStr(resCtx->mode), GetInstOperStr(resCtx->inst.mode), resCtx->resName); + return CM_ERROR; + } + + CM_RETURN_IFERR(GetIntFromText(resCtx, resCtx->inst.instName, INST_RES_INST_ID, &instInfo->instId, ERROR)); + + if (strstr(resCtx->inst.instName, INST_NODE_ID) != NULL) { + CM_RETURN_IFERR(GetIntFromText(resCtx, resCtx->inst.instName, INST_NODE_ID, &instInfo->nodeId, DEBUG1)); + if (instInfo->instId == -1) { + write_runlog(ERROR, "%s%s Res(%s) failed to get instId from array, when instId is invalid.\n", + GetResOperStr(resCtx->mode), GetInstOperStr(resCtx->inst.mode), resCtx->resName); + return CM_ERROR; + } + } + write_runlog(DEBUG1, "%s%s Res(%s) success to get nodeId(%d), instId(%d).\n", GetResOperStr(resCtx->mode), + GetInstOperStr(resCtx->inst.mode), resCtx->resName, instInfo->nodeId, instInfo->instId); + return CM_SUCCESS; +} + +static cJSON *GetInstFromArray(const ResOption *resCtx, const cJSON *resArray, int32 *index) +{ + if (CM_IS_EMPTY_STR(resCtx->inst.instName)) { + write_runlog(ERROR, "%s%s Res(%s) failed to get inst from array, when inst is NULL.\n", + GetResOperStr(resCtx->mode), GetInstOperStr(resCtx->inst.mode), resCtx->resName); + return NULL; + } + ResInstInfo instInfo; + if (FindInstIdInInstName(resCtx, &instInfo) != CM_SUCCESS) { + return NULL; + } + cJSON *resObj; + int32 instId; + int32 nodeId; + int32 arraySize = cJSON_GetArraySize(resArray); + for (int32 i = 0; i < arraySize; ++i) { + resObj = cJSON_GetArrayItem(resArray, i); + if (!cJSON_IsObject(resObj)) { continue; } - CM_RETURN_IFERR(check(resItem, curResName)); + instId = GetValueIntFromCJson(resObj, INST_RES_INST_ID); + nodeId = GetValueIntFromCJson(resObj, INST_NODE_ID); + if (instId != instInfo.instId) { + continue; + } + if ((instInfo.nodeId != -1 && instInfo.nodeId == nodeId) || (instInfo.nodeId == -1)) { + if (index != NULL) { + *index = i; + } + return resObj; + } } - return CM_SUCCESS; + return NULL; } -static cJSON *GetConfJsonArray(cJSON *resItem, const char *resName) +static status_t EditStringToJson( + const ResOption *resCtx, cJSON *root, const char *key, const char *value, ResOpMode mode) { - cJSON *instArray = cJSON_GetObjectItem(resItem, resName); - if (!cJSON_IsArray(instArray)) { - instArray = cJSON_AddArrayToObject(resItem, resName); - } - return instArray; -} - -// command: cm_ctl --edit --res_name --add_inst -static status_t ResAddInst(const ResOption *resCtx, const char *resName, ProcessConfJson processFuc) -{ - cJSON *root = GetResJsonFromFile(g_jsonFile, false); - CM_RETERR_IF_NULL(root); - cJSON *resArray = GetArrayFromObj(root, "resources"); - CM_RETURN_IF_FALSE_EX(cJSON_IsArray(resArray), cJSON_Delete(root)); - cJSON *resItem = GetResFromArray(resArray, resCtx->resName); - CM_RETERR_IF_NULL_EX(resItem, cJSON_Delete(root)); - cJSON *instArray = GetConfJsonArray(resItem, resName); - CM_RETURN_IF_FALSE_EX(cJSON_IsArray(instArray), cJSON_Delete(root)); - cJSON *newInst = ParseInstAttr(resCtx->addInstStr, processFuc); - CM_RETERR_IF_NULL_EX(newInst, cJSON_Delete(root)); - - CM_RETURN_IFERR_EX(AddNewInstToArrayJson(instArray, newInst), DeleteAllJson(root, newInst)); - CM_RETURN_IFERR_EX(WriteJsonFile(root, g_jsonFile), cJSON_Delete(root)); - cJSON_Delete(root); - - return CM_SUCCESS; -} - -// command: cm_ctl --edit --res_name --del_inst -static status_t ResDelInst(const ResOption *resCtx, const char *resName, DelArrayFuc fuc) -{ - cJSON *root = GetResJsonFromFile(g_jsonFile, false); - CM_RETERR_IF_NULL(root); - cJSON *resArray = GetArrayFromObj(root, "resources"); - CM_RETURN_IF_FALSE_EX(cJSON_IsArray(resArray), cJSON_Delete(root)); - cJSON *resItem = GetResFromArray(resArray, resCtx->resName); - CM_RETERR_IF_NULL_EX(resItem, cJSON_Delete(root)); - cJSON *instArray = cJSON_GetObjectItem(resItem, resName); - CM_RETURN_IF_FALSE_EX(cJSON_IsArray(instArray), cJSON_Delete(root)); - - CM_RETURN_IFERR_EX(fuc(instArray, resCtx->delInstStr), cJSON_Delete(root)); - CM_RETURN_IFERR_EX(WriteJsonFile(root, g_jsonFile), cJSON_Delete(root)); - cJSON_Delete(root); - - return CM_SUCCESS; -} - -// command: cm_ctl --edit --res_name --res_attr -static status_t ResEditInst(const ResOption *resCtx) -{ - cJSON *root = GetResJsonFromFile(g_jsonFile, false); - CM_RETERR_IF_NULL(root); - cJSON *resArray = GetArrayFromObj(root, "resources"); - CM_RETURN_IF_FALSE_EX(cJSON_IsArray(resArray), cJSON_Delete(root)); - cJSON *resItem = GetResFromArray(resArray, resCtx->resName); - CM_RETERR_IF_NULL_EX(resItem, cJSON_Delete(root)); - - CM_RETURN_IFERR_EX(SplitResAttr(resItem, resCtx->resAttr, ProcessEditAttrConfJson), cJSON_Delete(root)); - CM_RETURN_IFERR_EX(WriteJsonFile(root, g_jsonFile), cJSON_Delete(root)); - cJSON_Delete(root); - - return CM_SUCCESS; -} - -static status_t EditResInJsonCore(const ResOption *resCtx) -{ - switch (resCtx->editMode) { - case RES_ADD_INST_CONF: - return ResAddInst(resCtx, "instances"); - case RES_DEL_INST_CONF: - return ResDelInst(resCtx, "instances"); - case RES_EDIT_RES_CONF: - return ResEditInst(resCtx); - case RES_EDIT_UNKNOWN: - write_runlog(ERROR, "not input (--add_inst,--del_inst,--res_attr), please check input.\n"); - break; - default: - write_runlog(ERROR, "unknown edit mode(%u), cannot do edit res.\n", (uint32)resCtx->editMode); - break; - } - - return CM_ERROR; -} - -// command: cm_ctl res --del --res_name -static status_t DelResInJsonCore(const ResOption *resCtx) -{ - cJSON *root = GetResJsonFromFile(g_jsonFile, false); - CM_RETERR_IF_NULL(root); - CM_RETURN_IFERR_EX(DelResFromJsonObj(root, resCtx->resName), cJSON_Delete(root)); - CM_RETURN_IFERR_EX(WriteJsonFile(root, g_jsonFile), cJSON_Delete(root)); - cJSON_Delete(root); - return CM_SUCCESS; -} - -// command: cm_ctl res --check -static status_t CheckResInJsonCore() -{ - cJSON *root = GetResJsonFromFile(g_jsonFile, false); - CM_RETERR_IF_NULL(root); - cJSON *resArray = cJSON_GetObjectItem(root, "resources"); - if (!cJSON_IsArray(resArray)) { - write_runlog(ERROR, "resources do not exist.\n"); - cJSON_Delete(root); + if (CM_IS_EMPTY_STR(key) || CM_IS_EMPTY_STR(value)) { + write_runlog(ERROR, "%s%s Res(%s) fails to add string to json, when key or value is empty.\n", + GetResOperStr(resCtx->mode), GetInstOperStr(resCtx->inst.mode), resCtx->resName); return CM_ERROR; } - CM_RETURN_IFERR_EX(CheckResFromArray(resArray), cJSON_Delete(root)); - cJSON_Delete(root); + check_input_for_security(value); + if (mode != RES_OP_EDIT) { + (void)cJSON_AddStringToObject(root, key, value); + } else { + (void)cJSON_ReplaceItemInObject(root, key, cJSON_CreateString(value)); + } return CM_SUCCESS; } -static ResOperMap *FindOperMapByType(ResType type) +static status_t SetInstAttrToJson(const ResOption *resCtx, cJSON *resObj, ResOpMode mode) { - int32 unknownIndex = 0; - for (int32 i = 0; i < (int32)RES_TYPE_CEIL; ++i) { - if (g_resOperMap[i].type == type) { - return &(g_resOperMap[i]); - } - if (g_resOperMap[i].type == RES_TYPE_UNKOWN) { - unknownIndex = i; + if (resCtx->inst.instAttr == NULL) { + return CM_SUCCESS; + } + if (resCtx->inst.instAttr[0] == '\0') { + cJSON_DeleteItemFromObject(resObj, INST_ATTR); + } else { + return EditStringToJson(resCtx, resObj, INST_ATTR, resCtx->inst.instAttr, mode); + } + return CM_SUCCESS; +} + +static status_t AddInstToJson(cJSON *resArray, const ResOption *resCtx) +{ + CM_RETURN_IF_FALSE(CheckInstParam(resCtx)); + if (GetInstFromArray(resCtx, resArray, NULL) != NULL) { + write_runlog(ERROR, "%s%s Res(%s) failed to add inst to json, when inst in json.\n", + GetResOperStr(resCtx->mode), GetInstOperStr(resCtx->inst.mode), resCtx->resName); + return CM_ERROR; + } + + cJSON *resObj = cJSON_CreateObject(); + if (SplitResAttr(resCtx, resObj, resCtx->inst.instName, resCtx->inst.mode, EditInstAttrConfJson) != + CM_SUCCESS) { + write_runlog(ERROR, "%s%s Res(%s) failed to add inst to json.\n", + GetResOperStr(resCtx->mode), GetInstOperStr(resCtx->inst.mode), resCtx->resName); + cJSON_Delete(resObj); + return CM_ERROR; + } + + if (SetInstAttrToJson(resCtx, resObj, RES_OP_ADD) != CM_SUCCESS) { + write_runlog(ERROR, "%s%s Res(%s) failed to add %s to json.\n", GetResOperStr(resCtx->mode), + GetInstOperStr(resCtx->inst.mode), resCtx->resName, INST_ATTR); + cJSON_Delete(resObj); + return CM_ERROR; + } + + if (CheckCjsonObjInAdd(resCtx, resArray, resObj) != CM_SUCCESS) { + cJSON_Delete(resObj); + return CM_ERROR; + } + + if (AddNewResToJsonObj(resArray, resObj) != CM_SUCCESS) { + write_runlog(ERROR, "%s%s Res(%s) failed to add obj to array.\n", + GetResOperStr(resCtx->mode), GetInstOperStr(resCtx->inst.mode), resCtx->resName); + cJSON_Delete(resObj); + return CM_ERROR; + } + return CM_SUCCESS; +} + +static status_t DelInstInJson(cJSON *resArray, const ResOption *resCtx) +{ + CM_RETURN_IF_FALSE(CheckInstParam(resCtx)); + int32 index; + if (GetInstFromArray(resCtx, resArray, &index) == NULL) { + write_runlog(ERROR, "%s%s Res(%s) cannot find the inst in json.\n", + GetResOperStr(resCtx->mode), GetInstOperStr(resCtx->inst.mode), resCtx->resName); + return CM_ERROR; + } + cJSON_DeleteItemFromArray(resArray, index); + return CM_SUCCESS; +} + +static status_t EditInstInJson(cJSON *resArray, const ResOption *resCtx) +{ + CM_RETURN_IF_FALSE(CheckInstParam(resCtx)); + cJSON *resObj = GetInstFromArray(resCtx, resArray, NULL); + if (resObj == NULL) { + write_runlog(ERROR, "%s%s Res(%s) cannot find then inst in json.\n", + GetResOperStr(resCtx->mode), GetInstOperStr(resCtx->inst.mode), resCtx->resName); + return CM_ERROR; + } + + if (SplitResAttr(resCtx, resObj, resCtx->inst.instName, resCtx->inst.mode, EditInstAttrConfJson) != + CM_SUCCESS) { + write_runlog(ERROR, "%s%s Res(%s) failed to edit inst to json.\n", + GetResOperStr(resCtx->mode), GetInstOperStr(resCtx->inst.mode), resCtx->resName); + return CM_ERROR; + } + + if (SetInstAttrToJson(resCtx, resObj, resCtx->inst.mode) != CM_SUCCESS) { + write_runlog(ERROR, "%s%s Res(%s) failed to edit %s to json.\n", GetResOperStr(resCtx->mode), + GetInstOperStr(resCtx->inst.mode), resCtx->resName, INST_ATTR); + return CM_ERROR; + } + return CM_SUCCESS; +} + +static bool8 CjsonIntegerCheck(const ResOption *resCtx, const cJSON *objValue, const char *key) +{ + if (!cJSON_IsNumber(objValue)) { + write_runlog(ERROR, "%s%s Res(%s) key(%s) value is not integer.\n", + GetResOperStr(resCtx->mode), GetInstOperStr(resCtx->inst.mode), resCtx->resName, key); + return CM_FALSE; + } + + if (objValue->valueint < 0) { + write_runlog(ERROR, "%s%s Res(%s) key(%s) value is negative number.\n", + GetResOperStr(resCtx->mode), GetInstOperStr(resCtx->inst.mode), resCtx->resName, key); + return CM_FALSE; + } + return CM_TRUE; +} + +static bool8 CjsonStringCheck(const ResOption *resCtx, const cJSON *objValue, const char *key) +{ + if (!cJSON_IsString(objValue)) { + write_runlog(ERROR, "%s%s Res(%s) key(%s) value is not string.\n", + GetResOperStr(resCtx->mode), GetInstOperStr(resCtx->inst.mode), resCtx->resName, key); + return CM_FALSE; + } + + if (CM_IS_EMPTY_STR(objValue->valuestring)) { + write_runlog(ERROR, "%s%s Res(%s) key(%s) value is empty.\n", + GetResOperStr(resCtx->mode), GetInstOperStr(resCtx->inst.mode), resCtx->resName, key); + return CM_FALSE; + } + check_input_for_security(objValue->valuestring); + return CM_TRUE; +} + +static bool8 CjsonArrayCheck(const ResOption *resCtx, const cJSON *objValue, const char *key) +{ + if (!cJSON_IsArray(objValue)) { + write_runlog(ERROR, "%s%s Res(%s) key(%s) value is not array.\n", + GetResOperStr(resCtx->mode), GetInstOperStr(resCtx->inst.mode), resCtx->resName, key); + return CM_FALSE; + } + + return CM_TRUE; +} + +static bool8 CjsonObjectCheck(const ResOption *resCtx, const cJSON *objValue, const char *key) +{ + if (objValue == NULL) { + write_runlog(ERROR, "%s%s Res(%s) key(%s) value is not object.\n", + GetResOperStr(resCtx->mode), GetInstOperStr(resCtx->inst.mode), resCtx->resName, key); + return CM_FALSE; + } + return CM_TRUE; +} + +static bool8 IntegerUniqueCheck(const ResOption *resCtx, const cJSON *objValue, const cJSON *instArray, const char *key) +{ + int32 value = GetValueIntFromCJson(objValue, key); + if (value < 0) { + write_runlog(ERROR, "%s%s Res(%s) fail to check integer unique key(%s) value is invalid.\n", + GetResOperStr(resCtx->mode), GetInstOperStr(resCtx->inst.mode), resCtx->resName, key); + return CM_FALSE; + } + const cJSON *objItem; + int32 tmpValue; + cJSON_ArrayForEach(objItem, instArray) { + tmpValue = GetValueIntFromCJson(objItem, key); + if (tmpValue == value) { + write_runlog(ERROR, "%s%s Res(%s) unique_key([%s]: [%d]) may be repeat.\n", GetResOperStr(resCtx->mode), + GetInstOperStr(resCtx->inst.mode), resCtx->resName, key, value); + return CM_FALSE; } } - return &(g_resOperMap[unknownIndex]); + return CM_TRUE; } -static int AddResToJson(const ResOption *resCtx) +static bool8 StringUniqueCheck(const ResOption *resCtx, const cJSON *objValue, const cJSON *instArray, const char *key) { - if (CanDoAddRes(resCtx) != CM_SUCCESS) { - write_runlog(ERROR, "add res(%s) fail.\n", resCtx->resName); - return -1; + const char *value = GetValueStrFromCJson(objValue, key); + if (CM_IS_EMPTY_STR(value)) { + write_runlog(ERROR, "%s%s Res(%s) fail to check integer unique key(%s) value is empty.\n", + GetResOperStr(resCtx->mode), GetInstOperStr(resCtx->inst.mode), resCtx->resName, key); + return CM_FALSE; } - ResOperMap *oper = FindOperMapByType(resCtx->type); - if (oper->add == NULL) { - write_runlog(ERROR, "add res(%s) fail, bacause add oper is NULL.\n", resCtx->resName); - return -1; + const cJSON *objItem; + const char *tmpValue; + cJSON_ArrayForEach(objItem, instArray) { + tmpValue = GetValueStrFromCJson(objItem, key); + if (!CM_IS_EMPTY_STR(tmpValue) && cm_str_equal(tmpValue, value)) { + write_runlog(ERROR, "%s%s Res(%s) unique_key([%s]: [%s]) may be repeat.\n", GetResOperStr(resCtx->mode), + GetInstOperStr(resCtx->inst.mode), resCtx->resName, key, value); + return CM_FALSE; + } } - if (oper->add(resCtx) == CM_SUCCESS) { - write_runlog(LOG, "add res(%s) success.\n", resCtx->resName); - return 0; + return CM_TRUE; +} + +static status_t EditIntegerToJson( + const ResOption *resCtx, cJSON *root, const char *key, const char *value, ResOpMode mode) +{ + if (CM_IS_EMPTY_STR(key) || CM_IS_EMPTY_STR(value)) { + write_runlog(ERROR, "%s%s Res(%s) fails to add integer to json, when key or value is empty.\n", + GetResOperStr(resCtx->mode), GetInstOperStr(resCtx->inst.mode), resCtx->resName); + return CM_ERROR; + } + if (!IsValueNumber(value)) { + write_runlog(ERROR, "%s%s Res(%s) fails to add integer to json, when value(%s) is not number.\n", + GetResOperStr(resCtx->mode), GetInstOperStr(resCtx->inst.mode), resCtx->resName, value); + return CM_ERROR; + } + if (mode != RES_OP_EDIT) { + (void)cJSON_AddNumberToObject(root, key, (const double)CmAtol(value, -1)); } else { - write_runlog(ERROR, "add res(%s) fail.\n", resCtx->resName); - return -1; + (void)cJSON_ReplaceItemInObject(root, key, cJSON_CreateNumber((const double)CmAtol(value, -1))); } + return CM_SUCCESS; } -static int EditResInJson(const ResOption *resCtx) +static status_t EditObjectToJson( + const ResOption *resCtx, cJSON *root, const char *key, const char *value, ResOpMode mode) { - if (resCtx->resName == NULL) { - write_runlog(ERROR, "res_name is null, cannot do edit res.\n"); - return -1; - } - if (resCtx->editMode >= RES_EDIT_CEIL) { - write_runlog( - ERROR, "edit res(%s) fail, with unknown edit mode(%d).\n", resCtx->resName, (int32)resCtx->editMode); - return -1; - } - if (CanDoEditResInst(resCtx) != CM_SUCCESS) { - write_runlog(ERROR, "edit res(%s) fail.\n", resCtx->resName); - return -1; + if (CM_IS_EMPTY_STR(key) || CM_IS_EMPTY_STR(value)) { + write_runlog(ERROR, "%s%s Res(%s) fails to add object to json, when key or value is empty.\n", + GetResOperStr(resCtx->mode), GetInstOperStr(resCtx->inst.mode), resCtx->resName); + return CM_ERROR; } - ResOperMap *oper = FindOperMapByType(resCtx->type); - if (oper->edit == NULL) { - write_runlog(ERROR, "edit res(%s) fail, bacause add oper is NULL.\n", resCtx->resName); - return -1; + if (mode != RES_OP_EDIT) { + if (IsValueNumber(value)) { + (void)cJSON_AddNumberToObject(root, key, (const double)CmAtol(value, -1)); + } else { + check_input_for_security(value); + (void)cJSON_AddStringToObject(root, key, value); + } + return CM_SUCCESS; } - if (oper->edit(resCtx) == CM_SUCCESS) { - write_runlog(LOG, "edit res(%s) success.\n", resCtx->resName); - return 0; + if (IsValueNumber(value)) { + (void)cJSON_ReplaceItemInObject(root, key, cJSON_CreateNumber((const double)CmAtol(value, -1))); } else { - write_runlog(ERROR, "edit res(%s) fail.\n", resCtx->resName); - return -1; + (void)cJSON_ReplaceItemInObject(root, key, cJSON_CreateString(value)); } + return CM_SUCCESS; } -static int DelResInJson(const ResOption *resCtx) +static void AddPrintRet(int32 ret, const char *resName) { - if (CanDoDelRes(resCtx) != CM_SUCCESS) { - write_runlog(ERROR, "delete res(%s) fail, please check file \"%s\".\n", resCtx->resName, g_jsonFile); - return -1; - } - ResOperMap *oper = FindOperMapByType(resCtx->type); - if (oper->del == NULL) { - write_runlog(ERROR, "del res(%s) fail, bacause add oper is NULL.\n", resCtx->resName); - return -1; - } - if (oper->del(resCtx) == CM_SUCCESS) { - write_runlog(LOG, "delete res(%s) success.\n", resCtx->resName); - return 0; + if (ret == 0) { + write_runlog(LOG, "add res(%s) success.\n", resName); } else { - write_runlog(ERROR, "delete res(%s) fail, please check file \"%s\".\n", resCtx->resName, g_jsonFile); - return -1; + write_runlog(ERROR, "add res(%s) fail.\n", resName); } } -static int CheckResInJson(const ResOption *resCtx) +static void EditPrintRet(int32 ret, const char *resName) { - ResOperMap *oper = FindOperMapByType(resCtx->type); - if (oper->check == NULL) { - write_runlog(ERROR, "check res(%s) fail, bacause add oper is NULL.\n", resCtx->resName); - return -1; + if (ret == 0) { + write_runlog(LOG, "edit res(%s) success.\n", resName); + } else { + write_runlog(ERROR, "edit res(%s) fail.\n", resName); } - if (oper->check() == CM_SUCCESS) { +} + +static void DelPrintRet(int32 ret, const char *resName) +{ + if (ret == 0) { + write_runlog(LOG, "delete res(%s) success.\n", resName); + } else { + write_runlog(ERROR, "delete res(%s) fail, please check file \"%s\".\n", resName, g_jsonFile); + } +} + +static void CheckPrintRet(int32 ret, const char *resName) +{ + if (ret == 0) { write_runlog(LOG, "resource config is valid.\n"); - return 0; } else { write_runlog(ERROR, "resource config is invalid, please check file \"%s\".\n", g_jsonFile); - return -1; } } -int DoResCommand(const CtlOption *ctx) +static void InitOperResMap() { - GetCmConfJsonPath(g_jsonFile, sizeof(g_jsonFile)); - switch (ctx->resOpt.mode) { - case RES_ADD_CONF: - return AddResToJson(&ctx->resOpt); - case RES_EDIT_CONF: - return EditResInJson(&ctx->resOpt); - case RES_DEL_CONF: - return DelResInJson(&ctx->resOpt); - case RES_CHECK_CONF: - return CheckResInJson(&ctx->resOpt); - case RES_CONF_UNKNOWN: - write_runlog(ERROR, "not input (--add,--edit,--del,--check), please check input.\n"); - break; - default: - write_runlog(ERROR, "unknown cm_ctl res opt %u.\n", (uint32)ctx->resOpt.mode); - break; - } - return -1; + InitResTypeMap(); + + // res + errno_t rc = memset_s(g_operResMap, sizeof(g_operResMap), 0, sizeof(g_operResMap)); + securec_check_errno(rc, (void)rc); + g_operResMap[RES_OP_ADD] = AddResToJson; + g_operResMap[RES_OP_DEL] = DelResInJson; + g_operResMap[RES_OP_EDIT] = EditResInJson; + g_operResMap[RES_OP_CHECK] = CheckResInJson; + g_operResMap[RES_OP_LIST] = ListResInJson; + + // inst + rc = memset_s(g_operInstMap, sizeof(g_operInstMap), 0, sizeof(g_operInstMap)); + securec_check_errno(rc, (void)rc); + g_operInstMap[RES_OP_ADD] = AddInstToJson; + g_operInstMap[RES_OP_DEL] = DelInstInJson; + g_operInstMap[RES_OP_EDIT] = EditInstInJson; + g_operInstMap[RES_OP_CHECK] = NULL; + g_operInstMap[RES_OP_LIST] = NULL; + + // type + rc = memset_s(g_typeCheck, sizeof(g_typeCheck), 0, sizeof(g_typeCheck)); + securec_check_errno(rc, (void)rc); + g_typeCheck[RES_KV_TYPE_INTEGER] = CjsonIntegerCheck; + g_typeCheck[RES_KV_TYPE_STRING] = CjsonStringCheck; + g_typeCheck[RES_KV_TYPE_ARRAY] = CjsonArrayCheck; + g_typeCheck[RES_KV_TYPE_OBJECT] = CjsonObjectCheck; + + // unique + rc = memset_s(g_uniqueCheck, sizeof(g_uniqueCheck), 0, sizeof(g_uniqueCheck)); + securec_check_errno(rc, (void)rc); + g_uniqueCheck[RES_KV_TYPE_INTEGER] = IntegerUniqueCheck; + g_uniqueCheck[RES_KV_TYPE_STRING] = StringUniqueCheck; + + rc = memset_s(g_editJson, sizeof(g_editJson), 0, sizeof(g_editJson)); + securec_check_errno(rc, (void)rc); + g_editJson[RES_KV_TYPE_INTEGER] = EditIntegerToJson; + g_editJson[RES_KV_TYPE_STRING] = EditStringToJson; + g_editJson[RES_KV_TYPE_ARRAY] = EditArrayToJson; + g_editJson[RES_KV_TYPE_OBJECT] = EditObjectToJson; + + rc = memset_s(g_printRet, sizeof(g_printRet), 0, sizeof(g_printRet)); + securec_check_errno(rc, (void)rc); + g_printRet[RES_OP_ADD] = AddPrintRet; + g_printRet[RES_OP_DEL] = DelPrintRet; + g_printRet[RES_OP_EDIT] = EditPrintRet; + g_printRet[RES_OP_CHECK] = CheckPrintRet; +} + +void CheckAndWriteJson(const cJSON *root, ResOpMode mode) +{ + if (mode == RES_OP_ADD || mode == RES_OP_DEL || mode == RES_OP_EDIT) { + if (WriteJsonFile(root, g_jsonFile) != CM_SUCCESS) { + write_runlog(ERROR, "failed to write json file(%s).\n", g_jsonFile); + } + } +} + +static void PrintExecRet(int32 ret, const char *resName, ResOpMode mode) +{ + if (mode < RES_OP_INIT || mode >= RES_OP_CEIL) { + return; + } + printRet printRet = g_printRet[mode]; + if (printRet != NULL) { + printRet(ret, resName); + } +} + +int32 DoResOperCmd(ResOption *resCtx) +{ + if (resCtx->mode >= RES_OP_CEIL) { + write_runlog(ERROR, "unknown cm_ctl res opt %u.\n", (uint32)resCtx->mode); + return -1; + } + OperateRes operRes = g_operResMap[resCtx->mode]; + if (operRes == NULL) { + write_runlog(ERROR, "not input (--add,--edit,--del,--check), please check input.\n"); + return -1; + } + + GetCmConfJsonPath(g_jsonFile, sizeof(g_jsonFile)); + + cJSON *root = GetResJsonFromFile(g_jsonFile, (resCtx->mode == RES_OP_ADD)); + if (root == NULL) { + write_runlog(ERROR, "Failed to get res json from File(%s).\n", g_jsonFile); + return -1; + } + // resources + cJSON *resArray = cJSON_GetObjectItem(root, RESOURCES); + if (!cJSON_IsArray(resArray)) { + write_runlog(ERROR, "failed to get resource array from jsonFile(%s).\n", g_jsonFile); + cJSON_Delete(root); + return -1; + } + + int32 ret = (int32)operRes(resArray, resCtx); + if (ret == 0) { + CheckAndWriteJson(root, resCtx->mode); + } + PrintExecRet(ret, resCtx->resName, resCtx->mode); + cJSON_Delete(root); + return ret; +} + +int DoResCommand(ResOption *resCtx) +{ + TrimAllRes(resCtx); + InitOperResMap(); + return DoResOperCmd(resCtx); } diff --git a/src/cm_ctl/ctl_res_check.cpp b/src/cm_ctl/ctl_res_check.cpp new file mode 100644 index 0000000..3803017 --- /dev/null +++ b/src/cm_ctl/ctl_res_check.cpp @@ -0,0 +1,681 @@ +/* +* Copyright (c) 2023 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. +* ------------------------------------------------------------------------- +* +* ctl_res.cpp +* cm_ctl res --check +* +* IDENTIFICATION +* src/cm_ctl/ctl_res_check.cpp +* +* ------------------------------------------------------------------------- + */ + +#include "cjson/cJSON.h" + +#include "cm_text.h" + +#include "ctl_res.h" +#include "ctl_common.h" +#include "ctl_common_res.h" + +typedef struct FloatIpResInfoT { + char ip[CM_IP_LENGTH]; + int32 instId; +} FloatIpResInfo; + +static status_t CheckAppResInfo(cJSON *resItem, const char *resName); +static status_t CheckDnResInfo(cJSON *resItem, const char *resName); +static status_t CheckVipResInfo(cJSON *resItem, const char *resName); + +ResTypeMap g_resTypeMap[RES_TYPE_CEIL]; + +const char *g_instAttrMap[] = {"base_ip"}; + +static void PrintCheckJsonInfo(int level, const char* fmt, ...) +{ + va_list ap; + char infoBuf[MAX_LOG_BUFF_LEN] = {0}; + + fmt = _(fmt); + va_start(ap, fmt); + int ret = vsnprintf_s(infoBuf, sizeof(infoBuf), sizeof(infoBuf) - 1, fmt, ap); + securec_check_intval(ret, (void)ret); + + switch (level) { + case WARNING: + write_runlog(level, "warning: %s", infoBuf); + break; + case ERROR: + write_runlog(level, "error: %s", infoBuf); + break; + default: + write_runlog(level, "%s", infoBuf); + break; + } + + va_end(ap); +} + +static bool8 CmCheckIsJsonNumber(const cJSON *obj, const char *resName, const char *paraName, int logLevel) +{ + const char *defValue = ResConfDefValue(paraName); + if (obj == NULL) { + PrintCheckJsonInfo(logLevel, "resource(%s)'s %s not configured, default(%s).\n", resName, paraName, defValue); + return CM_FALSE; + } + if (!cJSON_IsNumber(obj)) { + PrintCheckJsonInfo(logLevel, "resource(%s)'s %s is not a number, default(%s).\n", resName, paraName, defValue); + return CM_FALSE; + } + + return CM_TRUE; +} + +static bool8 CmCheckIsJsonString(const cJSON *obj, const char *resName, const char *paraName, int logLevel) +{ + const char *defValue = ResConfDefValue(paraName); + if (obj == NULL) { + PrintCheckJsonInfo(logLevel, "resource(%s)'s %s not configured, default(%s).\n", resName, paraName, defValue); + return CM_FALSE; + } + if (!cJSON_IsString(obj)) { + PrintCheckJsonInfo(logLevel, "resource(%s)'s %s is not a string, default(%s).\n", resName, paraName, defValue); + return CM_FALSE; + } + + return CM_TRUE; +} + +static bool8 CmCheckIsJsonBool(const cJSON *obj, const char *resName, const char *paraName, int logLevel) +{ + const char *defValue = ResConfDefValue(paraName); + if (obj == NULL) { + PrintCheckJsonInfo(logLevel, "resource(%s)'s %s not configured, default(%s).\n", resName, paraName, defValue); + return CM_FALSE; + } + if (!cJSON_IsBool(obj) && (!cJSON_IsString(obj) || !CheckBoolConfigParam(obj->valuestring))) { + PrintCheckJsonInfo(logLevel, "resource(%s)'s %s is not a bool, default(%s).\n", resName, paraName, defValue); + return CM_FALSE; + } + + return CM_TRUE; +} + +static status_t CheckOneResInst(cJSON *instItem, const char *resName) +{ + cJSON *nodeJson = cJSON_GetObjectItem(instItem, INST_NODE_ID); + CM_RETERR_IF_FALSE(CmCheckIsJsonNumber(nodeJson, resName, "one instance node_id", ERROR)); + if (!IsNodeIdValid(nodeJson->valueint)) { + PrintCheckJsonInfo(ERROR, "resource(%s)'s one instance node_id(%d) is invalid.\n", resName, nodeJson->valueint); + return CM_ERROR; + } + + cJSON *resInstValue = cJSON_GetObjectItem(instItem, INST_RES_INST_ID); + (void)CmCheckIsJsonNumber(resInstValue, resName, "one instance res_instance_id", WARNING); + + resInstValue = cJSON_GetObjectItem(instItem, "res_args"); + (void)CmCheckIsJsonString(resInstValue, resName, "one instance res_args", WARNING); + + return CM_SUCCESS; +} + +static status_t CheckAllResInst(cJSON *instArray, const char *resName) +{ + cJSON *instItem; + cJSON_ArrayForEach(instItem, instArray) { + CM_RETURN_IFERR(CheckOneResInst(instItem, resName)); + } + + return CM_SUCCESS; +} + +static status_t CheckResNumberOptInfo(cJSON *resItem, const char *resName, const char *checkKey) +{ + cJSON *objValue = cJSON_GetObjectItem(resItem, checkKey); + CM_RETERR_IF_FALSE(CmCheckIsJsonNumber(objValue, resName, checkKey, WARNING)); + if (!IsResConfValid(checkKey, objValue->valueint)) { + PrintCheckJsonInfo(WARNING, "resource(%s)'s %s=%d out of range, range[%u %u], default(%s).\n", + resName, checkKey, objValue->valueint, + ResConfMinValue(checkKey), ResConfMaxValue(checkKey), ResConfDefValue(checkKey)); + return CM_ERROR; + } + + return CM_SUCCESS; +} + +static bool ParseIsCritical(cJSON *objValue) +{ + if (cJSON_IsBool(objValue)) { + return (bool)cJSON_IsTrue(objValue); + } + + if (cJSON_IsString(objValue) && CheckBoolConfigParam(objValue->valuestring)) { + return IsBoolCmParamTrue(objValue->valuestring); + } + + return true; +} + +static void CheckLocationAttrFormat(const char *resName, const char *attr) +{ + int paramLen = 0; + int valueLen = 0; + int flagCount = 0; + for (uint32 i = 0; i < strlen(attr); ++i) { + if (attr[i] == ':') { + ++flagCount; + continue; + } + + if (flagCount == 0) { + ++paramLen; + } + if (flagCount == 1) { + ++valueLen; + } + if (flagCount > 1) { + break; + } + } + + if (flagCount == 0) { + PrintCheckJsonInfo(WARNING, "resource(%s)'s location_attr(%s) format wrong, have no \':\'.\n", + resName, attr); + return; + } + if (flagCount > 1) { + PrintCheckJsonInfo(WARNING, "resource(%s)'s location_attr(%s) format wrong, more than one \':\'.\n", + resName, attr); + return; + } + + if (paramLen == 0) { + PrintCheckJsonInfo(WARNING, "resource(%s)'s location_attr(%s) format wrong, have no parameter.\n", + resName, attr); + } + if (valueLen == 0) { + PrintCheckJsonInfo(WARNING, "resource(%s)'s location_attr(%s) format wrong, have no right value.\n", + resName, attr); + } +} + +static void CheckResLocalOptInfo(cJSON *resItem, const char *resName) +{ + char localType[NAMEDATALEN] = {0}; + cJSON *objType = cJSON_GetObjectItem(resItem, "location_type"); + if (CmCheckIsJsonString(objType, resName, "location_type", WARNING)) { + errno_t rc = strcpy_s(localType, NAMEDATALEN, objType->valuestring); + securec_check_errno(rc, (void)rc); + } else { + cJSON *objValue = cJSON_GetObjectItem(resItem, "is_critical"); + (void)CmCheckIsJsonBool(objValue, resName, "is_critical", WARNING); + return; + } + + if (strcasecmp(localType, "local") != 0 && strcasecmp(localType, "any_one") != 0 && + strcasecmp(localType, "qualified_one") != 0) { + PrintCheckJsonInfo(WARNING, "resource(%s)'s location_type=\"%s\" not in (local/any_one/qualified_one), " + "default(%s).\n", resName, localType, ResConfDefValue("location_type")); + } + + cJSON *objValue = cJSON_GetObjectItem(resItem, "is_critical"); + bool isCritical = IsBoolCmParamTrue(ResConfDefValue("is_critical")); + if (CmCheckIsJsonBool(objValue, resName, "is_critical", WARNING)) { + isCritical = ParseIsCritical(objValue); + } + + if (isCritical && (strcasecmp(localType, "any_one") == 0 || strcasecmp(localType, "qualified_one") == 0)) { + PrintCheckJsonInfo(WARNING, "resource(%s)'s location_type is %s, is_critical must be false.\n", + resName, localType); + } + + if (strcasecmp(localType, "qualified_one") == 0) { + cJSON *objAttr = cJSON_GetObjectItem(resItem, "location_attr"); + if (CmCheckIsJsonString(objType, resName, "location_attr", WARNING)) { + CheckLocationAttrFormat(resName, objAttr->valuestring); + } + } +} + +static status_t CheckAppDnCommResInfo(cJSON *resItem, const char *resName) +{ + cJSON *objValue = cJSON_GetObjectItem(resItem, "script"); + CM_RETERR_IF_FALSE(CmCheckIsJsonString(objValue, resName, "script", ERROR)); + + (void)CheckResNumberOptInfo(resItem, resName, "check_interval"); + (void)CheckResNumberOptInfo(resItem, resName, "time_out"); + (void)CheckResNumberOptInfo(resItem, resName, "restart_delay"); + (void)CheckResNumberOptInfo(resItem, resName, "restart_period"); + (void)CheckResNumberOptInfo(resItem, resName, "restart_times"); + + CheckResLocalOptInfo(resItem, resName); + + return CM_SUCCESS; +} + +static status_t CheckAppResInfo(cJSON *resItem, const char *resName) +{ + cJSON *instArray = cJSON_GetObjectItem(resItem, INSTANCES); + if (!cJSON_IsArray(instArray)) { + PrintCheckJsonInfo(ERROR, "resource(%s)'s resource_type is APP, but instance array not configured.\n", resName); + return CM_ERROR; + } + if (cJSON_GetArraySize(instArray) == 0) { + PrintCheckJsonInfo(ERROR, "resource(%s)'s resource_type is APP, but instance array is empty.\n", resName); + return CM_ERROR; + } + + CM_RETURN_IFERR(CheckAllResInst(instArray, resName)); + + return CheckAppDnCommResInfo(resItem, resName); +} + +static status_t CheckDnResInfo(cJSON *resItem, const char *resName) +{ + cJSON *instArray = cJSON_GetObjectItem(resItem, INSTANCES); + if (cJSON_IsArray(instArray)) { + CM_RETURN_IFERR(CheckAllResInst(instArray, resName)); + } + return CheckAppDnCommResInfo(resItem, resName); +} + +static bool8 IsKeyInInstAttr(const char *key) +{ + if (CM_IS_EMPTY_STR(key)) { + return CM_FALSE; + } + + uint32 len = ELEMENT_COUNT(g_instAttrMap); + for (uint32 i = 0; i < len; ++i) { + if (cm_str_equal(key, g_instAttrMap[i])) { + return CM_TRUE; + } + } + return CM_FALSE; +} + +static status_t GetExpIpFromJson(cJSON *resItem, const char *key, const char *resName, char *ip, uint32 ipLen) +{ + bool8 isInInstAttr = IsKeyInInstAttr(key); + const char *trueKey = isInInstAttr ? INST_ATTR : key; + cJSON *objValue = cJSON_GetObjectItem(resItem, trueKey); + CM_RETERR_IF_FALSE(CmCheckIsJsonString(objValue, resName, trueKey, ERROR)); + + if (!isInInstAttr) { + check_input_for_security(objValue->valuestring); + errno_t rc = strcpy_s(ip, ipLen, objValue->valuestring); + securec_check_errno(rc, (void)rc); + return CM_SUCCESS; + } + + char *point = strstr(objValue->valuestring, key); + if (point == NULL) { + write_runlog(ERROR, "Res(%s) cannot find %s from %s.\n", resName, key, INST_ATTR); + return CM_ERROR; + } + char tmpIp[MAX_PATH_LEN] = {0}; + if (FetchStrFromText(point, tmpIp, MAX_PATH_LEN, KEY_VALUE_SPLIT_CHAR) != 0) { + write_runlog(ERROR, "Res(%s) cannot find [%s] from [%s] with the key[%s].\n", + resName, key, objValue->valuestring, INST_ATTR); + return CM_ERROR; + } + check_input_for_security(tmpIp); + errno_t rc = strncpy_s(ip, ipLen, tmpIp, ipLen - 1); + securec_check_errno(rc, (void)rc); + return CM_SUCCESS; +} + +static status_t CheckIpValidInJson(cJSON *resItem, const char *key, const char *resName, char *ip, uint32 ipLen) +{ + CM_RETURN_IFERR(GetExpIpFromJson(resItem, key, resName, ip, ipLen)); + if (CheckIpValid(ip) == CM_FALSE) { + PrintCheckJsonInfo(ERROR, "resource(%s)'s %s is an invalid ip.\n", resName, key); + return CM_ERROR; + } + return CM_SUCCESS; +} + +static status_t CheckAndGetNumberFromJson(cJSON *resItem, const char *resName, const char *checkKey, int32 *value) +{ + cJSON *objValue = cJSON_GetObjectItem(resItem, checkKey); + CM_RETERR_IF_FALSE(CmCheckIsJsonNumber(objValue, resName, checkKey, ERROR)); + + if (!IsResConfValid(checkKey, objValue->valueint)) { + PrintCheckJsonInfo(ERROR, "resource(%s)'s %s=%d out of range, range[%u %u].\n", resName, checkKey, + objValue->valueint, ResConfMinValue(checkKey), ResConfMaxValue(checkKey)); + return CM_ERROR; + } + if (value != NULL) { + *value = objValue->valueint; + } + return CM_SUCCESS; +} + +static status_t CheckFloatIPResInfo( + const char *resName, FloatIpResInfo *info, int32 maxLen, int32 *index, const FloatIpResInfo *curInfo) +{ + int32 point = *index; + if (point >= maxLen) { + PrintCheckJsonInfo(ERROR, "resource(%s)'s point(%d) has more then MaxLen(%d).\n", resName, point, maxLen); + return CM_ERROR; + } + + // instance_id + for (int32 i = 0; i < point; ++i) { + if (curInfo->instId == info[i].instId) { + PrintCheckJsonInfo(ERROR, + "resource(%s)'s FloatIp base_ip_list instance_id(%d) may be repeated.\n", resName, curInfo->instId); + return CM_ERROR; + } + } + + // base_ip + for (int32 i = 0; i < point; ++i) { + if (strcmp(curInfo->ip, info[i].ip) == 0) { + PrintCheckJsonInfo(ERROR, + "resource(%s)'s FloatIp base_ip_list base_ip(%s) may be repeated.\n", resName, curInfo->ip); + return CM_ERROR; + } + } + + info[point].instId = curInfo->instId; + errno_t rc = strcpy_s(info[point].ip, CM_IP_LENGTH, curInfo->ip); + securec_check_errno(rc, (void)rc); + ++(*index); + return CM_SUCCESS; +} + +static status_t CheckVipResInfo(cJSON *resItem, const char *resName) +{ + // instances + cJSON *instArray = cJSON_GetObjectItem(resItem, INSTANCES); + if (!cJSON_IsArray(instArray)) { + PrintCheckJsonInfo(ERROR, "resource(%s)'s resource_type is VIP, but base_ip_list not configured.\n", resName); + return CM_ERROR; + } + FloatIpResInfo info[CM_PRIMARY_STANDBY_MAX_NUM + 1] = {{{0}}}; + int32 arrSize = cJSON_GetArraySize(instArray); + if (arrSize < 0 || arrSize > CM_PRIMARY_STANDBY_MAX_NUM) { + PrintCheckJsonInfo(ERROR, + "resource(%s)'s base_ip_list size(%d) must in [0: %d].\n", resName, arrSize, CM_PRIMARY_STANDBY_MAX_NUM); + return CM_ERROR; + } + // float_ip + CM_RETURN_IFERR(CheckIpValidInJson(resItem, "float_ip", resName, info[0].ip, CM_IP_LENGTH)); + FloatIpResInfo curInfo = {0}; + cJSON *instItem; + int32 index = 1; + cJSON_ArrayForEach(instItem, instArray) { + // res_instance_id + CM_RETURN_IFERR(CheckAndGetNumberFromJson(instItem, resName, INST_RES_INST_ID, &(curInfo.instId))); + // base_ip + CM_RETURN_IFERR(CheckIpValidInJson(instItem, g_instAttrMap[0], resName, curInfo.ip, CM_IP_LENGTH)); + + CM_RETURN_IFERR(CheckFloatIPResInfo(resName, info, CM_PRIMARY_STANDBY_MAX_NUM + 1, &index, &curInfo)); + } + return CM_SUCCESS; +} + +static status_t CheckResName( + const cJSON *resItem, char (*resName)[CM_MAX_RES_NAME], uint32 maxCnt, uint32 *curCnt, const char **curResName) +{ + cJSON *objName = cJSON_GetObjectItem(resItem, RES_NAME); + CM_RETERR_IF_FALSE(CmCheckIsJsonString(objName, "", RES_NAME, ERROR)); + + if (strlen(objName->valuestring) >= CM_MAX_RES_NAME) { + PrintCheckJsonInfo(ERROR, "resource's name(%s) length exceeds the maximum(%d).\n", + objName->valuestring, CM_MAX_RES_NAME); + return CM_ERROR; + } + uint32 resNameCount = *curCnt; + if (resNameCount >= maxCnt) { + PrintCheckJsonInfo(ERROR, "resource count exceeds the maximum(%u).\n", maxCnt); + return CM_ERROR; + } + errno_t rc = strcpy_s(resName[resNameCount], CM_MAX_RES_NAME, objName->valuestring); + securec_check_errno(rc, (void)rc); + *curResName = resName[resNameCount]; + for (uint32 i = 0; i < resNameCount; i++) { + if (strcmp(resName[resNameCount], resName[i]) == 0) { + PrintCheckJsonInfo(ERROR, "resource(%s)'s configure repeated.\n", objName->valuestring); + return CM_ERROR; + } + } + ++(*curCnt); + return CM_SUCCESS; +} + +static void GetAllRestypeStr(char *typeStr, uint32 maxlen) +{ + errno_t rc; + uint32 arrLen = (uint32)(sizeof(g_resTypeMap) / sizeof(g_resTypeMap[0])); + char tmpStr[MAX_PATH_LEN] = {0}; + for (uint32 i = 0; i < arrLen; ++i) { + if (g_resTypeMap[i].type == RES_TYPE_UNKNOWN) { + continue; + } + if (strlen(typeStr) + strlen(g_resTypeMap[i].typeStr) >= maxlen) { + return; + } + if (i == 0) { + rc = snprintf_s(tmpStr, MAX_PATH_LEN, MAX_PATH_LEN - 1, "\"%s\"", g_resTypeMap[i].typeStr); + } else { + rc = snprintf_s(tmpStr, MAX_PATH_LEN, MAX_PATH_LEN - 1, ", \"%s\"", g_resTypeMap[i].typeStr); + } + securec_check_intval(rc, (void)rc); + rc = strcat_s(typeStr, maxlen, tmpStr); + securec_check_errno(rc, (void)rc); + } +} + +bool CompareResType(const char *value, uint32 *index) +{ + if (value == NULL) { + write_runlog(ERROR, "value is NULL.\n"); + return false; + } + char resTypeStr[MAX_PATH_LEN] = {0}; + errno_t rc; + uint32 arrLen = (uint32)(sizeof(g_resTypeMap) / sizeof(g_resTypeMap[0])); + char tmpStr[MAX_PATH_LEN] = {0}; + for (uint32 i = 0; i < arrLen; ++i) { + if (g_resTypeMap[i].typeStr == NULL) { + continue; + } + if (cm_str_equal(value, g_resTypeMap[i].typeStr)) { + *index = i; + return true; + } + if (i == 0) { + rc = snprintf_s( + tmpStr, MAX_PATH_LEN, MAX_PATH_LEN - 1, "%s-%s", g_resTypeMap[i].typeStr, g_resTypeMap[i].value); + } else { + rc = snprintf_s( + tmpStr, MAX_PATH_LEN, MAX_PATH_LEN - 1, ", %s-%s", g_resTypeMap[i].typeStr, g_resTypeMap[i].value); + } + securec_check_intval(rc, (void)rc); + rc = strcat_s(resTypeStr, MAX_PATH_LEN, tmpStr); + securec_check_errno(rc, (void)rc); + } + write_runlog(DEBUG1, "cannot find resType%s in g_resTypeMap%s.\n", value, resTypeStr); + return false; +} + +static uint32 GetResTypeIndex(cJSON *resItem, const char *resName) +{ + cJSON *objValue = cJSON_GetObjectItem(resItem, RESOURCE_TYPE); + if (!CmCheckIsJsonString(objValue, resName, RESOURCE_TYPE, WARNING)) { + return 0; + } + + uint32 index = 0; + if (CompareResType(objValue->valuestring, &index)) { + return index; + } + char allResName[MAX_PATH_LEN] = {0}; + GetAllRestypeStr(allResName, MAX_PATH_LEN); + PrintCheckJsonInfo(WARNING, "resource(%s)'s resources_type is (%s), not in range(%s), default(%s).\n", + resName, objValue->string, allResName, ResConfDefValue(RESOURCE_TYPE)); + return 0; +} + +ResType GetResTypeFromCjson(cJSON *resItem) +{ + const char *resType = GetValueStrFromCJson(resItem, RESOURCE_TYPE); + if (resType == NULL) { + resType = ResConfDefValue(RESOURCE_TYPE); + } + if (CM_IS_EMPTY_STR(resType)) { + return RES_TYPE_UNKNOWN; + } + for (uint32 i = 0; i < (uint32)RES_TYPE_CEIL; ++i) { + if (g_resTypeMap[i].typeStr == NULL) { + continue; + } + if (g_resTypeMap[i].type == RES_TYPE_UNKNOWN) { + continue; + } + if (cm_str_equal(g_resTypeMap[i].typeStr, resType)) { + return g_resTypeMap[i].type; + } + } + return RES_TYPE_UNKNOWN; +} + +static CheckResInfo GetResCheckFunc(uint32 curIndex) +{ + if (curIndex >= (uint32)RES_TYPE_CEIL) { + return NULL; + } + return g_resTypeMap[curIndex].check; +} + +status_t CheckResFromArray(cJSON *resArray) +{ + cJSON *resItem; + const uint32 maxResCnt = CM_MAX_RES_COUNT + CM_MAX_VIP_COUNT; + char resName[maxResCnt][CM_MAX_RES_NAME]; + uint32 resNameCount = 0; + + cJSON_ArrayForEach(resItem, resArray) { + const char *curResName; + + CM_RETURN_IFERR(CheckResName(resItem, resName, maxResCnt, &resNameCount, &curResName)); + + CheckResInfo check = GetResCheckFunc(GetResTypeIndex(resItem, curResName)); + // resource may not be checked. + if (check != NULL) { + CM_RETURN_IFERR(check(resItem, curResName)); + } + } + return CM_SUCCESS; +} + +static status_t GetLocalJsonMd5(const char *jsonFile, char *result, uint32 resultLen) +{ + char localMd5Cmd[MAX_PATH_LEN] = {0}; + int ret = sprintf_s(localMd5Cmd, MAX_PATH_LEN, "md5sum -t %s | awk '{print $1}'", jsonFile); + securec_check_intval(ret, (void)ret); + FILE *fp = popen(localMd5Cmd, "r"); + if (fp == NULL) { + PrintCheckJsonInfo(ERROR, "execute command:\"md5sum %s\" failed.\n", jsonFile); + return CM_ERROR; + } + if (fgets(result, ((int32)resultLen) - 1, fp) == NULL) { + (void)pclose(fp); + PrintCheckJsonInfo(ERROR, "can't get local md5sum of %s.\n", jsonFile); + return CM_ERROR; + } + + (void)pclose(fp); + return CM_SUCCESS; +} + +status_t CheckRemoteJson(const char *jsonFile) +{ + char localMd5[NAMEDATALEN] = {0}; + CM_RETURN_IFERR(GetLocalJsonMd5(jsonFile, localMd5, NAMEDATALEN)); + + char remoteMd5Cmd[MAX_PATH_LEN]; + int ret = sprintf_s(remoteMd5Cmd, MAX_PATH_LEN, "md5sum -t %s | grep -w %s", jsonFile, localMd5); + securec_check_intval(ret, (void)ret); + + status_t result = CM_SUCCESS; + for (uint32 i = 0; i < g_node_num; ++i) { + if (g_node[i].node == g_currentNode->node) { + continue; + } + if (ssh_exec(&g_node[i], remoteMd5Cmd, DEBUG1) != 0) { + PrintCheckJsonInfo(ERROR, "node(%u)'s cm_resource.json not same with local, please check ip(%s)'s json.\n", + g_node[i].node, g_node[i].sshChannel[0]); + result = CM_ERROR; + } + } + + return result; +} + +void InitResTypeMap() +{ + errno_t rc = memset_s(g_resTypeMap, sizeof(g_resTypeMap), 0, sizeof(g_resTypeMap)); + securec_check_errno(rc, (void)rc); + g_resTypeMap[RES_TYPE_UNKNOWN].type = RES_TYPE_UNKNOWN; + g_resTypeMap[RES_TYPE_UNKNOWN].typeStr = "APP"; + g_resTypeMap[RES_TYPE_UNKNOWN].value = INSTANCES; + g_resTypeMap[RES_TYPE_UNKNOWN].check = CheckAppResInfo; + + g_resTypeMap[RES_TYPE_APP].type = RES_TYPE_APP; + g_resTypeMap[RES_TYPE_APP].typeStr = "APP"; + g_resTypeMap[RES_TYPE_APP].value = INSTANCES; + g_resTypeMap[RES_TYPE_APP].check = CheckAppResInfo; + + g_resTypeMap[RES_TYPE_DN].type = RES_TYPE_DN; + g_resTypeMap[RES_TYPE_DN].typeStr = "DN"; + g_resTypeMap[RES_TYPE_DN].value = NULL; + g_resTypeMap[RES_TYPE_DN].check = CheckDnResInfo; + + g_resTypeMap[RES_TYPE_VIP].type = RES_TYPE_VIP; + g_resTypeMap[RES_TYPE_VIP].typeStr = "VIP"; + g_resTypeMap[RES_TYPE_VIP].value = INSTANCES; + g_resTypeMap[RES_TYPE_VIP].check = CheckVipResInfo; +} + +bool8 IsResCheckInstances(ResType resType) +{ + uint32 len = ELEMENT_COUNT(g_resTypeMap); + for (uint32 i = 0; i < len; ++i) { + if (resType == g_resTypeMap[i].type && g_resTypeMap[i].value != NULL) { + return CM_TRUE; + } + } + return CM_FALSE; +} + +bool8 IsCurNotCheckInstances(const ResOption *resCtx, const cJSON *resObj) +{ + ResType type = GetResTypeInJson(resCtx, resObj); + uint32 len = ELEMENT_COUNT(g_resTypeMap); + for (uint32 i = 0; i < len; ++i) { + if (type == g_resTypeMap[i].type && g_resTypeMap[i].value == NULL) { + return CM_TRUE; + } + } + return CM_FALSE; +} + +const char *GetResTypeValue(uint32 index) +{ + return g_resTypeMap[index].value; +} diff --git a/src/cm_ctl/ctl_res_list.cpp b/src/cm_ctl/ctl_res_list.cpp new file mode 100644 index 0000000..f6d67d3 --- /dev/null +++ b/src/cm_ctl/ctl_res_list.cpp @@ -0,0 +1,857 @@ +/* +* 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. +* ------------------------------------------------------------------------- +* +* ctl_res_list.cpp +* +* IDENTIFICATION +* src/cm_ctl/ctl_res_list.cpp +* +* ------------------------------------------------------------------------- +*/ +#include "ctl_res_list.h" + +#include "cjson/cJSON.h" + +#include "cm_text.h" +#include "cm_elog.h" +#include "cm_misc_res.h" +#include "cm_misc.h" + +#include "ctl_global_params.h" +#include "ctl_res.h" + +typedef struct ResBaseInfoT { + CmConstText resName; + CmConstText resType; +} ResBaseInfo; + +typedef struct PrintArrayT { + const char **arr; + uint32 arrLen; +} PrintArray; + +typedef struct ResPrintInfoT { + PrintArray resArr; + PrintArray instArr; +} ResPrintInfo; + +typedef struct ResValueInfoT { + char *attrChar; + uint32 attrValue; + uint32 len; + uint32 value[0]; +} ResValueInfo; + +// for str '\0' +static const uint32 TEXT_RESERVE_LEN = 10; + +static const char *const PRINT_TABLE_SPEPARATOR = "-"; +static const char *const PRINT_TABLE_SPLIT = "| "; +static const char *const PRINT_NULL = "Null"; + +static const uint32 LIST_RES_SPACE_LEN = 1; +static const int32 TEN_MECHAN = 10; + +static const char *g_resCom[] = {RES_NAME, RESOURCE_TYPE}; + +static const char *g_appResArr[] = { + RES_SCRIPT, RES_CHECK_INTERVAL, RES_TIMEOUT, RES_RESTART_DELAY, RES_PERIOD, RES_RESTART_TIMES}; + +static const char *g_appInstArr[] = {INST_NODE_ID, INST_RES_INST_ID, INST_REG}; + +// VIP +static const char *g_vipResArr[] = {RES_FLOAT_IP}; +static const char *g_vipInstArr[] = {INST_NODE_ID, INST_RES_INST_ID, INST_ATTR}; + +static const char *g_resAttr[] = {RES_FLOAT_IP, INST_ATTR}; + +static const char *g_resSkipAttr[] = {RES_ATTR, INST_ATTR}; + +static ResPrintInfo g_printInfo[RES_TYPE_CEIL]; + +static KvRestrict g_resAllKv[] = {{RES_KV_TYPE_STRING, RES_NAME}, + {RES_KV_TYPE_STRING, RESOURCE_TYPE}, + {RES_KV_TYPE_STRING, RES_SCRIPT}, + {RES_KV_TYPE_INTEGER, RES_CHECK_INTERVAL}, + {RES_KV_TYPE_INTEGER, RES_TIMEOUT}, + {RES_KV_TYPE_INTEGER, RES_RESTART_DELAY}, + {RES_KV_TYPE_INTEGER, RES_PERIOD}, + {RES_KV_TYPE_INTEGER, RES_RESTART_TIMES}, + {RES_KV_TYPE_INTEGER, INST_NODE_ID}, + {RES_KV_TYPE_INTEGER, INST_RES_INST_ID}, + {RES_KV_TYPE_STRING, RES_FLOAT_IP}, + {RES_KV_TYPE_STRING, INST_REG}, + {RES_KV_TYPE_STRING, INST_ATTR}, + {RES_KV_TYPE_STRING, RES_ATTR}}; + +static void PrintListTitle() +{ + (void)fprintf(g_logFilePtr, "\n[ CM Resource Info ]\n\n"); +} + +static bool8 IsInSkipAttr(const char *key) +{ + if (CM_IS_EMPTY_STR(key)) { + return CM_FALSE; + } + + uint32 len = ELEMENT_COUNT(g_resSkipAttr); + for (uint32 i = 0; i < len; ++i) { + if (cm_str_equal(g_resSkipAttr[i], key)) { + return CM_TRUE; + } + } + return CM_FALSE; +} + +static void InitResBaseInfo(ResBaseInfo *info) +{ + errno_t rc = memset_s(info, sizeof(ResBaseInfo), 0, sizeof(ResBaseInfo)); + securec_check_errno(rc, (void)rc); + + info->resName.str = RES_NAME; + info->resName.len = (uint32)strlen(RES_NAME); + + info->resType.str = RESOURCE_TYPE; + info->resType.len = (uint32)strlen(RESOURCE_TYPE); +} + +static status_t SetResBaseInfoInArray(ResBaseInfo *info, const cJSON *resArray, const ResOption *resCtx) +{ + const cJSON *item; + const char *resName; + const char *resType; + bool8 isCanPrint = CM_FALSE; + cJSON_ArrayForEach(item, resArray) { + if (!cJSON_IsObject(item)) { + continue; + } + resName = GetValueStrFromCJson(item, RES_NAME); + if (resName == NULL) { + resName = NULL; + } else { + isCanPrint = CM_TRUE; + } + info->resName.len = CM_MAX(info->resName.len, (uint32)strlen(resName)); + resType = GetValueStrFromCJson(item, RESOURCE_TYPE); + if (resType == NULL) { + resType = ResConfDefValue(RESOURCE_TYPE); + } + info->resType.len = CM_MAX(info->resType.len, (uint32)strlen(resType)); + } + // space + info->resName.len += LIST_RES_SPACE_LEN; + info->resType.len += LIST_RES_SPACE_LEN; + if (!isCanPrint) { + write_runlog(ERROR, "%s%s Res(%s) cannot print res info, when no res in json.\n", GetResOperStr(resCtx->mode), + GetInstOperStr(resCtx->inst.mode), resCtx->resName); + return CM_ERROR; + } + return CM_SUCCESS; +} + +static void PrintAllResInfoTitle(const ResBaseInfo *info) +{ + (void)fprintf(g_logFilePtr, "%-*s%s%-*s\n", + info->resName.len, info->resName.str, + PRINT_TABLE_SPLIT, + info->resType.len, info->resType.str); + + // --- + uint32 totalLen = info->resName.len + info->resType.len + (uint32)strlen(PRINT_TABLE_SPLIT); + for (uint32 i = 0; i < totalLen; ++i) { + (void)fprintf(g_logFilePtr, "%s", PRINT_TABLE_SPEPARATOR); + } + (void)fprintf(g_logFilePtr, "\n"); +} + +static void PrintAllResInfoBody(const ResBaseInfo *info, const cJSON *resArray) +{ + const cJSON *item; + const char *resName; + const char *resType; + cJSON_ArrayForEach(item, resArray) { + if (!cJSON_IsObject(item)) { + continue; + } + resName = GetValueStrFromCJson(item, RES_NAME); + if (resName == NULL) { + resName = NULL; + } + resType = GetValueStrFromCJson(item, RESOURCE_TYPE); + if (resType == NULL) { + resType = ResConfDefValue(RESOURCE_TYPE); + } + (void)fprintf(g_logFilePtr, "%-*s%s%-*s\n", + info->resName.len, resName, + PRINT_TABLE_SPLIT, + info->resType.len, resType); + } +} + +static bool8 IsInResArr(const char *key) +{ + if (key == NULL) { + return CM_FALSE; + } + uint32 len = ELEMENT_COUNT(g_resAttr); + for (uint32 i = 0; i < len; ++i) { + if (cm_str_equal(key, g_resAttr[i])) { + return CM_TRUE; + } + } + return CM_FALSE; +} + +static uint32 GetValueLen(int32 value, int32 mechan = TEN_MECHAN) +{ + if (mechan == 0) { + write_runlog(DEBUG1, "fail to get value len, whne mechan is 0.\n"); + return 0; + } + uint32 len = 0; + int32 tmpValue = value; + int32 tmpMechan = abs(mechan); + if (tmpValue < 0) { + // minus sign + tmpValue = abs(tmpValue); + len += 1; + } + + while (tmpValue != 0) { + tmpValue /= tmpMechan; + ++len; + } + return len; +} + +static status_t PrintAllResInfo(const cJSON *resArray, const ResOption *resCtx) +{ + PrintListTitle(); + ResBaseInfo info; + InitResBaseInfo(&info); + CM_RETURN_IFERR(SetResBaseInfoInArray(&info, resArray, resCtx)); + PrintAllResInfoTitle(&info); + PrintAllResInfoBody(&info, resArray); + return CM_SUCCESS; +} + +static status_t CheckListParam(cJSON *resArray, const ResOption *resCtx) +{ + if (resArray == NULL) { + write_runlog(ERROR, "%s%s Res(%s) cannot list res, when resArray is NULL.\n", GetResOperStr(resCtx->mode), + GetInstOperStr(resCtx->inst.mode), resCtx->resName); + return CM_ERROR; + } + return CM_SUCCESS; +} + +static void InitListFunc() +{ + errno_t rc = memset_s(g_printInfo, sizeof(g_printInfo), 0, sizeof(g_printInfo)); + securec_check_errno(rc, (void)rc); + + g_printInfo[RES_TYPE_APP].resArr.arr = g_appResArr; + g_printInfo[RES_TYPE_APP].resArr.arrLen = ELEMENT_COUNT(g_appResArr); + g_printInfo[RES_TYPE_APP].instArr.arr = g_appInstArr; + g_printInfo[RES_TYPE_APP].instArr.arrLen = ELEMENT_COUNT(g_appInstArr); + + g_printInfo[RES_TYPE_DN].resArr.arr = g_appResArr; + g_printInfo[RES_TYPE_DN].resArr.arrLen = ELEMENT_COUNT(g_appResArr); + + g_printInfo[RES_TYPE_VIP].resArr.arr = g_vipResArr; + g_printInfo[RES_TYPE_VIP].resArr.arrLen = ELEMENT_COUNT(g_vipResArr); + g_printInfo[RES_TYPE_VIP].instArr.arr = g_vipInstArr; + g_printInfo[RES_TYPE_VIP].instArr.arrLen = ELEMENT_COUNT(g_vipInstArr); +} + +static ResPrintInfo *GetPrintInfo(cJSON *objItem, const ResOption *resCtx) +{ + ResType type = GetResTypeFromCjson(objItem); + if (type == RES_TYPE_UNKNOWN) { + write_runlog(ERROR, "%s%s Res(%s) cannot get print Info, when type is %d.\n", + GetResOperStr(resCtx->mode), GetInstOperStr(resCtx->inst.mode), resCtx->resName, (int32)type); + return NULL; + } + + if (type >= RES_TYPE_CEIL) { + write_runlog(ERROR, "%s%s Res(%s) cannot get print Info, when type is %d.\n", + GetResOperStr(resCtx->mode), GetInstOperStr(resCtx->inst.mode), resCtx->resName, (int32)type); + return NULL; + } + return &(g_printInfo[type]); +} + +static ResValueInfo *InitValueArr(uint32 arrLen, const ResOption *resCtx) +{ + uint32 totalLen = arrLen + (uint32)ELEMENT_COUNT(g_resCom); + size_t totalsize = sizeof(ResValueInfo) + sizeof(uint32) * totalLen; + ResValueInfo *valueArr = (ResValueInfo *)malloc(totalsize); + if (valueArr == NULL) { + write_runlog(DEBUG1, "%s%s Res(%s) fails to print list info, when valueArr is NULL, and len=[%u: %zu].\n", + GetResOperStr(resCtx->mode), GetInstOperStr(resCtx->inst.mode), resCtx->resName, totalLen, totalsize); + write_runlog(ERROR, "%s%s Res(%s) fails to print list info, when valueArr is NULL.\n", + GetResOperStr(resCtx->mode), GetInstOperStr(resCtx->inst.mode), resCtx->resName); + return NULL; + } + errno_t rc = memset_s(valueArr, totalsize, 0, totalsize); + securec_check_errno(rc, (void)rc); + valueArr->len = totalLen; + return valueArr; +} + +static ResKvType GetCurKvType(const char *key) +{ + if (key == NULL) { + return RES_KV_TYPE_UNKNOWN; + } + uint32 len = ELEMENT_COUNT(g_resAllKv); + for (uint32 i = 0; i < len; ++i) { + if (cm_str_equal(g_resAllKv[i].key, key)) { + return g_resAllKv[i].type; + } + } + return RES_KV_TYPE_UNKNOWN; +} + +static int32 GetValueIntOrDefValueFromJson(const cJSON *root, const char *key) +{ + int32 value = GetValueIntFromCJson(root, key, DEBUG1); + if (value == -1) { + value = CmAtoi(ResConfDefValue(key), -1); + } + return value; +} + +static uint32 GetValueLenFromJson(const cJSON *root, const char *key) +{ + int32 value = GetValueIntOrDefValueFromJson(root, key); + return GetValueLen(value); +} + +static const char *GetValueStrOrDefValueFromJson(const cJSON *root, const char *key) +{ + const char *value = GetValueStrFromCJson(root, key, DEBUG1); + if (value == NULL) { + value = ResConfDefValue(key); + } + if (value == NULL) { + value = PRINT_NULL; + } + return value; +} + +static uint32 GetValueStrLenFromJson(const cJSON *root, const char *key) +{ + const char *value = GetValueStrOrDefValueFromJson(root, key); + if (value == NULL) { + return 0; + } + return (uint32)strlen(value); +} + +static uint32 GetCJsonItemLen(const cJSON *root, const char *key, const ResOption *resCtx) +{ + if (!cJSON_IsObject(root)) { + write_runlog(DEBUG1, "%s%s Res(%s) fails to get cJson item len, when root is not object.\n", + GetResOperStr(resCtx->mode), GetInstOperStr(resCtx->inst.mode), resCtx->resName); + return 0; + } + if (CM_IS_EMPTY_STR(key)) { + write_runlog(DEBUG1, "%s%s Res(%s) fails to get cJson item len, when key is empty.\n", + GetResOperStr(resCtx->mode), GetInstOperStr(resCtx->inst.mode), resCtx->resName); + return 0; + } + ResKvType type = GetCurKvType(key); + if (type == RES_KV_TYPE_UNKNOWN) { + write_runlog(DEBUG1, "%s%s Res(%s) fails to get cJson item len, when type is unknown.\n", + GetResOperStr(resCtx->mode), GetInstOperStr(resCtx->inst.mode), resCtx->resName); + return 0; + } + uint32 valueLen = 0; + switch (type) { + case RES_KV_TYPE_INTEGER: + valueLen = GetValueLenFromJson(root, key); + break; + case RES_KV_TYPE_STRING: + valueLen = GetValueStrLenFromJson(root, key); + break; + default:; + } + if (!IsInResArr(key)) { + return valueLen; + } + if (!IsInSkipAttr(key)) { + // "=" + const uint32 splitLen = 1; + return (uint32)strlen(key) + splitLen + valueLen; + } + return valueLen; +} + +static void InitArrItemLen( + ResValueInfo *valueArr, const PrintArray *printInfo, uint32 *index, const ResOption *resCtx, const char *attrName) +{ + uint32 tmpIndex = *index; + const char *key; + for (uint32 i = 0; i < printInfo->arrLen; ++i) { + if (tmpIndex + i >= valueArr->len) { + write_runlog(DEBUG1, "%s%s Res(%s) fails to init arr Item len, when tmpIndex=%u, i=%u, len=%u.\n", + GetResOperStr(resCtx->mode), GetInstOperStr(resCtx->inst.mode), resCtx->resName, tmpIndex, i, + valueArr->len); + break; + } + key = printInfo->arr[i]; + if (!IsInResArr(key)) { + valueArr->value[tmpIndex + i] = (uint32)strlen(key); + } else { + valueArr->attrValue = (uint32)strlen(attrName); + } + } + *index = tmpIndex + printInfo->arrLen; +} + +static void InitListArrItem(ResValueInfo *valueArr, const ResOption *resCtx, const PrintArray *printInfo) +{ + uint32 index = 0; + // g_resComm + PrintArray tmpArray = {.arr = g_resCom, .arrLen = ELEMENT_COUNT(g_resCom)}; + InitArrItemLen(valueArr, &tmpArray, &index, resCtx, INST_ATTR); + + // printInfo + InitArrItemLen(valueArr, printInfo, &index, resCtx, INST_ATTR); +} + +static void ComputeArrItemLen( + const cJSON *objItem, ResValueInfo *valueArr, uint32 *index, const PrintArray *printInfo, const ResOption *resCtx) +{ + uint32 tmpIndex = *index; + const char *key; + for (uint32 i = 0; i < printInfo->arrLen; ++i) { + if (tmpIndex + i >= valueArr->len) { + write_runlog(DEBUG1, "%s%s Res(%s) fails to compute arr Item len, when tmpIndex=%u, i=%u, len=%u.\n", + GetResOperStr(resCtx->mode), GetInstOperStr(resCtx->inst.mode), resCtx->resName, tmpIndex, i, + valueArr->len); + break; + } + key = printInfo->arr[i]; + if (!IsInResArr(key)) { + valueArr->value[tmpIndex + i] = + CM_MAX(GetCJsonItemLen(objItem, key, resCtx), valueArr->value[tmpIndex + i]); + } else { + if (valueArr->attrValue == 0) { + valueArr->attrValue += GetCJsonItemLen(objItem, key, resCtx); + } else { + // "," + valueArr->attrValue += GetCJsonItemLen(objItem, key, resCtx) + 1; + } + } + } + *index = tmpIndex + printInfo->arrLen; +} + +static void AddSplit(ResValueInfo *valueArr) +{ + // add split + for (uint32 i = 0; i < valueArr->len; ++i) { + if (valueArr->value[i] == 0) { + continue; + } + valueArr->value[i] += LIST_RES_SPACE_LEN; + } + if (valueArr->attrValue != 0) { + valueArr->attrValue += LIST_RES_SPACE_LEN; + } +} + +static status_t ComputeListTableItemLen( + const cJSON *objItem, const PrintArray *printInfo, ResValueInfo *valueArr, const ResOption *resCtx) +{ + // record attrValue + uint32 attrValue = valueArr->attrValue; + valueArr->attrValue = 0; + + // g_resComm + uint32 index = 0; + PrintArray tmpArray = {.arr = g_resCom, .arrLen = ELEMENT_COUNT(g_resCom)}; + ComputeArrItemLen(objItem, valueArr, &index, &tmpArray, resCtx); + + // printInfo + cJSON *objArray = cJSON_GetObjectItem(objItem, INSTANCES); + if (!cJSON_IsArray(objArray)) { + write_runlog(DEBUG1, "%s%s Res(%s) fails to compute cur table item len.\n", + GetResOperStr(resCtx->mode), GetInstOperStr(resCtx->inst.mode), resCtx->resName); + return CM_ERROR; + } + cJSON *item; + uint32 tmpAttrValue = valueArr->attrValue; + cJSON_ArrayForEach(item, objArray) { + if (!cJSON_IsObject(item)) { + continue; + } + attrValue = CM_MAX(valueArr->attrValue, attrValue); + valueArr->attrValue = tmpAttrValue; + ComputeArrItemLen(item, valueArr, &index, printInfo, resCtx); + } + valueArr->attrValue = CM_MAX(valueArr->attrValue, attrValue); + + AddSplit(valueArr); + return CM_SUCCESS; +} + +static void PrintTableTileItem( + const PrintArray *printInfo, ResValueInfo *valueArr, const ResOption *resCtx, uint32 *index, bool8 isFirst) +{ + uint32 tmpIndex = *index; + bool8 isTmpFirst = isFirst; + for (uint32 i = 0; i < printInfo->arrLen; ++i) { + if (tmpIndex + i >= valueArr->len) { + write_runlog(DEBUG1, "%s%s Res(%s) fails to print table title item, when tmpIndex=%u, i=%u, len=%u.\n", + GetResOperStr(resCtx->mode), GetInstOperStr(resCtx->inst.mode), resCtx->resName, tmpIndex, i, + valueArr->len); + break; + } + if (valueArr->value[tmpIndex + i] == 0) { + continue; + } + if (isTmpFirst) { + isTmpFirst = CM_FALSE; + (void)fprintf(g_logFilePtr, "%-*s", valueArr->value[tmpIndex + i], printInfo->arr[i]); + } else { + (void)fprintf(g_logFilePtr, "%s%-*s", PRINT_TABLE_SPLIT, valueArr->value[tmpIndex + i], printInfo->arr[i]); + } + } + *index = tmpIndex + printInfo->arrLen; +} + +static void PrintListTableTile( + const PrintArray *printInfo, ResValueInfo *valueArr, const ResOption *resCtx, const char *attrName) +{ + uint32 index = 0; + // g_resComm + PrintArray tmpArray = {.arr = g_resCom, .arrLen = ELEMENT_COUNT(g_resCom)}; + PrintTableTileItem(&tmpArray, valueArr, resCtx, &index, CM_TRUE); + + // prinfInfo + PrintTableTileItem(printInfo, valueArr, resCtx, &index, CM_FALSE); + + if (valueArr->attrValue != 0) { + (void)fprintf(g_logFilePtr, "%s%-*s", PRINT_TABLE_SPLIT, valueArr->attrValue, attrName); + } + (void)fprintf(g_logFilePtr, "\n"); +} + +static void PrintListTableSperatorBar(ResValueInfo *valueArr) +{ + uint32 totalLen = valueArr->attrValue; + uint32 trueCnt = 0; + if (totalLen != 0) { + ++trueCnt; + } + for (uint32 i = 0; i < valueArr->len; ++i) { + if (valueArr->value[i] == 0) { + continue; + } + totalLen += valueArr->value[i]; + ++trueCnt; + } + if (trueCnt >= 1) { + totalLen += (trueCnt - 1) * (uint32)strlen(PRINT_TABLE_SPLIT); + } + for (uint32 i = 0; i < totalLen; ++i) { + (void)fprintf(g_logFilePtr, "%s", PRINT_TABLE_SPEPARATOR); + } + (void)fprintf(g_logFilePtr, "\n"); +} + +static status_t PrintListTableInfo( + const cJSON *objItem, const PrintArray *printInfo, ResValueInfo *valueArr, const ResOption *resCtx) +{ + InitListArrItem(valueArr, resCtx, printInfo); + CM_RETURN_IFERR(ComputeListTableItemLen(objItem, printInfo, valueArr, resCtx)); + + PrintListTableTile(printInfo, valueArr, resCtx, INST_ATTR); + + PrintListTableSperatorBar(valueArr); + return CM_SUCCESS; +} + +static void PrintNameAndResType(const char *resName, const char *resType, ResValueInfo *valueArr) +{ + (void)fprintf(g_logFilePtr, "%-*s%s%-*s", valueArr->value[0], resName, PRINT_TABLE_SPLIT, valueArr->value[1], + resType); +} + +static void SetResAttrFromJson(const cJSON *root, const char *key, ResValueInfo *valueArr, const ResOption *resCtx) +{ + ResKvType type = GetCurKvType(key); + if (type == RES_KV_TYPE_UNKNOWN) { + write_runlog(DEBUG1, "%s%s Res(%s) fails to set res attr from json, when type is unknown.\n", + GetResOperStr(resCtx->mode), GetInstOperStr(resCtx->inst.mode), resCtx->resName); + return; + } + errno_t rc; + uint32 curLen = (uint32)strlen(valueArr->attrChar); + if (curLen != 0) { + rc = strcat_s(valueArr->attrChar, valueArr->attrValue, ","); + securec_check_errno(rc, (void)rc); + ++curLen; + } + + if (!IsInSkipAttr(key)) { + rc = snprintf_s(valueArr->attrChar + curLen, valueArr->attrValue - curLen, (valueArr->attrValue - curLen) - 1, + "%s=", key); + securec_check_intval(rc, (void)rc); + } + + curLen = (uint32)strlen(valueArr->attrChar); + switch (type) { + case RES_KV_TYPE_INTEGER: + rc = snprintf_s(valueArr->attrChar + curLen, valueArr->attrValue - curLen, + (valueArr->attrValue - curLen) - 1, "%d", GetValueIntOrDefValueFromJson(root, key)); + securec_check_intval(rc, (void)rc); + break; + case RES_KV_TYPE_STRING: + rc = snprintf_s(valueArr->attrChar + curLen, valueArr->attrValue - curLen, + (valueArr->attrValue - curLen) - 1, "%s", GetValueStrOrDefValueFromJson(root, key)); + securec_check_intval(rc, (void)rc); + break; + default:; + } + return; +} + +static void PrintInfoFromCjson(const cJSON *root, const char *key, uint32 len, const ResOption *resCtx) +{ + ResKvType type = GetCurKvType(key); + if (type == RES_KV_TYPE_UNKNOWN) { + write_runlog(DEBUG1, "%s%s Res(%s) fails to set res attr from json, when type is unknown.\n", + GetResOperStr(resCtx->mode), GetInstOperStr(resCtx->inst.mode), resCtx->resName); + return; + } + switch (type) { + case RES_KV_TYPE_INTEGER: + (void)fprintf(g_logFilePtr, "%s%-*d", PRINT_TABLE_SPLIT, len, GetValueIntOrDefValueFromJson(root, key)); + break; + case RES_KV_TYPE_STRING: + (void)fprintf(g_logFilePtr, "%s%-*s", PRINT_TABLE_SPLIT, len, GetValueStrOrDefValueFromJson(root, key)); + break; + default:; + } + return; +} + +static void PrintCJsonBody( + const cJSON *objItem, const PrintArray *printInfo, ResValueInfo *valueArr, const ResOption *resCtx) +{ + const char *key; + const uint32 otherIndex = 2; + for (uint32 i = 0; i < printInfo->arrLen; ++i) { + if (otherIndex + i >= valueArr->len) { + write_runlog(DEBUG1, "%s%s Res(%s) fails to print cjson body, when index=%u, i=%u, len=%u.\n", + GetResOperStr(resCtx->mode), GetInstOperStr(resCtx->inst.mode), resCtx->resName, otherIndex, i, + valueArr->len); + break; + } + key = printInfo->arr[i]; + if (IsInResArr(key)) { + SetResAttrFromJson(objItem, key, valueArr, resCtx); + } else { + PrintInfoFromCjson(objItem, key, valueArr->value[otherIndex + i], resCtx); + } + } + if (valueArr->attrValue != 0) { + (void)fprintf(g_logFilePtr, "%s%-*s", PRINT_TABLE_SPLIT, valueArr->attrValue, valueArr->attrChar); + } + (void)fprintf(g_logFilePtr, "\n"); +} + +static void SetAttrChar(ResValueInfo *valueArr) +{ + if (valueArr->attrValue == 0 || valueArr->attrChar == NULL) { + return; + } + errno_t rc = + memset_s(valueArr->attrChar, valueArr->attrValue + TEXT_RESERVE_LEN, 0, valueArr->attrValue + TEXT_RESERVE_LEN); + securec_check_errno(rc, (void)rc); +} + +static status_t InitAttrChar(ResValueInfo *valueArr, const ResOption *resCtx) +{ + if (valueArr->attrValue == 0) { + return CM_SUCCESS; + } + valueArr->attrChar = (char *)malloc(valueArr->attrValue + TEXT_RESERVE_LEN); + if (valueArr->attrChar == NULL) { + write_runlog(ERROR, "%s%s res(%s) fails to malloc attr char.\n", GetResOperStr(resCtx->mode), + GetInstOperStr(resCtx->inst.mode), resCtx->resName); + return CM_ERROR; + } + SetAttrChar(valueArr); + return CM_SUCCESS; +} + +static status_t PrintListTableBody( + const cJSON *objItem, const PrintArray *printInfo, ResValueInfo *valueArr, const ResOption *resCtx) +{ + const uint32 minValueLen = 2; + if (valueArr->value == NULL || valueArr->len < minValueLen) { + write_runlog(ERROR, "%s%s Res(%s) fails to print list table body, when value is NULL, or len=[%u: %u].\n", + GetResOperStr(resCtx->mode), GetInstOperStr(resCtx->inst.mode), resCtx->resName, valueArr->len, + minValueLen); + return CM_ERROR; + } + const char *resName = GetValueStrOrDefValueFromJson(objItem, RES_NAME); + const char *resType = GetValueStrOrDefValueFromJson(objItem, RESOURCE_TYPE); + cJSON *objArray = cJSON_GetObjectItem(objItem, INSTANCES); + if (!cJSON_IsArray(objArray)) { + write_runlog(DEBUG1, "%s%s Res(%s) fails to print list table body, when objArray is not array.\n", + GetResOperStr(resCtx->mode), GetInstOperStr(resCtx->inst.mode), resCtx->resName); + return CM_ERROR; + } + CM_RETURN_IFERR(InitAttrChar(valueArr, resCtx)); + cJSON *item; + cJSON_ArrayForEach(item, objArray) { + PrintNameAndResType(resName, resType, valueArr); + PrintCJsonBody(item, printInfo, valueArr, resCtx); + SetAttrChar(valueArr); + } + FREE_AND_RESET(valueArr->attrChar); + return CM_SUCCESS; +} + +static status_t PrintListInfo(const cJSON *objItem, const ResOption *resCtx, const PrintArray *printInfo) +{ + if (printInfo->arr == NULL || printInfo->arrLen == 0) { + return CM_SUCCESS; + } + PrintListTitle(); + ResValueInfo *valueArr = InitValueArr(printInfo->arrLen, resCtx); + CM_RETERR_IF_NULL(valueArr); + status_t st = CM_SUCCESS; + do { + st = PrintListTableInfo(objItem, printInfo, valueArr, resCtx); + CM_BREAK_IF_ERROR(st); + st = PrintListTableBody(objItem, printInfo, valueArr, resCtx); + CM_BREAK_IF_ERROR(st); + } while (0); + FREE_AND_RESET(valueArr); + return st; +} + +static void InitResArrItem(ResValueInfo *valueArr, const ResOption *resCtx, const PrintArray *printInfo) +{ + uint32 index = 0; + // g_resComm + PrintArray tmpArray = {.arr = g_resCom, .arrLen = ELEMENT_COUNT(g_resCom)}; + InitArrItemLen(valueArr, &tmpArray, &index, resCtx, RES_NAME); + + // printInfo + InitArrItemLen(valueArr, printInfo, &index, resCtx, RES_NAME); +} + +static void ComputeResTableItemLen( + const cJSON *objItem, const PrintArray *printInfo, ResValueInfo *valueArr, const ResOption *resCtx) +{ + // record attrValue + uint32 attrValue = valueArr->attrValue; + valueArr->attrValue = 0; + + // g_resComm + uint32 index = 0; + PrintArray tmpArray = {.arr = g_resCom, .arrLen = ELEMENT_COUNT(g_resCom)}; + ComputeArrItemLen(objItem, valueArr, &index, &tmpArray, resCtx); + + ComputeArrItemLen(objItem, valueArr, &index, printInfo, resCtx); + valueArr->attrValue = CM_MAX(valueArr->attrValue, attrValue); + + AddSplit(valueArr); +} + +static void PrintResTableInfo( + const cJSON *objItem, const PrintArray *printInfo, ResValueInfo *valueArr, const ResOption *resCtx) +{ + InitResArrItem(valueArr, resCtx, printInfo); + ComputeResTableItemLen(objItem, printInfo, valueArr, resCtx); + PrintListTableTile(printInfo, valueArr, resCtx, RES_ATTR); + + PrintListTableSperatorBar(valueArr); +} + +static status_t PrintResTableBody( + const cJSON *objItem, const PrintArray *printInfo, ResValueInfo *valueArr, const ResOption *resCtx) +{ + const uint32 minValueLen = 2; + if (valueArr->value == NULL || valueArr->len < minValueLen) { + write_runlog(ERROR, "%s%s Res(%s) fails to print res table body, when value is NULL, or len=[%u: %u].\n", + GetResOperStr(resCtx->mode), GetInstOperStr(resCtx->inst.mode), resCtx->resName, + valueArr->len, minValueLen); + return CM_ERROR; + } + const char *resName = GetValueStrOrDefValueFromJson(objItem, RES_NAME); + const char *resType = GetValueStrOrDefValueFromJson(objItem, RESOURCE_TYPE); + CM_RETURN_IFERR(InitAttrChar(valueArr, resCtx)); + PrintNameAndResType(resName, resType, valueArr); + PrintCJsonBody(objItem, printInfo, valueArr, resCtx); + FREE_AND_RESET(valueArr->attrChar); + return CM_SUCCESS; +} + +static status_t PrintResInfo(const cJSON *objItem, const ResOption *resCtx, const PrintArray *printInfo) +{ + if (printInfo->arr == NULL || printInfo->arrLen == 0) { + return CM_SUCCESS; + } + PrintListTitle(); + ResValueInfo *valueArr = InitValueArr(printInfo->arrLen, resCtx); + CM_RETERR_IF_NULL(valueArr); + status_t st = CM_SUCCESS; + do { + PrintResTableInfo(objItem, printInfo, valueArr, resCtx); + st = PrintResTableBody(objItem, printInfo, valueArr, resCtx); + CM_BREAK_IF_ERROR(st); + } while (0); + FREE_AND_RESET(valueArr); + return st; +} + +status_t ListResInJson(cJSON *resArray, const ResOption *resCtx) +{ + InitListFunc(); + CM_RETURN_IFERR(CheckListParam(resArray, resCtx)); + if (CM_IS_EMPTY_STR(resCtx->resName)) { + return PrintAllResInfo(resArray, resCtx); + } + cJSON *objItem = GetCurResInArray(resArray, resCtx->resName, resCtx); + if (objItem == NULL) { + write_runlog(ERROR, "%s%s cannot list Res, because can't find the res(%s) in json.\n", + GetResOperStr(resCtx->mode), GetInstOperStr(resCtx->inst.mode), resCtx->resName); + return CM_ERROR; + } + ResPrintInfo *printInfo = GetPrintInfo(objItem, resCtx); + if (printInfo == NULL) { + return CM_ERROR; + } + if (resCtx->inst.mode == RES_OP_LIST) { + return PrintListInfo(objItem, resCtx, &(printInfo->instArr)); + } + + if (resCtx->inst.mode != RES_OP_INIT) { + write_runlog(ERROR, "%s%s Res(%s) cannot list Res, because inst_mode(%u) may not be supported.\n", + GetResOperStr(resCtx->mode), GetInstOperStr(resCtx->inst.mode), resCtx->resName, (uint32)resCtx->inst.mode); + return CM_ERROR; + } + return PrintResInfo(objItem, resCtx, &(printInfo->resArr)); +} diff --git a/src/cm_ctl/ctl_show.cpp b/src/cm_ctl/ctl_show.cpp index 7e389c1..c76066c 100644 --- a/src/cm_ctl/ctl_show.cpp +++ b/src/cm_ctl/ctl_show.cpp @@ -21,21 +21,349 @@ * * ------------------------------------------------------------------------- */ -#include "cm/libpq-fe.h" -#include "ctl_common.h" + +#include "ctl_show.h" #include #include "c.h" +#include "cm_text.h" +#include "cm/libpq-fe.h" +#include "cm_msg_common.h" #include "cm_elog.h" #include "cm_rhb.h" #include "cm_voting_disk.h" +#include "cm_json_parse_floatIp.h" + +#include "ctl_global_params.h" +#include "ctl_misc.h" +#include "ctl_common.h" +#include "ctl_process_message.h" +#include "ctl_query_base.h" +#include "cm_misc_res.h" + +typedef struct CtlFloatIpInstT { + uint32 dnIdx; + DnFloatIp floatIp; +} CtlFloatIpInst; + +typedef struct CtlFloatIpNodeT { + uint32 nodeIdx; + uint32 instCnt; + CtlFloatIpInst floapIpInst[CM_MAX_DATANODE_PER_NODE]; +} CtlFloatIpNode; + +typedef struct CtlFloatIpMapT { + uint32 nodeCnt; + CtlFloatIpNode floatIpNode[0]; +} CtlFloatIpMap; + +typedef struct CtlFloatIpHeadSizeT { + CmConstText nodeText; + CmConstText instText; + CmConstText floatIpNameText; + CmConstText floatIpText; + CmConstText baseIpText; +} CtlFloatIpHeadSize; + +static ParseFloatIpFunc g_ctlParseFuc = {0}; +static CtlFloatIpMap *g_floatIpMap = NULL; +static uint32 g_floatIpCnt = 0; + +static void GetMaxFloatIpNameLen(CtlFloatIpHeadSize *floatIpLen) +{ + DnFloatIp *dnFloatIp; + uint32 len; + for (uint32 i = 0; i < g_floatIpMap->nodeCnt; ++i) { + for (uint32 j = 0; j < g_floatIpMap->floatIpNode[i].instCnt; ++j) { + for (uint32 k = 0; k < g_floatIpMap->floatIpNode[i].floapIpInst[j].floatIp.dnFloatIpCount; ++k) { + dnFloatIp = &(g_floatIpMap->floatIpNode[i].floapIpInst[j].floatIp); + // float_ip_name + len = (uint32)strlen(dnFloatIp->floatIpName[k]); + floatIpLen->floatIpNameText.len = CM_MAX(len, floatIpLen->floatIpNameText.len); + + // base_ip + len = (uint32)strlen(dnFloatIp->baseIp[i]); + floatIpLen->baseIpText.len = CM_MAX(len, floatIpLen->baseIpText.len); + + // float_ip + len = (uint32)strlen(dnFloatIp->dnFloatIp[i]); + floatIpLen->floatIpText.len = CM_MAX(len, floatIpLen->floatIpText.len); + } + } + } + floatIpLen->floatIpNameText.len += SPACE_LEN; + floatIpLen->baseIpText.len += SPACE_LEN; + floatIpLen->floatIpText.len += SPACE_LEN; +} + +static void CalcFloatIpHeaderSize(CtlFloatIpHeadSize *floatIpLen) +{ + // node + uint32 tmpNodeLen = (uint32)(MAX_NODE_ID_LEN + SPACE_LEN + max_node_name_len + SPACE_LEN); + floatIpLen->nodeText.len = CM_MAX(tmpNodeLen, floatIpLen->nodeText.len); + + // instance + uint32 tmpInstLen = (uint32)(INSTANCE_ID_LEN + SPACE_LEN + DEFAULT_PATH_LEN); + floatIpLen->instText.len = CM_MAX(tmpInstLen, floatIpLen->instText.len); + + GetMaxFloatIpNameLen(floatIpLen); +} + +static void PrintFloatIpHeaderLine(const CtlFloatIpHeadSize *floatIpLen) +{ + (void)fprintf(g_logFilePtr, "%-*s%-*s%-*s%-*s%-*s\n", + floatIpLen->nodeText.len, floatIpLen->nodeText.str, + floatIpLen->instText.len, floatIpLen->instText.str, + floatIpLen->baseIpText.len, floatIpLen->baseIpText.str, + floatIpLen->floatIpNameText.len, floatIpLen->floatIpNameText.str, + floatIpLen->floatIpText.len, floatIpLen->floatIpText.str); + uint32 totalLen = floatIpLen->nodeText.len + floatIpLen->instText.len + floatIpLen->baseIpText.len + + floatIpLen->floatIpNameText.len + floatIpLen->floatIpText.len; + for (uint32 i = 0; i < totalLen; ++i) { + (void)fprintf(g_logFilePtr, "-"); + } + if (totalLen != 0) { + (void)fprintf(g_logFilePtr, "\n"); + } +} + +static bool8 CheckFloatIpInput(uint32 nodeIdx, uint32 instIdx, uint32 ipIdx) +{ + if (g_floatIpMap == NULL) { + write_runlog(DEBUG1, "Failed to checkFloatIpInput, because g_floatIpMap is NULL.\n"); + return CM_FALSE; + } + if (nodeIdx >= g_floatIpMap->nodeCnt) { + write_runlog(DEBUG1, "Failed to checkFloatIpInput, because nodeIdx is [%u: %u].\n", + nodeIdx, g_floatIpMap->nodeCnt); + return CM_FALSE; + } + if (instIdx >= g_floatIpMap->floatIpNode[nodeIdx].instCnt) { + write_runlog(DEBUG1, "Failed to checkFloatIpInput, because instId is [%u: %u].\n", + instIdx, g_floatIpMap->floatIpNode[nodeIdx].instCnt); + return CM_FALSE; + } + if (ipIdx >= g_floatIpMap->floatIpNode[nodeIdx].floapIpInst[instIdx].floatIp.dnFloatIpCount) { + return CM_FALSE; + } + return CM_TRUE; +} + +static const char *GetBaseIp(uint32 nodeIdx, uint32 instIdx, uint32 ipIdx) +{ + if (!CheckFloatIpInput(nodeIdx, instIdx, ipIdx)) { + return "Unknown"; + } + return g_floatIpMap->floatIpNode[nodeIdx].floapIpInst[instIdx].floatIp.baseIp[ipIdx]; +} + +static const char *GetFloatIp(uint32 nodeIdx, uint32 instIdx, uint32 ipIdx) +{ + if (!CheckFloatIpInput(nodeIdx, instIdx, ipIdx)) { + return "Unknown"; + } + return g_floatIpMap->floatIpNode[nodeIdx].floapIpInst[instIdx].floatIp.dnFloatIp[ipIdx]; +} + +static const char *GetFloatIpName(uint32 nodeIdx, uint32 instIdx, uint32 ipIdx) +{ + if (!CheckFloatIpInput(nodeIdx, instIdx, ipIdx)) { + return "Unknown"; + } + return g_floatIpMap->floatIpNode[nodeIdx].floapIpInst[instIdx].floatIp.floatIpName[ipIdx]; +} + +static void PrintFloatIpContent(const CmFloatIpStatAck *ack, const CtlFloatIpHeadSize *floatIpLen) +{ + Instance inst; + errno_t rc; + for (uint32 i = 0; i < ack->count; ++i) { + rc = memset_s(&inst, sizeof(Instance), 0, sizeof(Instance)); + securec_check_errno(rc, (void)rc); + rc = FindInstanceByInstId(ack->info[i].instId, &inst); + if (rc != 0) { + continue; + } + for (uint32 j = 0; j < ack->info[i].count; ++j) { + if (ack->info[i].nicNetState[j] != (int32)NETWORK_STATE_UP) { + continue; + } + // node + (void)fprintf(g_logFilePtr, "%-2u ", g_node[inst.baseInfo.nodeIdx].node); + (void)fprintf(g_logFilePtr, "%-*s ", max_node_name_len, g_node[inst.baseInfo.nodeIdx].nodeName); + + // instance + (void)fprintf(g_logFilePtr, "%u ", ack->info[i].instId); + (void)fprintf(g_logFilePtr, " "); + + // base_ip + (void)fprintf(g_logFilePtr, "%-*s ", (floatIpLen->baseIpText.len - 1), + GetBaseIp(inst.baseInfo.nodeIdx, inst.baseInfo.instIdx, j)); + + // floatIpName + (void)fprintf(g_logFilePtr, "%-*s ", (floatIpLen->floatIpNameText.len - 1), + GetFloatIpName(inst.baseInfo.nodeIdx, inst.baseInfo.instIdx, j)); + + // floatIp + (void)fprintf(g_logFilePtr, "%-*s \n", (floatIpLen->floatIpText.len - 1), + GetFloatIp(inst.baseInfo.nodeIdx, inst.baseInfo.instIdx, j)); + } + } +} + +static void InitCtlFloatIpHeadSize(CtlFloatIpHeadSize *floatIpLen) +{ + errno_t rc = memset_s(floatIpLen, sizeof(CtlFloatIpHeadSize), 0, sizeof(CtlFloatIpHeadSize)); + securec_check_errno(rc, (void)rc); + + // node + CmConststr2Text("node", &(floatIpLen->nodeText)); + + // instance + CmConststr2Text("instance", &(floatIpLen->instText)); + + // baseIp + CmConststr2Text("base_ip", &(floatIpLen->baseIpText)); + + // floatIpName + CmConststr2Text("float_ip_name", &(floatIpLen->floatIpNameText)); + + // floatIp + CmConststr2Text("float_ip", &(floatIpLen->floatIpText)); +} + +status_t HandleFloatIpAck(const char *option, char *recvMsg) +{ + const CmFloatIpStatAck *ack = (const CmFloatIpStatAck *)recvMsg; + if (!ack->canShow) { + write_runlog(DEBUG1, "cur cluster can't show floatIp.\n"); + return CM_SUCCESS; + } + (void)fprintf(g_logFilePtr, "\n[ FloatIp Network State ]\n\n"); + if (ack->count == 0) { + return CM_ERROR; + } + CtlFloatIpHeadSize floatIpLen; + InitCtlFloatIpHeadSize(&floatIpLen); + CalcFloatIpHeaderSize(&floatIpLen); + PrintFloatIpHeaderLine(&floatIpLen); + PrintFloatIpContent(ack, &floatIpLen); + return CM_SUCCESS; +} + +static int32 InitFloatIpMap() +{ + size_t len = sizeof(CtlFloatIpMap) + sizeof(CtlFloatIpNode) * g_node_num; + g_floatIpMap = (CtlFloatIpMap *)malloc(len); + if (g_floatIpMap == NULL) { + write_runlog(DEBUG1, "failed to malloc g_floatIpMap, and len=%zu.\n", len); + return -1; + } + errno_t rc = memset_s(g_floatIpMap, len, 0, len); + securec_check_errno(rc, (void)rc); + g_floatIpMap->nodeCnt = g_node_num; + for (uint32 i = 0; i < g_node_num; ++i) { + g_floatIpMap->floatIpNode[i].nodeIdx = i; + for (uint32 j = 0; j < g_node[i].datanodeCount && j < CM_MAX_DATANODE_PER_NODE; ++j) { + g_floatIpMap->floatIpNode[i].floapIpInst[j].dnIdx = j; + } + } + return 0; +} + +static bool8 CtlFindNodeInfoByNodeIdx(uint32 instId, uint32 *nodeIdx, uint32 *dnIdx, const char *str) +{ + Instance instance; + errno_t rc = memset_s(&instance, sizeof(Instance), 0, sizeof(Instance)); + securec_check_errno(rc, (void)rc); + int32 ret = FindInstanceByInstId(instId, &instance); + if (ret != 0) { + write_runlog(DEBUG1, "[%s] cannot find the instance by instId(%u).\n", str, instId); + return CM_FALSE; + } + *nodeIdx = instance.baseInfo.nodeIdx; + *dnIdx = instance.baseInfo.instIdx; + return CM_TRUE; +} + +static DnFloatIp *CtlGetDnFloatIpByNodeInfo(uint32 nodeIdx, uint32 dnIdx) +{ + if (nodeIdx >= g_floatIpMap->nodeCnt || dnIdx >= CM_MAX_DATANODE_PER_NODE) { + write_runlog(DEBUG1, "failed to get Dn floatIp, because nodeIdx(%u) beyond the nodeNum(%u), " + "dnIdx(%u) beyond the dnNum(%d).\n", nodeIdx, g_floatIpMap->nodeCnt, dnIdx, CM_MAX_DATANODE_PER_NODE); + return NULL; + } + return &(g_floatIpMap->floatIpNode[nodeIdx].floapIpInst[dnIdx].floatIp); +} + +static void CtlIncreDnFloatIpCnt(uint32 nodeIdx) +{ + ++g_floatIpMap->floatIpNode[nodeIdx].instCnt; + ++g_floatIpCnt; +} + +static void CtlInitFloatIpFunc() +{ + g_ctlParseFuc.findNodeInfo = CtlFindNodeInfoByNodeIdx; + g_ctlParseFuc.getFloatIp = CtlGetDnFloatIpByNodeInfo; + g_ctlParseFuc.increaseCnt = CtlIncreDnFloatIpCnt; + InitParseFloatIpFunc(&g_ctlParseFuc); +} + +static int32 CtlParseFloatIp() +{ + CtlGetCmJsonConf(); + CM_RETURN_INT_IFERR(InitFloatIpMap()); + CtlInitFloatIpFunc(); + ParseVipConf(DEBUG1); + return 0; +} + +static void ReleaseFloatIp() +{ + FREE_AND_RESET(g_floatIpMap); + g_floatIpCnt = 0; +} + +static int32 SetQueryFloatIpMsg() +{ + CmShowStatReq req = { 0 }; + req.msgType = (int32)MSG_CTL_CM_FLOAT_IP_REQ; + if (cm_client_send_msg(GetCmsConn(), 'C', (char*)(&req), sizeof(CmShowStatReq)) != 0) { + FINISH_CONNECTION_WITHOUT_EXIT(); + write_runlog(ERROR, "ctl send show node disk msg to cms failed.\n"); + (void)printf(_("ctl send msg to cms failed.\n")); + return 1; + } + return 0; +} + +static int32 QueryCmsFloatIp() +{ + CM_RETURN_INT_IFERR(CtlParseFloatIp()); + if (g_floatIpCnt == 0) { + return 0; + } + CM_RETURN_INT_IFERR(SetQueryFloatIpMsg()); + if (GetExecCmdResult(NULL, (int)MSG_CTL_CM_FLOAT_IP_ACK) != CM_SUCCESS) { + return -1; + } + return 0; +} + +static int32 QueryCmsFloatIpMain() +{ + int32 ret = QueryCmsFloatIp(); + ReleaseFloatIp(); + return ret; +} -extern CM_Conn* CmServer_conn; // cm_ctl rhb print int DoShowCommand() { + InitCtlShowMsgFunc(); do_conn_cmserver(false, 0); if (CmServer_conn == NULL) { write_runlog(LOG, "show command, can't connect to cmserver.\n"); @@ -63,12 +391,19 @@ int DoShowCommand() } GetExecCmdResult(NULL, (int)MSG_CTL_CM_NODE_DISK_STATUS_ACK); + + if (QueryCmsFloatIpMain() != 0) { + FINISH_CONNECTION_WITHOUT_EXIT(); + write_runlog(ERROR, "Failed to show floatIp.\n"); + return -1; + } FINISH_CONNECTION_WITHOUT_EXIT(); return 0; } -void HandleRhbAck(CmRhbStatAck *ack) +status_t HandleRhbAck(const char *option, char *recvMsg) { + CmRhbStatAck *ack = (CmRhbStatAck *)recvMsg; (void)printf("\n[ Network Connect State ]\n\n"); (void)printf("Network timeout: %us\n", ack->timeout); @@ -82,9 +417,10 @@ void HandleRhbAck(CmRhbStatAck *ack) (void)printf("Network stat('Y' means connected, otherwise 'N'):\n"); char *rs = GetRhbSimple((time_t *)ack->hbs, MAX_RHB_NUM, ack->hwl, ack->baseTime, ack->timeout); - CM_RETURN_IF_NULL(rs); + CM_RETERR_IF_NULL(rs); (void)printf("%s\n", rs); - free(rs); + FREE_AND_RESET(rs); + return CM_SUCCESS; } // | Y | Y | Y | Y | Y | @@ -111,8 +447,9 @@ static char *GetNodeDiskSimple(time_t *ndHbs, uint32 hwl, time_t baseTime, uint3 return buf; } -void HandleNodeDiskAck(CmNodeDiskStatAck *ack) +status_t HandleNodeDiskAck(const char *option, char *recvMsg) { + CmNodeDiskStatAck *ack = (CmNodeDiskStatAck *)recvMsg; (void)printf("\n[ Node Disk HB State ]\n\n"); (void)printf("Node disk hb timeout: %us\n", ack->timeout); @@ -126,6 +463,8 @@ void HandleNodeDiskAck(CmNodeDiskStatAck *ack) (void)printf("Node disk hb stat('Y' means connected, otherwise 'N'):\n"); char *rs = GetNodeDiskSimple(ack->nodeDiskStats, ack->hwl, ack->baseTime, ack->timeout); + CM_RETERR_IF_NULL(rs); (void)printf("%s\n", rs); - free(rs); + FREE_AND_RESET(rs); + return CM_SUCCESS; } diff --git a/src/cm_server/cms_arbitrate_cluster.cpp b/src/cm_server/cms_arbitrate_cluster.cpp index 72bec1b..b9bdc95 100644 --- a/src/cm_server/cms_arbitrate_cluster.cpp +++ b/src/cm_server/cms_arbitrate_cluster.cpp @@ -478,7 +478,7 @@ static void PrintMaxNodeCluster(const MaxNodeCluster *maxNodeCluster, const char for (int32 i = 0; i < maxNodeCluster->nodeCluster.clusterNum; ++i) { StrcatNextNodeStr(clusterStr, MAX_PATH_LEN, maxNodeCluster->nodeCluster.cluster[i]); } - write_runlog(logLevel, "%s the max node cluster: %s.\n", str, clusterStr); + write_runlog(LOG, "%s the max node cluster: %s.\n", str, clusterStr); } static void GetClusterKeyInDdb(char *key, uint32 keyLen) diff --git a/src/cm_server/cms_arbitrate_datanode_pms.cpp b/src/cm_server/cms_arbitrate_datanode_pms.cpp index 1466842..5411235 100644 --- a/src/cm_server/cms_arbitrate_datanode_pms.cpp +++ b/src/cm_server/cms_arbitrate_datanode_pms.cpp @@ -1549,7 +1549,7 @@ static bool IsInstanceNoCmd(const DnArbCtx *ctx, const char *str) static void SendSwitchoverMessage(const DnArbCtx *ctx, int32 memIdx, const char *str) { - if (IsMaintenanceModeDisableOperation(CMS_SWITCHOVER_DN, ctx->maintaMode)) { + if (IsMaintenanceModeDisableOperation(CMS_SWITCHOVER_DN, ctx->maintaMode) || backup_open != CLUSTER_PRIMARY) { write_runlog(LOG, "%s, %u Maintaining cluster: cm server cannot switchover dn.\n", str, ctx->instId); return; } diff --git a/src/cm_server/cms_common.cpp b/src/cm_server/cms_common.cpp index f7f722d..dcfcb13 100644 --- a/src/cm_server/cms_common.cpp +++ b/src/cm_server/cms_common.cpp @@ -310,16 +310,6 @@ void get_paramter_coordinator_heartbeat_timeout() #endif -bool CheckBoolConfigParam(const char* value) -{ - if (strcasecmp(value, "on") == 0 || strcasecmp(value, "yes") == 0 || strcasecmp(value, "true") == 0 || - strcasecmp(value, "1") == 0 || strcasecmp(value, "off") == 0 || strcasecmp(value, "no") == 0 || - strcasecmp(value, "false") == 0 || strcasecmp(value, "0") == 0) { - return true; - } - return false; -} - void GetDdbTypeParam(void) { int32 ddbType = get_int_value_from_config(configDir, "ddb_type", 0); diff --git a/src/cm_server/cms_common_res.cpp b/src/cm_server/cms_common_res.cpp index 0ce7568..7982e97 100644 --- a/src/cm_server/cms_common_res.cpp +++ b/src/cm_server/cms_common_res.cpp @@ -285,6 +285,7 @@ void UpdateIsworkList(uint32 cmInstId, int newIswork) ++g_resStatus[i].status.version; ProcessReportResChangedMsg(false, g_resStatus[i].status); SaveOneResStatusToDdb(&g_resStatus[i].status); + PrintCusInfoResList(&g_resStatus[i].status, __FUNCTION__); return; } } @@ -530,27 +531,13 @@ void GetOneResStatusFromDdb(OneResStatList *resStat) cJSON_Delete(root); } -static inline void PrintNewResStatus(const OneResStatList *resStatus) -{ - write_runlog(LOG, "res(%s), version=%llu:\n", resStatus->resName, resStatus->version); - for (uint32 j = 0; j < resStatus->instanceCount; ++j) { - write_runlog(LOG, "nodeId=%u, cmInstId=%u, resInstId=%u, isWork=%u, status=%u;\n", - resStatus->resStat[j].nodeId, - resStatus->resStat[j].cmInstanceId, - resStatus->resStat[j].resInstanceId, - resStatus->resStat[j].isWorkMember, - resStatus->resStat[j].status); - } -} - void GetAllResStatusFromDdb() { for (uint32 i = 0; i < CusResCount(); ++i) { (void)pthread_rwlock_wrlock(&g_resStatus[i].rwlock); GetOneResStatusFromDdb(&g_resStatus[i].status); - write_runlog(LOG, "show res status get from ddb.\n"); - PrintNewResStatus(&g_resStatus[i].status); (void)pthread_rwlock_unlock(&g_resStatus[i].rwlock); + PrintCusInfoResList(&g_resStatus[i].status, __FUNCTION__); } } diff --git a/src/cm_server/cms_conn.cpp b/src/cm_server/cms_conn.cpp index 8aa8b61..d5856a0 100644 --- a/src/cm_server/cms_conn.cpp +++ b/src/cm_server/cms_conn.cpp @@ -26,6 +26,7 @@ #include #include #include "cm/cm_elog.h" +#include "cm_debug.h" #include "cms_common.h" #include "cms_global_params.h" #include "cms_conn.h" diff --git a/src/cm_server/cms_ddb_adapter.cpp b/src/cm_server/cms_ddb_adapter.cpp index 92383a3..5a7f73a 100644 --- a/src/cm_server/cms_ddb_adapter.cpp +++ b/src/cm_server/cms_ddb_adapter.cpp @@ -259,10 +259,6 @@ status_t GetAllKVFromDDb(char *key, uint32 keyLen, DrvKeyValue *keyValue, uint32 *ddbResult = SUCCESS_GET_VALUE; } } - if (getStatus == CM_SUCCESS) { - logLevel = (g_HA_status->local_role == CM_SERVER_PRIMARY) ? LOG : DEBUG1; - PrintKeyValueMsg(key, keyValue, len, logLevel); - } RestDdbConn(ddbConn, getStatus, ddbResult); return getStatus; } diff --git a/src/cm_server/cms_disk_check.cpp b/src/cm_server/cms_disk_check.cpp index 63b7349..966e91c 100644 --- a/src/cm_server/cms_disk_check.cpp +++ b/src/cm_server/cms_disk_check.cpp @@ -71,6 +71,9 @@ static bool g_allHealth = true; bool CheckReadOnlyStatus(uint32 instanceId) { + if (!IsBoolCmParamTrue(g_enableSetReadOnly)) { + return false; + } write_runlog(DEBUG1, "[%s] instanceId: %u\n", __FUNCTION__, instanceId); for (uint32 i = 0; i < g_node_num; i++) { if (g_dynamicNodeReadOnlyInfo[i].coordinateNode.readOnly && diff --git a/src/cm_server/cms_monitor_main.cpp b/src/cm_server/cms_monitor_main.cpp index 474e57d..c733303 100644 --- a/src/cm_server/cms_monitor_main.cpp +++ b/src/cm_server/cms_monitor_main.cpp @@ -158,6 +158,8 @@ static void datanode_status_reset(uint32 group_index, int member_index, bool isN .instance_status.data_node_member[member_index] .local_status.buildReason = INSTANCE_HA_DATANODE_BUILD_REASON_UNKNOWN; + g_instance_group_report_status_ptr[group_index].instance_status.data_node_member[member_index].floatIp.count = 0; + rc = memset_s(&g_instance_group_report_status_ptr[group_index] .instance_status.data_node_member[member_index] .sender_status[0].sender_sent_location, 8 * sizeof(XLogRecPtr), 0, 8 * sizeof(XLogRecPtr)); diff --git a/src/cm_server/cms_msg_que.cpp b/src/cm_server/cms_msg_que.cpp index f777aab..ba22f3c 100644 --- a/src/cm_server/cms_msg_que.cpp +++ b/src/cm_server/cms_msg_que.cpp @@ -22,9 +22,9 @@ * ------------------------------------------------------------------------- */ -#include "elog.h" #include "cm_c.h" #include "cm_util.h" +#include "cm_misc_base.h" #include "cm_msg_buf_pool.h" #include "cms_msg_que.h" @@ -40,7 +40,7 @@ void InitMsgQue(PriMsgQues &que) } (void)pthread_mutex_init(&que.msgLock, NULL); - (void)pthread_cond_init(&que.msgCond, NULL); + InitPthreadCondMonotonic(&que.msgCond); } void setWakeSenderFunc(wakeSenderFuncType func) @@ -133,7 +133,7 @@ const MsgRecvInfo *getRecvMsg(PriMsgQues *priQue, MsgSourceType src, uint32 wait const MsgRecvInfo* msg = getRecvMsgInner(priQue, src, threadInfo); if (msg == NULL && waitTime > 0) { - (void)clock_gettime(CLOCK_REALTIME, &tv); + (void)clock_gettime(CLOCK_MONOTONIC, &tv); tv.tv_sec = tv.tv_sec + (long long)waitTime; (void)pthread_mutex_lock(&priQue->msgLock); (void)pthread_cond_timedwait(&priQue->msgCond, &priQue->msgLock, &tv); diff --git a/src/cm_server/cms_process_messages.cpp b/src/cm_server/cms_process_messages.cpp index a76cbb7..f2dad48 100644 --- a/src/cm_server/cms_process_messages.cpp +++ b/src/cm_server/cms_process_messages.cpp @@ -1573,6 +1573,15 @@ void ProcessNodeDiskStatReq(MsgRecvInfo *recvMsgInfo, const CmShowStatReq *req) (void)RespondMsg(recvMsgInfo, 'S', (char *)(&ack), sizeof(CmNodeDiskStatAck)); } +void ProcessFloatIpReq(MsgRecvInfo *recvMsgInfo, const CmShowStatReq *req) +{ + write_runlog(DEBUG1, "[ProcessFloatIpReq] receive float ip query msg.\n"); + char sendMsg[DDB_MAX_KEY_VALUE_LEN] = {0}; + size_t msgLen = sizeof(CmFloatIpStatAck); + GetFloatIpSet((CmFloatIpStatAck*)sendMsg, DDB_MAX_KEY_VALUE_LEN, &msgLen); + (void)RespondMsg(recvMsgInfo, 'S', sendMsg, msgLen); +} + static void MsgShowStatus(MsgRecvInfo* recvMsgInfo, int msgType, CmdMsgProc *msgProc) { CmShowStatReq *req = NULL; @@ -1583,12 +1592,24 @@ static void MsgShowStatus(MsgRecvInfo* recvMsgInfo, int msgType, CmdMsgProc *msg case MSG_CTL_CM_NODE_DISK_STATUS_REQ: PROCESS_MSG_BY_TYPE(CmShowStatReq, req, ProcessNodeDiskStatReq); break; + case MSG_CTL_CM_FLOAT_IP_REQ: + PROCESS_MSG_BY_TYPE(CmShowStatReq, req, ProcessFloatIpReq); + break; default: write_runlog(ERROR, "[MsgShowStatus] unknown request(%d)\n", msgType); break; } } +static void MsgGetFloatIpInfo(MsgRecvInfo *recvMsgInfo, int msgType, CmdMsgProc *msgProc) +{ + if (!IsNeedCheckFloatIp() || (backup_open != CLUSTER_PRIMARY)) { + return; + } + CmaDnFloatIpInfo *floatIpInfo; + PROCESS_MSG_BY_TYPE(CmaDnFloatIpInfo, floatIpInfo, ProcessDnFloatIpMsg); +} + static void MsgResIsreg(MsgRecvInfo *recvMsgInfo, int msgType, CmdMsgProc *msgProc) { CmaToCmsIsregMsg *isregMsg; @@ -1632,6 +1653,7 @@ static void InitCmCtlCmdProc() g_cmdProc[MSG_CTL_CM_QUERY_RES_INST] = MsgCmQueryOneResInst; g_cmdProc[MSG_CTL_CM_RHB_STATUS_REQ] = MsgShowStatus; g_cmdProc[MSG_CTL_CM_NODE_DISK_STATUS_REQ] = MsgShowStatus; + g_cmdProc[MSG_CTL_CM_FLOAT_IP_REQ] = MsgShowStatus; } static void InitCmAgentCmdProc() @@ -1653,7 +1675,7 @@ static void InitCmAgentCmdProc() g_cmdProc[MSG_GET_SHARED_STORAGE_INFO] = MsgGetSharedStorageInfo; g_cmdProc[MSG_CM_RES_LOCK] = MsgCmResLock; g_cmdProc[MSG_CM_RHB] = MsgCmRhb; - g_cmdProc[MSG_AGENT_CM_FLOAT_IP] = NULL; + g_cmdProc[MSG_AGENT_CM_FLOAT_IP] = MsgGetFloatIpInfo; g_cmdProc[MSG_AGENT_CM_ISREG_REPORT] = MsgResIsreg; } diff --git a/src/cm_server/cms_process_messages_agent.cpp b/src/cm_server/cms_process_messages_agent.cpp index 5fda8c2..041c062 100644 --- a/src/cm_server/cms_process_messages_agent.cpp +++ b/src/cm_server/cms_process_messages_agent.cpp @@ -771,3 +771,145 @@ void ProcessDnLocalPeerMsg(MsgRecvInfo* recvMsgInfo, AgentCmDnLocalPeer *dnLpInf &(g_instance_group_report_status_ptr[groupIdx].instance_status.data_node_member[memIdx].dnLp.peerInst), groupIdx, &(dnLpInfo->dnLpInfo)); } + +static status_t FindAvaliableFloatIpPrimary(uint32 groupIdx, int32 *memIdx) +{ + cm_instance_datanode_report_status *dnReport = + g_instance_group_report_status_ptr[groupIdx].instance_status.data_node_member; + cm_local_replconninfo *dnLocal; + uint32 primaryDnCnt = 0; + for (int32 i = 0; i < g_instance_role_group_ptr[groupIdx].count; ++i) { + dnLocal = &(dnReport[i].local_status); + if (dnLocal->local_role == INSTANCE_ROLE_PRIMARY && dnLocal->db_state == INSTANCE_HA_STATE_NORMAL) { + *memIdx = i; + ++primaryDnCnt; + } + } + if (primaryDnCnt != 1) { + return CM_ERROR; + } + return CM_SUCCESS; +} + +static void ArbitrateFloatIpOper( + MsgRecvInfo *recvMsgInfo, const CmaDnFloatIpInfo *floatIp, NetworkOper oper, NetworkState state) +{ + CmsDnFloatIpAck ack = {{0}}; + errno_t rc = memcpy_s(&(ack.baseInfo), sizeof(BaseInstInfo), &(floatIp->baseInfo), sizeof(BaseInstInfo)); + securec_check_errno(rc, (void)rc); + ack.baseInfo.msgType = (int32)MSG_CM_AGENT_FLOAT_IP_ACK; + ack.oper = (int32)oper; + const DnFloatIpInfo *dnFloatIp = &(floatIp->info); + for (uint32 i = 0; i < dnFloatIp->count; ++i) { + if (dnFloatIp->dnNetState[i] != (int32)state || dnFloatIp->nicNetState[i] != (int32)state) { + (void)RespondMsg(recvMsgInfo, 'S', (const char *)(&ack), sizeof(CmsDnFloatIpAck)); + return; + } + } +} + +static void ArbitateFloatIp(MsgRecvInfo *recvMsgInfo, const CmaDnFloatIpInfo *floatIp, uint32 groupIdx, int32 memIdx) +{ + cm_instance_datanode_report_status *dnReport = + &(g_instance_group_report_status_ptr[groupIdx].instance_status.data_node_member[memIdx]); + (void)pthread_rwlock_wrlock(&(g_instance_group_report_status_ptr[groupIdx].lk_lock)); + errno_t rc = memcpy_s(&(dnReport->floatIp), sizeof(DnFloatIpInfo), &(floatIp->info), sizeof(DnFloatIpInfo)); + (void)pthread_rwlock_unlock(&(g_instance_group_report_status_ptr[groupIdx].lk_lock)); + securec_check_errno(rc, (void)rc); + int32 avaliMemIdx = -1; + status_t st = FindAvaliableFloatIpPrimary(groupIdx, &avaliMemIdx); + if (st != CM_SUCCESS) { + return; + } + if (avaliMemIdx == memIdx) { + ArbitrateFloatIpOper(recvMsgInfo, floatIp, NETWORK_OPER_UP, NETWORK_STATE_UP); + } else { + ArbitrateFloatIpOper(recvMsgInfo, floatIp, NETWORK_OPER_DOWN, NETWORK_STATE_DOWN); + } +} + +void ProcessDnFloatIpMsg(MsgRecvInfo *recvMsgInfo, CmaDnFloatIpInfo *floatIp) +{ + const char *str = "[ProcessDnLocalPeerMsg]"; + const BaseInstInfo *baseInst = &(floatIp->baseInfo); + if (baseInst->instType != INSTANCE_TYPE_DATANODE) { + write_runlog(ERROR, "%s cms get instance(%u) is not dn, this type is %d.\n", + str, baseInst->instId, baseInst->instType); + return; + } + uint32 groupIdx = 0; + int32 memIdx = 0; + uint32 node = baseInst->node; + uint32 instId = baseInst->instId; + // get groupIndex, memberIndex + int32 ret = find_node_in_dynamic_configure(node, instId, &groupIdx, &memIdx); + if (ret != 0) { + write_runlog(LOG, "[%s] can't find the instance(node=%u instanceid =%u)\n", __FUNCTION__, node, instId); + return; + } + write_runlog(DEBUG1, "cms receive dnFloatIpMsg, and group[%u: %d], node[%u], instId[%u].\n", + groupIdx, memIdx, node, instId); + ArbitateFloatIp(recvMsgInfo, floatIp, groupIdx, memIdx); +} + +static void InitFloatIpAck(CmFloatIpStatAck *ack) +{ + ack->msgType = (int32)MSG_CTL_CM_FLOAT_IP_ACK; + ack->count = 0; + ack->canShow = CM_TRUE; +} + +static bool8 IsCurInstanceExistingFloatIp(uint32 groupIdx, int32 memIdx) +{ + DnFloatIpInfo *dnFloatIp = + &(g_instance_group_report_status_ptr[groupIdx].instance_status.data_node_member[memIdx].floatIp); + for (uint32 i = 0; i < dnFloatIp->count; ++i) { + if (dnFloatIp->nicNetState[i] == (int32)NETWORK_STATE_UP) { + return CM_TRUE; + } + } + return CM_FALSE; +} + +static void GetFloatIpInfo(CmFloatIpStatAck *ack, size_t *curMsgLen, uint32 groupIdx, int32 memIdx) +{ + uint32 point = ack->count; + CmFloatIpStatInfo *info = &(ack->info[point]); + info->nodeId = g_instance_role_group_ptr[groupIdx].instanceMember[memIdx].node; + info->instId = g_instance_role_group_ptr[groupIdx].instanceMember[memIdx].instanceId; + if (!IsCurInstanceExistingFloatIp(groupIdx, memIdx)) { + return; + } + DnFloatIpInfo *dnFloatIp = + &(g_instance_group_report_status_ptr[groupIdx].instance_status.data_node_member[memIdx].floatIp); + (void)pthread_rwlock_rdlock(&(g_instance_group_report_status_ptr[groupIdx].lk_lock)); + uint32 i = 0; + for (; i < dnFloatIp->count && i < MAX_FLOAT_IP_COUNT; ++i) { + info->nicNetState[i] = dnFloatIp->nicNetState[i]; + } + info->count = i; + (void)pthread_rwlock_unlock(&(g_instance_group_report_status_ptr[groupIdx].lk_lock)); + ++ack->count; + *curMsgLen += sizeof(CmFloatIpStatInfo); +} + +void GetFloatIpSet(CmFloatIpStatAck *ack, size_t maxMsgLen, size_t *curMsgLen) +{ + InitFloatIpAck(ack); + if (!IsNeedCheckFloatIp() || (backup_open != CLUSTER_PRIMARY)) { + ack->canShow = CM_FALSE; + return; + } + for (uint32 i = 0; i < g_dynamic_header->relationCount; ++i) { + if (g_instance_role_group_ptr[i].instanceMember[0].instanceType != INSTANCE_TYPE_DATANODE) { + continue; + } + for (int32 j = 0; j < g_instance_role_group_ptr[i].count; ++j) { + if (*curMsgLen + sizeof(CmFloatIpStatInfo) > maxMsgLen) { + write_runlog(LOG, "tmpMsgLen is %zu, and maxMsgLen is %zu.\n", *curMsgLen, maxMsgLen); + return; + } + GetFloatIpInfo(ack, curMsgLen, i, j); + } + } +} diff --git a/src/cm_server/cms_process_messages_ctl.cpp b/src/cm_server/cms_process_messages_ctl.cpp index a9fc31d..e12259a 100644 --- a/src/cm_server/cms_process_messages_ctl.cpp +++ b/src/cm_server/cms_process_messages_ctl.cpp @@ -2314,8 +2314,10 @@ void process_ctl_to_cm_get_datanode_relation_msg( for (int i = 0; i < CM_PRIMARY_STANDBY_MAX_NUM; i++) { ack.instanceMember[i] = g_instance_role_group_ptr[group_index].instanceMember[i]; - ack.data_node_member[i] = - g_instance_group_report_status_ptr[group_index].instance_status.data_node_member[i]; + errno_t rc = memcpy_s(&(ack.data_node_member[i]), sizeof(CmDnReportStatusMsg), + &(g_instance_group_report_status_ptr[group_index].instance_status.data_node_member[i]), + sizeof(CmDnReportStatusMsg)); + securec_check_errno(rc, (void)rc); ack.gtm_member[i] = g_instance_group_report_status_ptr[group_index].instance_status.gtm_member[i]; } diff --git a/src/cm_server/cms_process_messages_res.cpp b/src/cm_server/cms_process_messages_res.cpp index dfad408..857e58b 100644 --- a/src/cm_server/cms_process_messages_res.cpp +++ b/src/cm_server/cms_process_messages_res.cpp @@ -42,16 +42,6 @@ void ProcessReportResChangedMsg(bool notifyClient, const OneResStatList &status) errno_t rc = memcpy_s(&sendMsg.resList, sizeof(OneResStatList), &status, sizeof(OneResStatList)); securec_check_errno(rc, (void)rc); - write_runlog(LOG, "[CLIENT] res(%s), version=%llu, status:\n", status.resName, status.version); - for (uint32 i = 0; i < status.instanceCount; ++i) { - write_runlog(LOG, "[CLIENT] nodeId=%u, cmInstId=%u, resInstId=%u, isWork=%u, status=%u;\n", - status.resStat[i].nodeId, - status.resStat[i].cmInstanceId, - status.resStat[i].resInstanceId, - status.resStat[i].isWorkMember, - status.resStat[i].status); - } - (void)BroadcastMsg('S', (char *)(&sendMsg), sizeof(CmsReportResStatList)); } @@ -169,6 +159,7 @@ static bool IsCusResStatValid(const OneNodeResourceStatus *nodeStat) for (uint32 i = 0; i < nodeStat->count; ++i) { if (nodeStat->status[i].status != CUS_RES_CHECK_STAT_ONLINE && nodeStat->status[i].status != CUS_RES_CHECK_STAT_OFFLINE && + nodeStat->status[i].status != CUS_RES_CHECK_STAT_ABNORMAL && nodeStat->status[i].status != CUS_RES_CHECK_STAT_TIMEOUT) { return false; } @@ -270,6 +261,9 @@ static uint32 GetResInstStat(uint32 recvStat) if (recvStat == CUS_RES_CHECK_STAT_OFFLINE) { return (uint32)CM_RES_STAT_OFFLINE; } + if (recvStat == CUS_RES_CHECK_STAT_ABNORMAL) { + return (uint32)CM_RES_STAT_ONLINE; + } return (uint32)CM_RES_STAT_UNKNOWN; } @@ -302,6 +296,7 @@ static void ProcessOneResInstStatReport(CmResourceStatus *stat) (void)pthread_rwlock_rdlock(&(resStat->rwlock)); SaveOneResStatusToDdb(&resStat->status); (void)pthread_rwlock_unlock(&(resStat->rwlock)); + PrintCusInfoResList(&resStat->status, __FUNCTION__); write_runlog(LOG, "[CLIENT] [%u:%u] res(%s) changed\n", stat->nodeId, stat->cmInstanceId, stat->resName); } } @@ -431,6 +426,7 @@ void ReleaseResLockOwner(const char *resName, uint32 instId) } return; } + PrintKeyValueMsg(key, kvs, kvCount, DEBUG5); for (uint32 i = 0; i < kvCount; ++i) { if (kvs[i].key[0] == '\0' || kvs[i].value[0] == '\0') { diff --git a/src/include/cm/cm_agent/clients/libpq/cma_libpq_api.h b/src/include/cm/cm_agent/clients/libpq/cma_libpq_api.h index 7b5fd29..be1dd2c 100644 --- a/src/include/cm/cm_agent/clients/libpq/cma_libpq_api.h +++ b/src/include/cm/cm_agent/clients/libpq/cma_libpq_api.h @@ -24,6 +24,8 @@ #ifndef CMA_LIBPQ_API_H #define CMA_LIBPQ_API_H +#include + typedef void cltPqConn_t; typedef void cltPqResult_t; diff --git a/src/include/cm/cm_agent/clients/libpq/cma_libpq_com.h b/src/include/cm/cm_agent/clients/libpq/cma_libpq_com.h new file mode 100644 index 0000000..0993da2 --- /dev/null +++ b/src/include/cm/cm_agent/clients/libpq/cma_libpq_com.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2023 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. + * ------------------------------------------------------------------------- + * + * cma_libpq_com.h + * + * IDENTIFICATION + * include/cm/cm_agent/clients/libpq/cma_libpq_com.h + * + * ------------------------------------------------------------------------- + */ +#ifndef CMA_LIBPQ_COM_H +#define CMA_LIBPQ_COM_H + +#include "cma_libpq_api.h" + +typedef void *CltResultSet; + +typedef struct SqlCondT { + const char *str; + unsigned int instId; +} SqlCond; + +typedef int (*ResultSetHandle)(CltResultSet set, const cltPqResult_t *nodeResult, const char *sqlCommand, + const SqlCond *sqlCond); + + +int ExecDmlSqlCmd(ResultSetHandle handle, CltResultSet set, cltPqConn_t **conn, const char *sqlCommand, + const SqlCond *sqlCond); + +#endif diff --git a/src/include/cm/cm_agent/cma_client.h b/src/include/cm/cm_agent/cma_client.h index 9ddc801..707ba42 100644 --- a/src/include/cm/cm_agent/cma_client.h +++ b/src/include/cm/cm_agent/cma_client.h @@ -31,7 +31,7 @@ void StartDatanodeCheck(void); int CheckDnStausPhonyDead(int dnId, int agentCheckTimeInterval); -int DatanodeStatusCheck(DnStatus *dnStatus, uint32 dataNodeIndex); +int DatanodeStatusCheck(DnStatus *dnStatus, uint32 dataNodeIndex, int32 dnProcess); int CheckDatanodeStatus(const char *dataDir, int *role); int ProcessUnlockCmd(const cm_to_agent_unlock *unlockMsg); @@ -42,4 +42,6 @@ void *DNSyncCheckMain(void *arg); void ProcessStreamingStandbyClusterBuildCommand( int instanceType, const char* dataDir, const cm_to_agent_build *buildMsg); void* DNBackupStatusCheckMain(void *arg); +void DnCheckFloatIp(DnStatus *dnStatus, uint32 dnIdx, bool8 isRunning); +uint32 DelFloatIpInDatanode(uint32 dnIdx); #endif // CM_CMA_CLIENT_ADPT_H diff --git a/src/include/cm/cm_agent/cma_common.h b/src/include/cm/cm_agent/cma_common.h index 7489a29..c0ed1b5 100644 --- a/src/include/cm/cm_agent/cma_common.h +++ b/src/include/cm/cm_agent/cma_common.h @@ -43,6 +43,10 @@ typedef enum { CM_RES_CORPSE = 3, } CM_ResStatus; +const int ERROR_EXECUTE_CMD = -2; +const int FAILED_EXECUTE_CMD = -1; +const int SUCCESS_EXECUTE_CMD = 0; + void save_thread_id(pthread_t thrId); void set_thread_state(pthread_t thrId); void immediate_stop_one_instance(const char* instance_data_path, InstanceTypes instance_type); @@ -73,7 +77,7 @@ int search_HA_node(uint32 localPort, uint32 LocalHAListenCount, char LocalHAIP[] int agentCheckPort(uint32 port); uint32 CheckDiskForLogPath(void); uint32 GetDiskUsageForPath(const char *pathName); -int ExecuteSystemCmd(const char *cmd); +int ExecuteSystemCmd(const char *cmd, int32 logLevel = ERROR, int32 *errCode = NULL); void CheckDnNicDown(uint32 index); void CheckDnDiskDamage(uint32 index); bool IsDirectoryDestoryed(const char *path); diff --git a/src/include/cm/cm_agent/cma_instance_management.h b/src/include/cm/cm_agent/cma_instance_management.h index 607172b..241bc06 100644 --- a/src/include/cm/cm_agent/cma_instance_management.h +++ b/src/include/cm/cm_agent/cma_instance_management.h @@ -45,6 +45,7 @@ uint32 GetLibcommPort(const char* file_path, uint32 base_port, int port_type); extern bool UpdateLibcommConfig(); int stop_instance_check(void); int killInstanceByPid(const char *processName, const char *cmdLine); +void DelAndDownFloatIpInDn(uint32 index); #ifdef ENABLE_UT extern void StopOneZengine(uint32 index); diff --git a/src/include/cm/cm_agent/cma_instance_management_res.h b/src/include/cm/cm_agent/cma_instance_management_res.h index 30a5a6e..1df7cc4 100644 --- a/src/include/cm/cm_agent/cma_instance_management_res.h +++ b/src/include/cm/cm_agent/cma_instance_management_res.h @@ -27,7 +27,6 @@ #include "cm_misc.h" -int SystemExecute(const char *scriptPath, const char *oper, uint32 timeout); status_t StartOneResInst(const CmResConfList *conf); void StopOneResInst(const CmResConfList *conf); void OneResInstShutdown(const CmResConfList *oneResConf); diff --git a/src/include/cm/cm_agent/cma_msg_queue.h b/src/include/cm/cm_agent/cma_msg_queue.h index dff0bfd..297974e 100644 --- a/src/include/cm/cm_agent/cma_msg_queue.h +++ b/src/include/cm/cm_agent/cma_msg_queue.h @@ -47,6 +47,7 @@ void PushMsgToCmsSendQue(const char *msgPtr, uint32 msgLen, const char *msgInfo) void PushMsgToCmsRecvQue(const char *msgPtr, uint32 msgLen); void PushMsgToClientSendQue(const char *msgPtr, uint32 msgLen, uint32 conId); void PushMsgToClientRecvQue(const char *msgPtr, uint32 msgLen, uint32 conId); +void PushMsgToAllClientSendQue(const char *msgPtr, uint32 msgLen); void CleanCmsMsgQueue(); void CleanClientMsgQueue(uint32 conId); diff --git a/src/include/cm/cm_agent/cma_network_check.h b/src/include/cm/cm_agent/cma_network_check.h index ee47380..fa75dfe 100644 --- a/src/include/cm/cm_agent/cma_network_check.h +++ b/src/include/cm/cm_agent/cma_network_check.h @@ -24,7 +24,11 @@ #ifndef CMA_NETWORK_CHECK_H #define CMA_NETWORK_CHECK_H #include "cm_defs.h" + +#include "common/config/cm_config.h" + #include "cm_msg_common.h" +#include "cm_json_parse_floatIp.h" typedef enum CmaInstTypeE { CM_INSTANCE_TYPE_CMA = 0, // it cannot smaller than 0 @@ -42,6 +46,12 @@ typedef enum NetworkTypeE { NETWORK_TYPE_CEIL // it must be end } NetworkType; +typedef struct DnFloatIpOperMapT { + uint32 count; + NetworkOper oper[CM_MAX_DATANODE_PER_NODE]; + DnFloatIp floatIp[CM_MAX_DATANODE_PER_NODE]; +} DnFloatIpMapOper; + bool GetNicStatus(unsigned int instId, CmaInstType instType, NetworkType type = NETWORK_TYPE_LISTEN); void SetNicOper(uint32 instId, CmaInstType instType, NetworkType type, NetworkOper oper); void GetFloatIpNicStatus(uint32 instId, CmaInstType instType, NetworkState *state, uint32 count); @@ -50,6 +60,10 @@ status_t CreateNetworkResource(); NetworkState GetNetworkStateByOper(NetworkOper oper); NetworkOper GetNetworkOperByState(NetworkState state); NetworkOper ChangeInt2NetworkOper(int32 oper); +void SetFloatIpOper(uint32 dnIdx, NetworkOper oper, const char *str); +NetworkOper GetFloatIpOper(uint32 dnIdx); +DnFloatIp *GetDnFloatIpByDnIdx(uint32 dnIdx); const char *GetOperMapString(NetworkOper oper); +bool8 CheckNetworkStatusByIps(const char (*ips)[CM_IP_LENGTH], uint32 cnt); #endif diff --git a/src/include/cm/cm_agent/cma_process_messages_client.h b/src/include/cm/cm_agent/cma_process_messages_client.h index 708658a..1b09377 100644 --- a/src/include/cm/cm_agent/cma_process_messages_client.h +++ b/src/include/cm/cm_agent/cma_process_messages_client.h @@ -29,5 +29,6 @@ void ProcessResStatusChanged(const CmsReportResStatList *msg); void ProcessResLockAckFromCms(const CmsReportLockResult *recvMsg); void ProcessResRegFromCms(const CmsNotifyAgentRegMsg *recvMsg); void ProcessIsregCheckListChanged(const CmsFlushIsregCheckList *recvMsg); +void NotifyClientConnectClose(); #endif // CMA_PROCESS_MESSAGES_CLIENT_H diff --git a/src/include/cm/cm_ctl/ctl_common.h b/src/include/cm/cm_ctl/ctl_common.h index faab63b..24f8575 100644 --- a/src/include/cm/cm_ctl/ctl_common.h +++ b/src/include/cm/cm_ctl/ctl_common.h @@ -30,6 +30,9 @@ #include "cm/cm_defs.h" #include "cm_ddb_adapter.h" #include "cm_cipher.h" +#include "ctl_global_params.h" +#include "cm_json_config.h" +#include "ctl_res.h" #define DEFAULT_WAIT 60 #define DYNAMIC_PRIMARY 0 @@ -200,48 +203,6 @@ typedef struct DcfOptionSt { int priority; } DcfOption; -typedef enum ResOptModeEn { - RES_CONF_UNKNOWN = 0, - RES_ADD_CONF = 1, - RES_EDIT_CONF = 2, - RES_DEL_CONF = 3, - RES_CHECK_CONF = 4, -} ResOptMode; - -typedef enum ResEditModeEn { - RES_EDIT_UNKNOWN = 0, - RES_ADD_INST_CONF = 1, - RES_DEL_INST_CONF = 2, - RES_EDIT_RES_CONF = 3, - RES_EDIT_CEIL, // it must be end -} ResEditMode; - -typedef enum ResTypeE { - RES_TYPE_UNKOWN, - RES_TYPE_APP, - RES_TYPE_DN, - RES_TYPE_CEIL, // it must be end -} ResType; - -typedef struct ResOptionSt { - ResOptMode mode; - ResType type; - char *resName; - char *resAttr; - ResEditMode editMode; - char *addInstStr; - char *delInstStr; -} ResOption; - -typedef status_t (*CheckResInfo)(cJSON *resItem, const char *resName); - -typedef struct ResTypeMapT { - ResType type; - const char *typeStr; - const char *value; - CheckResInfo check; -} ResTypeMap; - typedef struct CtlOptionSt { CommonOption comm; GucOption guc; @@ -255,7 +216,6 @@ typedef struct CtlOptionSt { extern bool g_isRestop; extern DdbConn *g_sess; extern TlsAuthPath g_tlsPath; -extern ResTypeMap g_resTypeMap[]; status_t do_start(void); int DoStop(void); @@ -284,13 +244,8 @@ void DoDccCmd(int argc, char **argv); int DoGuc(CtlOption *ctx); int DoEncrypt(const CtlOption *ctx); int DoSwitch(const CtlOption *ctx); -int DoResCommand(const CtlOption *ctx); int DoShowCommand(); -void GetExecCmdResult(const char *option, int expCmd); -void HandleRhbAck(CmRhbStatAck *ack); -void HandleNodeDiskAck(CmNodeDiskStatAck *ack); - void stop_etcd_cluster(void); int stop_check_node(uint32 node_id_check); void stop_etcd_node(uint32 nodeid); @@ -302,13 +257,13 @@ uint32 get_node_index(uint32 node_id); bool isMajority(const char* cm_arbitration_mode); bool isMinority(const char* cm_arbitration_mode); int FindInstanceIdAndType(uint32 node, const char* dataPath, uint32* instanceId, int* instanceType); -int ssh_exec(const staticNodeConfig* node, const char* cmd); +int ssh_exec(const staticNodeConfig* node, const char* cmd, int32 logLevel = ERROR); int SshExec(const staticNodeConfig* node, const char* cmd); int RunEtcdCmd(const char* command, uint32 nodeIndex); -void do_conn_cmserver(bool queryCmserver, uint32 nodeIndex, bool queryEtcd = false, CM_Conn **curConn = NULL); -int cm_client_flush_msg(CM_Conn* conn); -int cm_client_send_msg(CM_Conn* conn, char msgtype, const char* s, size_t len); -char* recv_cm_server_cmd(CM_Conn* conn); +void do_conn_cmserver(bool queryCmserver, uint32 nodeIndex, bool queryEtcd = false, struct cm_conn **curConn = NULL); +int cm_client_flush_msg(struct cm_conn* conn); +int cm_client_send_msg(struct cm_conn* conn, char msgtype, const char* s, size_t len); +char* recv_cm_server_cmd(struct cm_conn* conn); void init_hosts(); bool is_node_stopping(uint32 checkNode, uint32 currentNode, const char *manualStartFile, const char *resultFile, const char *mppEnvSeperateFile); @@ -348,8 +303,8 @@ status_t KillAllCms(bool isNeedKillPrimaryCms); uint32 *GetCmsNodeIndex(void); status_t CheckGucOptionValidate(const GucOption &gucCtx); void GetUpgradeVersionFromCmaConfig(); -bool SetOfflineNode(uint32 nodeIndex, CM_Conn *con); -void ReleaseConn(CM_Conn *con); +bool SetOfflineNode(uint32 nodeIndex, struct cm_conn *con); +void ReleaseConn(struct cm_conn *con); bool IsCmSharedStorageMode(); void CtlGetCmJsonConf(); int DoRhbPrint(); diff --git a/src/include/cm/cm_ctl/ctl_global_params.h b/src/include/cm/cm_ctl/ctl_global_params.h new file mode 100644 index 0000000..7d38512 --- /dev/null +++ b/src/include/cm/cm_ctl/ctl_global_params.h @@ -0,0 +1,38 @@ +/* + * 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. + * ------------------------------------------------------------------------- + * + * ctl_distribute.h + * + * + * IDENTIFICATION + * include/cm/cm_ctl/ctl_common.h + * + * ------------------------------------------------------------------------- + */ + +#ifndef CTL_GLOBAL_PARAMS_H +#define CTL_GLOBAL_PARAMS_H + +#include + +struct cm_conn; + +extern struct cm_conn *CmServer_conn; +extern struct cm_conn *CmServer_conn1; +extern struct cm_conn *CmServer_conn2; +extern FILE *g_logFilePtr; +struct cm_conn *GetCmsConn(); + +#endif \ No newline at end of file diff --git a/src/include/cm/cm_ctl/ctl_misc.h b/src/include/cm/cm_ctl/ctl_misc.h new file mode 100644 index 0000000..7d50c77 --- /dev/null +++ b/src/include/cm/cm_ctl/ctl_misc.h @@ -0,0 +1,31 @@ +/* + * 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. + * ------------------------------------------------------------------------- + * + * ctl_misc.h + * + * IDENTIFICATION + * include/cm/cm_ctl/ctl_misc.h + * + * ------------------------------------------------------------------------- + */ + +#ifndef CTL_MISC_H +#define CTL_MISC_H +#include "c.h" +#include "cm_misc.h" + +int FindInstanceByInstId(uint32 instId, Instance *inst); + +#endif diff --git a/src/include/cm/cm_ctl/ctl_process_message.h b/src/include/cm/cm_ctl/ctl_process_message.h new file mode 100644 index 0000000..65260c5 --- /dev/null +++ b/src/include/cm/cm_ctl/ctl_process_message.h @@ -0,0 +1,41 @@ +/* + * 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. + * ------------------------------------------------------------------------- + * + * ctl_process_message.h + * + * + * IDENTIFICATION + * include/cm/cm_ctl/ctl_process_message.h + * + * ------------------------------------------------------------------------- + */ +#ifndef CTL_PROCESS_MESSAGE_H +#define CTL_PROCESS_MESSAGE_H + +#include "c.h" +#include "cm_defs.h" +#include "ctl_global_params.h" + +const int32 INVALID_EXPECT_CMD = -1; + +typedef status_t (*CtlDealCmdFunc)(const char *option, char *msg); + +struct cm_conn; + +status_t GetExecCmdResult(const char *option, int32 expCmd = INVALID_EXPECT_CMD, struct cm_conn *conn = GetCmsConn()); +void InitDdbCmdMsgFunc(); +void InitCtlShowMsgFunc(); + +#endif \ No newline at end of file diff --git a/src/include/cm/cm_ctl/ctl_res.h b/src/include/cm/cm_ctl/ctl_res.h new file mode 100644 index 0000000..5c63802 --- /dev/null +++ b/src/include/cm/cm_ctl/ctl_res.h @@ -0,0 +1,157 @@ +/* + * Copyright (c) 2023 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. + * ------------------------------------------------------------------------- + * + * ctl_res.h + * + * + * IDENTIFICATION + * include/cm/cm_ctl/ctl_res.h + * + * ------------------------------------------------------------------------- + */ + +#ifndef CTL_RES_H +#define CTL_RES_H + +#include "c.h" +#include "cm_defs.h" + +#include "cjson/cJSON.h" +#include "cm_elog.h" + +typedef enum ResTypeE { + RES_TYPE_INIT = 0, + RES_TYPE_UNKNOWN, + RES_TYPE_APP, + RES_TYPE_DN, + RES_TYPE_VIP, + RES_TYPE_CEIL, // it must be end +} ResType; + +typedef enum ResOpModeE { + RES_OP_INIT = 0, + RES_OP_UNKNOWN, + RES_OP_ADD, + RES_OP_DEL, + RES_OP_EDIT, + RES_OP_CHECK, + RES_OP_LIST, + RES_OP_CEIL // it must be end +} ResOpMode; + +typedef struct ResInstOpT { + ResOpMode mode; + char reserved[4]; // for alignment + char *instName; + char *instAttr; +} ResInstOp; + +typedef struct ResOptionT { + ResOpMode mode; + char reserved[4]; // for alignment + char *resName; + char *resAttr; + ResInstOp inst; +} ResOption; + +typedef struct ResTypeStrT { + ResType type; + const char *str; +} ResTypeStr; + +typedef enum ResLevelE { + RES_LEVEL_INIT = 0, + RES_LEVEL_UNKNOWN, + RES_LEVEL_RES, + RES_LEVEL_INST, + RES_LEVEL_CEIL +} ResLevel; + +typedef enum ResKvTypeE { + RES_KV_TYPE_INIT = 0, + RES_KV_TYPE_UNKNOWN, + RES_KV_TYPE_INTEGER, + RES_KV_TYPE_STRING, + RES_KV_TYPE_ARRAY, + RES_KV_TYPE_OBJECT, + RES_KV_TYPE_CEIL +} ResKvType; + +typedef struct KvRestrictT { + ResKvType type; + const char *key; +} KvRestrict; + +typedef struct ResInstInfoT { + int32 instId; + int32 nodeId; +} ResInstInfo; + +// res +const char KEY_VALUE_SPLIT_CHAR = '='; +const char KEY_VALUE_SPLIT_ARRAY[] = {KEY_VALUE_SPLIT_CHAR, '\0'}; +const char *const RES_NAME = "name"; +const char *const RESOURCE_TYPE = "resources_type"; +const char *const RESOURCES = "resources"; +const char *const INSTANCES = "instances"; +const char *const RES_ATTR = "res_attr"; + +// instances +const char *const INST_NODE_ID = "node_id"; +const char *const INST_RES_INST_ID = "res_instance_id"; + +// APP or DN +const char *const RES_SCRIPT = "script"; +const char *const RES_CHECK_INTERVAL = "check_interval"; +const char *const RES_TIMEOUT = "time_out"; +const char *const RES_RESTART_DELAY = "restart_delay"; +const char *const RES_PERIOD = "restart_period"; +const char *const RES_RESTART_TIMES = "restart_times"; + +const char *const INST_REG = "res_args"; + +// VIP +const char *const RES_FLOAT_IP = "float_ip"; +const char *const INST_ATTR = "inst_attr"; + +typedef status_t (*CheckResInfo)(cJSON *resItem, const char *resName); + +typedef struct ResTypeMapT { + ResType type; + const char *typeStr; + const char *value; + CheckResInfo check; +} ResTypeMap; + +status_t GetIntFromText( + const ResOption *resCtx, const char *str, const char *expectValue, int32 *value, int32 logLevel); +status_t CheckResFromArray(cJSON *resArray); +bool CompareResType(const char *value, uint32 *index); +status_t CheckResFromArray(cJSON *resArray); +int DoResCommand(ResOption *resCtx); +const char *GetResOperStr(ResOpMode opMode); +const char *GetInstOperStr(ResOpMode opMode); +int GetValueIntFromCJson(const cJSON *object, const char *infoKey, int32 logLevel = ERROR); +char *GetValueStrFromCJson(const cJSON *object, const char *infoKey, int32 logLevel = ERROR); +cJSON *GetCurResInArray(cJSON *resArray, const char *resName, const ResOption *resCtx, int32 *resIdx = NULL); +ResType GetResTypeFromCjson(cJSON *resItem); +bool CompareResType(const char *value, uint32 *index); +void InitResTypeMap(); +bool8 IsResCheckInstances(ResType resType); +bool8 IsCurNotCheckInstances(const ResOption *resCtx, const cJSON *resObj); +const char *GetResTypeValue(uint32 index); +ResType GetResTypeInJson(const ResOption *resCtx, const cJSON *resObj); + +#endif diff --git a/src/include/cm/cm_ctl/ctl_res_list.h b/src/include/cm/cm_ctl/ctl_res_list.h new file mode 100644 index 0000000..3418d9e --- /dev/null +++ b/src/include/cm/cm_ctl/ctl_res_list.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2023 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. + * ------------------------------------------------------------------------- + * + * ctl_res_list.h + * + * IDENTIFICATION + * include/cm/cm_ctl/ctl_res_list.h + * + * ------------------------------------------------------------------------- + */ + +#ifndef CTL_RES_LIST_H +#define CTL_RES_LIST_H + +#include "c.h" +#include "cm_defs.h" + +#include "cjson/cJSON.h" + +#include "ctl_res.h" + +status_t ListResInJson(cJSON *resArray, const ResOption *resCtx); + +#endif diff --git a/src/include/cm/cm_ctl/ctl_show.h b/src/include/cm/cm_ctl/ctl_show.h new file mode 100644 index 0000000..3f7b033 --- /dev/null +++ b/src/include/cm/cm_ctl/ctl_show.h @@ -0,0 +1,32 @@ +/* + * 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. + * ------------------------------------------------------------------------- + * + * ctl_show.h + * + * + * IDENTIFICATION + * include/cm/cm_ctl/ctl_show.h + * + * ------------------------------------------------------------------------- + */ +#ifndef CTL_SHOW_H +#define CTL_SHOW_H + +#include "cm_defs.h" +status_t HandleRhbAck(const char *option, char *recvMsg); +status_t HandleNodeDiskAck(const char *option, char *recvMsg); +status_t HandleFloatIpAck(const char *option, char *recvMsg); + +#endif diff --git a/src/include/cm/cm_debug.h b/src/include/cm/cm_debug.h new file mode 100644 index 0000000..eb877d2 --- /dev/null +++ b/src/include/cm/cm_debug.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2023 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_debug.h + * + * IDENTIFICATION + * include/cm/cm_debug.h + * + * ------------------------------------------------------------------------- + */ + +#ifndef CM_DEBUG_H +#define CM_DEBUG_H + +#include "c.h" +static inline void cm_assert(bool condition) +{ + if (!condition) { + *((uint32 *)NULL) = 1; + } +} + +#ifdef CM_DEBUG_VERSION +#define CM_ASSERT(expr) cm_assert((bool)(expr)) +#else +#define CM_ASSERT(expr) ((void)(expr)) +#endif + +static inline void cm_exit(int32 exitcode) +{ + _exit(exitcode); +} +#endif diff --git a/src/include/cm/cm_defs.h b/src/include/cm/cm_defs.h index 80d7a6b..bc12220 100644 --- a/src/include/cm/cm_defs.h +++ b/src/include/cm/cm_defs.h @@ -274,6 +274,17 @@ typedef int socket_t; #define CM_IS_EMPTY_STR(str) (((str) == NULL) || ((str)[0] == 0)) +/* simple mathematical calculation */ +#define CM_MIN(A, B) ((B) < (A) ? (B) : (A)) +#define CM_MAX(A, B) ((B) > (A) ? (B) : (A)) +#define CM_SWAP(type, A, B) \ + do { \ + type t_ = (A); \ + (A) = (B); \ + (B) = t_; \ + } while (0) +#define CM_DELTA(A, B) (((A) > (B)) ? ((A) - (B)) : ((B) - (A))) + #define CM_PASSWORD_BUFFER_SIZE (uint32)512 #ifndef ITERATE_TIMES #define ITERATE_TIMES 10000 diff --git a/src/include/cm/cm_elog.h b/src/include/cm/cm_elog.h index 8d5b305..22a948a 100644 --- a/src/include/cm/cm_elog.h +++ b/src/include/cm/cm_elog.h @@ -58,6 +58,18 @@ typedef struct log_level_string_st { int level_val; } log_level_string; +static inline int32 GetCmLogMessage() +{ + if (log_min_messages == WARNING) { + return LOG; + } + + if (log_min_messages == LOG) { + return WARNING; + } + return log_min_messages; +} + typedef status_t (*SetParam)(const char *key, const char *value); void LoadParamterFromConfigWithPrefixKey(const char *configFile, const char *prefixKey, SetParam setParam); diff --git a/src/include/cm/cm_json_config.h b/src/include/cm/cm_json_config.h index 9856c31..129b0b5 100644 --- a/src/include/cm/cm_json_config.h +++ b/src/include/cm/cm_json_config.h @@ -38,6 +38,9 @@ #define CM_JSON_STR_LEN 1024 +const char SEPARATOR_CHAR = ','; +const char SEPARATOR_ARRAY[] = {SEPARATOR_CHAR, '\0'}; + typedef void (*CmJsonLogOutput)(int logLevel, const char *format, ...) __attribute__((format(printf, 2, 3))); typedef struct CusResInstConfSt { @@ -54,6 +57,7 @@ typedef struct CusResConfJson { int restartDelay; int restartPeriod; int restartTimes; + int abnormalTimeout; struct { CusResInstConf *conf; uint32 count; @@ -65,17 +69,28 @@ typedef struct BaseIpListConfSt { char baseIp[CM_JSON_STR_LEN]; } BaseIpListConf; +typedef struct VipCusResConfJsonSt { + char resName[CM_JSON_STR_LEN]; + char floatIp[CM_JSON_STR_LEN]; + struct { + BaseIpListConf *conf; + uint32 count; + } baseIpList; +} VipCusResConfJson; + typedef enum CusResTypeEn { CUSTOM_RESOURCE_UNKNOWN, CUSTOM_RESOURCE_APP, CUSTOM_RESOURCE_DN, + CUSTOM_RESOURCE_VIP, } CusResType; typedef struct OneCusResConfJsonSt { - CusResType resType; // resources_type (APP,DN) + CusResType resType; // resources_type (APP,DN,VIP) union { AppCusResConfJson appResConf; // APP DnCusResConfJson dnResConf; // DN + VipCusResConfJson vipResConf; // VIP }; } OneCusResConfJson; @@ -93,5 +108,7 @@ int ReadConfJsonFile(const char *jsonFile); void SetReadJsonConfWriteLog(CmJsonLogOutput logFunc); bool IsConfJsonEmpty(); cJSON *ReadJsonFile(const char *jsonPath, int *err); +int FetchStrFromText(const char *textStr, char *result, uint32 len, char beginPoint); +int GetValueStrFromText(char *result, uint32 resultLen, const char *textStr, const char *expectValue); #endif // CM_CM_JSON_CONFIG_H diff --git a/src/include/cm/cm_json_parse_floatIp.h b/src/include/cm/cm_json_parse_floatIp.h new file mode 100644 index 0000000..845405b --- /dev/null +++ b/src/include/cm/cm_json_parse_floatIp.h @@ -0,0 +1,55 @@ +/* +* 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_json_parse_floatIp.h +* +* +* IDENTIFICATION +* include/cm/cm_json_parse_floatIp.h +* +* ------------------------------------------------------------------------- +*/ +#ifndef CM_JSON_PARSE_FLOATIP_H +#define CM_JSON_PARSE_FLOATIP_H +#include "c.h" +#include "cm_defs.h" +#include "cm_msg.h" +#include "cm_misc_res.h" + +typedef struct DnFloatIpT { + uint32 instId; + const char *dataPath; + // float ip and manage ip + uint32 dnFloatIpCount; + char baseIp[MAX_FLOAT_IP_COUNT][CM_IP_LENGTH]; + char dnFloatIp[MAX_FLOAT_IP_COUNT][CM_IP_LENGTH]; + char floatIpName[MAX_FLOAT_IP_COUNT][CM_MAX_RES_NAME]; + uint32 dnFloatIpPort; +} DnFloatIp; + +typedef bool8 (*findNodeInfoByNodeIdx)(uint32 instId, uint32 *nodeIdx, uint32 *dnIdx, const char *str); +typedef DnFloatIp *(*getDnFloatIpByNodeInfo)(uint32 nodeIdx, uint32 dnIdx); +typedef void (*increDnFloatIpCnt)(uint32 nodeIdx); + +typedef struct ParseFloatIpFuncT { + findNodeInfoByNodeIdx findNodeInfo; + getDnFloatIpByNodeInfo getFloatIp; + increDnFloatIpCnt increaseCnt; +} ParseFloatIpFunc; + +void ParseVipConf(int32 logLevel); +void InitParseFloatIpFunc(const ParseFloatIpFunc *parseFuc); + +#endif diff --git a/src/include/cm/cm_misc.h b/src/include/cm/cm_misc.h index 84deb6a..eaa64ef 100644 --- a/src/include/cm/cm_misc.h +++ b/src/include/cm/cm_misc.h @@ -142,12 +142,14 @@ typedef struct ResStatusCheckInfoSt { long brokeTime; int startCount; int onlineTimes; + long abnormalTime; int checkInterval; int timeOut; int restartDelay; int restartPeriod; int restartTimes; + int abnormalTimeout; } ResStatusCheckInfo; typedef struct CmResConfListSt { @@ -170,8 +172,14 @@ typedef enum { INST_TYPE_FENCED_UDF = 5, } InstanceType; +typedef struct NodeInstBaseInfoT { + uint32 nodeIdx; + uint32 instIdx; +} NodeInstBaseInfo; + typedef struct Instance_t { uint32 node; + NodeInstBaseInfo baseInfo; InstanceType instType; union { dataNodeInfo *dnInst; @@ -279,4 +287,5 @@ void listen_ip_merge(uint32 ipCnt, const char (*ipListen)[CM_IP_LENGTH], char *r bool IsNodeIdValid(int nodeId); void FreeSslOpton(); +bool IsNeedCheckFloatIp(); #endif diff --git a/src/include/cm/cm_misc_base.h b/src/include/cm/cm_misc_base.h index b04873c..a72240b 100644 --- a/src/include/cm/cm_misc_base.h +++ b/src/include/cm/cm_misc_base.h @@ -58,7 +58,10 @@ bool IsSharedStorageMode(); bool IsBoolCmParamTrue(const char *param); status_t TcpSendMsg(int socket, const char *buf, size_t remainSize, uint32 timeout = CM_TCP_TIMEOUT); status_t TcpRecvMsg(int socket, char *buf, size_t remainSize, uint32 timeout = CM_TCP_TIMEOUT); +long GetCurMonotonicTimeSec(); +void InitPthreadCondMonotonic(pthread_cond_t *cond); bool CmFileExist(const char *file_path); +bool CheckBoolConfigParam(const char* value); #endif // CM_MISC_API_H diff --git a/src/include/cm/cm_misc_res.h b/src/include/cm/cm_misc_res.h index c22b937..e40f202 100644 --- a/src/include/cm/cm_misc_res.h +++ b/src/include/cm/cm_misc_res.h @@ -48,6 +48,7 @@ const uint32 CM_MAX_VIP_COUNT = 16; #define CUS_RES_CHECK_STAT_ONLINE 0 #define CUS_RES_CHECK_STAT_OFFLINE 1 #define CUS_RES_CHECK_STAT_UNKNOWN 2 +#define CUS_RES_CHECK_STAT_ABNORMAL 3 #define CUS_RES_CHECK_STAT_TIMEOUT 137 #define CUS_RES_START_FAIL_DEPEND_NOT_ALIVE 6 @@ -94,6 +95,10 @@ typedef struct CmResStatListSt { extern bool g_enableSharedStorage; extern CmResStatList g_resStatus[CM_MAX_RES_COUNT]; +int ResConfMaxValue(const char *param); +int ResConfMinValue(const char *param); +const char* ResConfDefValue(const char *param); + bool IsResConfValid(const char *param, int value); void GetCmConfJsonPath(char *path, uint32 pathLen); int ReadCmConfJson(void *logFunc); @@ -108,5 +113,10 @@ uint8 CheckIpValid(const char *ip); uint32 CusResCount(); bool IsCusResExist(); const char *GetIsregStatus(int isreg); +void PrintCusInfoResList(const OneResStatList *status, const char *info); +bool8 IsDatanodeSSMode(); +const char* ResConfDefValue(const char *param); +int ResConfMinValue(const char *param); +int ResConfMaxValue(const char *param); #endif // CM_CM_MISC_RES_H diff --git a/src/include/cm/cm_msg.h b/src/include/cm/cm_msg.h index 1347919..919615b 100644 --- a/src/include/cm/cm_msg.h +++ b/src/include/cm/cm_msg.h @@ -224,7 +224,7 @@ typedef enum CM_MessageType_st { MSG_AGENT_CLIENT_HEARTBEAT_ACK = 141, MSG_AGENT_CLIENT_RES_STATUS_LIST = 142, MSG_AGENT_CLIENT_RES_STATUS_CHANGE = 143, - MSG_AGENT_CLIENT_SET_RES_DATA_STATUS = 144, + MSG_AGENT_CLIENT_NOTIFY_CONN_CLOSE = 144, MSG_AGENT_CLIENT_REPORT_RES_DATA = 145, MSG_EXEC_DDB_COMMAND = 146, @@ -260,6 +260,13 @@ typedef enum CM_MessageType_st { MSG_FINISHREDO_RETRIVE = 173, MSG_AGENT_CM_ISREG_REPORT = 174, MSG_CM_AGENT_ISREG_CHECK_LIST_CHANGED = 175, + MSG_CM_AGENT_DISKUSAGE_STATUS_ACK = 176, + MSG_AGENT_CM_EXT_IP_STATUS = 177, + MSG_CTL_CM_EXT_IP_STATUS_REQ = 178, + MSG_CM_CTL_EXT_IP_DATA = 179, + MSG_CM_CTL_EXT_IP_DATA_END = 180, + MSG_CTL_CM_FLOAT_IP_REQ = 181, + MSG_CTL_CM_FLOAT_IP_ACK = 182, MSG_CM_TYPE_CEIL, // new message types should be added before this. } CM_MessageType; @@ -1274,6 +1281,24 @@ typedef struct BaseInstInfoT { const uint32 FLOAT_IP_MSG_RES = 512; +typedef struct DnFloatIpInfoT { + uint32 count; + int32 dnNetState[MAX_FLOAT_IP_COUNT]; + int32 nicNetState[MAX_FLOAT_IP_COUNT]; +} DnFloatIpInfo; + +typedef struct CmaDnFloatIpInfoT { + BaseInstInfo baseInfo; + DnFloatIpInfo info; + char remain[FLOAT_IP_MSG_RES]; +} CmaDnFloatIpInfo; + +typedef struct CmsDnFloatIpAckT { + BaseInstInfo baseInfo; + int32 oper; + char remain[FLOAT_IP_MSG_RES]; +} CmsDnFloatIpAck; + typedef struct DnStatus_t { CM_MessageType barrierMsgType; agent_to_cm_datanode_status_report reportMsg; @@ -1283,6 +1308,7 @@ typedef struct DnStatus_t { }; AgentCmDnLocalPeer lpInfo; AgentToCmDiskUsageStatusReport diskUsageMsg; + CmaDnFloatIpInfo floatIpInfo; } DnStatus; typedef struct DnSyncListInfo_t { @@ -1422,6 +1448,39 @@ typedef struct DatanodelocalPeer_t { uint32 peerInst; } DatanodelocalPeer; +typedef struct CmDnReportStatusMsgT { + cm_local_replconninfo local_status; + int sender_count; + BuildState build_info; + cm_sender_replconninfo sender_status[CM_MAX_SENDER_NUM]; + cm_receiver_replconninfo receive_status; + RedoStatsData parallel_redo_status; + cm_redo_stats local_redo_stats; + synchronous_standby_mode sync_standby_mode; + int send_gs_guc_time; + int dn_restart_counts; + bool arbitrateFlag; + int failoverStep; + int failoverTimeout; + int phony_dead_times; + int phony_dead_interval; + int dn_restart_counts_in_hour; + bool is_finish_redo_cmd_sent; + uint64 ckpt_redo_point; + char barrierID[BARRIERLEN]; + char query_barrierId[BARRIERLEN]; + uint64 barrierLSN; + uint64 archive_LSN; + uint64 flush_LSN; + DatanodeSyncList dnSyncList; + int32 syncDone; + uint32 arbiTime; + uint32 sendFailoverTimes; + bool is_barrier_exist; + cmTime_t printBegin; // print synclist time + DatanodelocalPeer dnLp; +} CmDnReportStatusMsg; + // need to keep consist with cm_to_ctl_instance_datanode_status typedef struct cm_instance_datanode_report_status_st { cm_local_replconninfo local_status; @@ -1454,6 +1513,7 @@ typedef struct cm_instance_datanode_report_status_st { bool is_barrier_exist; cmTime_t printBegin; // print synclist time DatanodelocalPeer dnLp; + DnFloatIpInfo floatIp; } cm_instance_datanode_report_status; typedef struct cm_instance_gtm_report_status_st { @@ -1585,7 +1645,7 @@ typedef struct cm_to_ctl_get_datanode_relation_ack_st { int member_index; cm_instance_role_status instanceMember[CM_PRIMARY_STANDBY_MAX_NUM]; cm_instance_gtm_report_status gtm_member[CM_PRIMARY_STANDBY_NUM]; - cm_instance_datanode_report_status data_node_member[CM_PRIMARY_STANDBY_MAX_NUM]; + CmDnReportStatusMsg data_node_member[CM_PRIMARY_STANDBY_MAX_NUM]; } cm_to_ctl_get_datanode_relation_ack; // need to keep consist with the struct cm_instance_datanode_report_status @@ -1970,6 +2030,11 @@ typedef struct LockResultSt { char lockName[CM_MAX_LOCK_NAME]; } LockResult; +typedef struct CmaNotifyClientSt { + bool8 isCmaConnClose; + char reserve[7]; +} CmaNotifyClient; + // cms to cma typedef struct CmsReportResStatListSt { int msgType; @@ -2060,6 +2125,11 @@ typedef struct AgentToClientResLockResultSt { LockResult result; } AgentToClientResLockResult; +typedef struct AgentToClientNotifySt { + MsgHead head; + CmaNotifyClient notify; +} AgentToClientNotify; + // client to cma typedef struct ClientHbMsgSt { MsgHead head; @@ -2098,4 +2168,20 @@ typedef struct CmsSSLConnSt { uint64 startConnTime; } CmsSSLConnMsg; +typedef struct CmFloatIpStatInfoT { + uint32 nodeId; + uint32 instId; + uint32 count; + int32 nicNetState[MAX_FLOAT_IP_COUNT]; +} CmFloatIpStatInfo; + +typedef struct CmFloatIpStatAckT { + int32 msgType; + bool8 canShow; + char reserved1[3]; // for alignment + char reserved2[52]; // the reserved + uint32 count; + CmFloatIpStatInfo info[0]; +} CmFloatIpStatAck; // the totol size is 64 + #endif diff --git a/src/include/cm/cm_server/cms_common.h b/src/include/cm/cm_server/cms_common.h index 445f060..a0a0d86 100644 --- a/src/include/cm/cm_server/cms_common.h +++ b/src/include/cm/cm_server/cms_common.h @@ -43,7 +43,6 @@ void SendSignalToAgentThreads(); extern int GetCtlThreadNum(); int UpdateDynamicConfig(); void UpdateAzNodeInfo(); -bool CheckBoolConfigParam(const char* value); void GetDdbTypeParam(void); void GetDdbArbiCfg(int32 loadWay); status_t GetMaintainPath(char *maintainFile, uint32 fileLen); diff --git a/src/include/cm/cm_server/cms_process_messages.h b/src/include/cm/cm_server/cms_process_messages.h index d6395fc..c7c2101 100644 --- a/src/include/cm/cm_server/cms_process_messages.h +++ b/src/include/cm/cm_server/cms_process_messages.h @@ -159,6 +159,8 @@ void ProcessCmRhbMsg(MsgRecvInfo* recvMsgInfo, const CmRhbMsg *rhbMsg); void ProcessResIsregMsg(MsgRecvInfo *recvMsgInfo, CmaToCmsIsregMsg *isreg); void ReleaseResLockOwner(const char *resName, uint32 instId); void ResetResNodeStat(); +void ProcessDnFloatIpMsg(MsgRecvInfo *recvMsgInfo, CmaDnFloatIpInfo *floatIp); +void GetFloatIpSet(CmFloatIpStatAck *ack, size_t maxMsgLen, size_t *curMsgLen); #ifdef ENABLE_MULTIPLE_NODES void SetCmdStautus(int32 ret); diff --git a/src/include/cm/cm_ssl_base.h b/src/include/cm/cm_ssl_base.h index e5e27cd..f4b0385 100644 --- a/src/include/cm/cm_ssl_base.h +++ b/src/include/cm/cm_ssl_base.h @@ -108,13 +108,6 @@ typedef struct st_cs_pipe { int32 l_linger; } cs_pipe_t; -#pragma pack(4) -typedef struct st_text { - char *str; - uint32 len; -} text_t; -#pragma pack() - #define MESSAGE_BUFFER_SIZE (SIZE_M(1)) #define PADDING_BUFFER_SIZE (SIZE_K(1)) #define MAX_BATCH_SIZE 500 @@ -128,19 +121,6 @@ typedef struct st_text { #define CS_INVALID_SOCKET (-1) -#define CM_TEXT_BEGIN(text) ((text)->str[0]) -#define CM_TEXT_FIRST(text) ((text)->str[0]) -#define CM_TEXT_SECOND(text) ((text)->str[1]) -#define CM_TEXT_END(text) ((text)->str[(text)->len - 1]) -#define CM_TEXT_SECONDTOLAST(text) (((text)->len >= 2) ? ((text)->str[(text)->len - 2]) : '\0') -#define CM_NULL_TERM(text) \ - { \ - (text)->str[(text)->len] = '\0'; \ - } -#define CM_IS_EMPTY(text) (((text)->str == NULL) || ((text)->len == 0)) -#define CM_IS_QUOTE_CHAR(c1) ((c1)== '\'' || (c1) == '"' || (c1) == '`') -#define CM_IS_QUOTE_STRING(c1, c2) ((c1) == (c2) && CM_IS_QUOTE_CHAR(c1)) - #define CS_WAIT_FOR_READ 1 #define CS_WAIT_FOR_WRITE 2 @@ -158,52 +138,5 @@ typedef struct st_text { #define CM_TIME_THOUSAND_UN (uint32)1000 #define CM_HANDSHAKE_TIMEOUT (uint32)600000 /* mill-seconds */ -#define cm_str_equal(str1, str2) (strcmp(str1, str2) == 0) - -/* Remove the enclosed char or the head and the tail of the text */ -#define CM_REMOVE_ENCLOSED_CHAR(text) \ - do { \ - ++((text)->str); \ - (text)->len -= 2; \ - } while (0) - -static inline void cm_assert(bool condition) -{ - if (!condition) { - *((uint32 *)NULL) = 1; - } -} - -#ifdef CM_DEBUG_VERSION -#define CM_ASSERT(expr) cm_assert((bool)(expr)) -#else -#define CM_ASSERT(expr) ((void)(expr)) -#endif - -static inline void cm_exit(int32 exitcode) -{ - _exit(exitcode); -} - -#define CM_TEXT_CLEAR(text) ((text)->len = 0) - -#define CM_FILE_NAME_BUFFER_SIZE (uint32)256 -#define CM_MAX_FILE_NAME_LEN (uint32)(CM_FILE_NAME_BUFFER_SIZE - 1) - -static inline void cm_str2text(char *str, text_t *text) -{ - text->str = str; - text->len = (str == NULL) ? 0 : (uint32)strlen(str); -} - - -#define UPPER(c) (((c) >= 'a' && (c) <= 'z') ? ((c) - 32) : (c)) -#define LOWER(c) (((c) >= 'A' && (c) <= 'Z') ? ((c) + 32) : (c)) - -#ifndef ELEMENT_COUNT -#define ELEMENT_COUNT(x) ((uint32)(sizeof(x) / sizeof((x)[0]))) -#endif - - #endif diff --git a/src/include/cm/cm_text.h b/src/include/cm/cm_text.h new file mode 100644 index 0000000..d7d603f --- /dev/null +++ b/src/include/cm/cm_text.h @@ -0,0 +1,126 @@ +/* + * 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_text.h + * + * + * IDENTIFICATION + * include/cm/cm_text.h + * + * ------------------------------------------------------------------------- + */ +#ifndef CM_TEXT_H +#define CM_TEXT_H + +#include + +#include "c.h" +#include "cm_defs.h" + +#pragma pack(4) +typedef struct st_text { + char *str; + uint32 len; +} text_t; + +typedef struct CmConstTextT { + const char *str; + uint32 len; +} CmConstText; +#pragma pack() + +#define CM_TEXT_BEGIN(text) ((text)->str[0]) +#define CM_TEXT_FIRST(text) ((text)->str[0]) +#define CM_TEXT_SECOND(text) ((text)->str[1]) +#define CM_TEXT_END(text) ((text)->str[(text)->len - 1]) +#define CM_TEXT_SECONDTOLAST(text) (((text)->len >= 2) ? ((text)->str[(text)->len - 2]) : '\0') +#define CM_NULL_TERM(text) \ + { \ + (text)->str[(text)->len] = '\0'; \ + } +#define CM_IS_EMPTY(text) (((text)->str == NULL) || ((text)->len == 0)) +#define CM_IS_QUOTE_CHAR(c1) ((c1) == '\'' || (c1) == '"' || (c1) == '`') +#define CM_IS_QUOTE_STRING(c1, c2) ((c1) == (c2) && CM_IS_QUOTE_CHAR(c1)) + +#define CM_TEXT_CLEAR(text) ((text)->len = 0) + +#define CM_FILE_NAME_BUFFER_SIZE (uint32)256 +#define CM_MAX_FILE_NAME_LEN (uint32)(CM_FILE_NAME_BUFFER_SIZE - 1) + +#define UPPER(c) (((c) >= 'a' && (c) <= 'z') ? ((c) - 32) : (c)) +#define LOWER(c) (((c) >= 'A' && (c) <= 'Z') ? ((c) + 32) : (c)) + +#ifndef ELEMENT_COUNT +#define ELEMENT_COUNT(x) ((uint32)(sizeof(x) / sizeof((x)[0]))) +#endif + +#define CM_C2D(c) ((c) - '0') + +#ifdef WIN32 +#define cm_strcmpi _strcmpi +#define cm_strcmpni _strnicmp +#define cm_strstri stristr +#else +#define cm_strcmpi strcasecmp +#define cm_strcmpni strncasecmp +#define cm_strstri strcasestr +#endif + +#define cm_compare_str(str1, str2) strcmp(str1, str2) +#define cm_compare_str_ins(str1, str2) cm_strcmpi(str1, str2) +#define cm_str_str(str1, str2) strstr(str1, str) +#define cm_str_str_ins(str1, str2) cm_strstri(str1, str2) +#define cm_str_equal(str1, str2) (strcmp(str1, str2) == 0) +#define cm_str_equal_ins(str1, str2) (cm_strcmpi(str1, str2) == 0) +#define cm_str_match(str1, str2) (strstr(str1, str2) != NULL) +#define cm_str_match_ins(str1, str2) (cm_strstri(str1, str2) != NULL) + +static inline void CmStr2Text(char *str, text_t *text) +{ + text->str = str; + text->len = (str == NULL) ? 0 : (uint32)strlen(str); +} + +static inline void CmConststr2Text(const char *str, CmConstText *text) +{ + text->str = str; + text->len = (str == NULL) ? 0 : (uint32)strlen(str); +} + +/* Remove the enclosed char or the head and the tail of the text */ +#define CM_REMOVE_ENCLOSED_CHAR(text) \ + do { \ + ++((text)->str); \ + (text)->len -= 2; \ + } while (0) + +#define CM_TEXT_EMPTY_STR_TO_NULL(str) \ + if ((str) != NULL && (str)[0] == '\0') { \ + (str) = NULL; \ + } + +void CmFetchFileName(text_t *files, text_t *name); +bool8 CmTextStrEqualIns(const text_t *text, const char *str); +bool8 CmFetchText(text_t *text, char splitChar, char encloseChar, text_t *sub); +void CmSplitText(const text_t *text, char splitChar, char encloseChar, text_t *left, text_t *right); +void CmRemoveBrackets(text_t *text); +void CmTrimText(text_t *text); +void CmLtrimText(text_t *text); +void CmRtrimText(text_t *text); +bool8 IsCmBracketText(const text_t *text); +status_t CmText2Str(const text_t *text, char *buf, uint32 bufSize); +void CmTrimStr(char *str); + +#endif