* Copyright (c) 2021 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.cpp
* cm_ctl show
*
* IDENTIFICATION
* src/cm_ctl/ctl_show.cpp
*
* -------------------------------------------------------------------------
*/
#include "ctl_show.h"
#include <time.h>
#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);
len = (uint32)strlen(dnFloatIp->floatIpName[k]);
floatIpLen->floatIpNameText.len = CM_MAX(len, floatIpLen->floatIpNameText.len);
len = (uint32)strlen(dnFloatIp->baseIp[k]);
floatIpLen->baseIpText.len = CM_MAX(len, floatIpLen->baseIpText.len);
len = (uint32)strlen(dnFloatIp->dnFloatIp[k]);
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)
{
uint32 tmpNodeLen = (uint32)(MAX_NODE_ID_LEN + SPACE_LEN + max_node_name_len + SPACE_LEN);
floatIpLen->nodeText.len = CM_MAX(tmpNodeLen, floatIpLen->nodeText.len);
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;
}
(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);
(void)fprintf(g_logFilePtr, "%u ", ack->info[i].instId);
(void)fprintf(g_logFilePtr, " ");
(void)fprintf(g_logFilePtr, "%-*s ", (floatIpLen->baseIpText.len - 1),
GetBaseIp(inst.baseInfo.nodeIdx, inst.baseInfo.instIdx, j));
(void)fprintf(g_logFilePtr, "%-*s ", (floatIpLen->floatIpNameText.len - 1),
GetFloatIpName(inst.baseInfo.nodeIdx, inst.baseInfo.instIdx, j));
(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);
CmConststr2Text("node", &(floatIpLen->nodeText));
CmConststr2Text("instance", &(floatIpLen->instText));
CmConststr2Text("base_ip", &(floatIpLen->baseIpText));
CmConststr2Text("float_ip_name", &(floatIpLen->floatIpNameText));
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_EXITCODE((CmServer_conn));
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;
}
int DoShowCommand()
{
InitCtlShowMsgFunc();
do_conn_cmserver(false, 0);
if (CmServer_conn == NULL) {
write_runlog(LOG, "show command, can't connect to cmserver.\n");
return -1;
}
CmShowStatReq req = { 0 };
req.msgType = (int)MSG_CTL_CM_RHB_STATUS_REQ;
if (cm_client_send_msg(CmServer_conn, 'C', (char*)(&req), sizeof(CmShowStatReq)) != 0) {
FINISH_CONNECTION_WITHOUT_EXITCODE((CmServer_conn));
write_runlog(ERROR, "ctl send show rhb msg to cms failed.\n");
(void)printf(_("ctl show send msg to cms failed.\n"));
return 1;
}
GetExecCmdResult(NULL, (int)MSG_CTL_CM_RHB_STATUS_ACK);
req.msgType = (int)MSG_CTL_CM_NODE_DISK_STATUS_REQ;
if (cm_client_send_msg(CmServer_conn, 'C', (char*)(&req), sizeof(CmShowStatReq)) != 0) {
FINISH_CONNECTION_WITHOUT_EXITCODE((CmServer_conn));
write_runlog(ERROR, "ctl send show node disk msg to cms failed.\n");
(void)printf(_("ctl send msg to cms failed.\n"));
return 1;
}
GetExecCmdResult(NULL, (int)MSG_CTL_CM_NODE_DISK_STATUS_ACK);
if (QueryCmsFloatIpMain() != 0) {
FINISH_CONNECTION_WITHOUT_EXITCODE((CmServer_conn));
write_runlog(ERROR, "Failed to show floatIp.\n");
return -1;
}
FINISH_CONNECTION_WITHOUT_EXITCODE((CmServer_conn));
return 0;
}
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);
struct tm result;
GetLocalTime(&ack->baseTime, &result);
const uint32 timeBufMaxLen = 128;
char timeBuf[timeBufMaxLen] = {0};
(void)strftime(timeBuf, timeBufMaxLen, "%Y-%m-%d %H:%M:%S", &result);
(void)printf("Current CMServer time: %s\n", timeBuf);
(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_RETERR_IF_NULL(rs);
(void)printf("%s\n", rs);
FREE_AND_RESET(rs);
return CM_SUCCESS;
}
static char *GetNodeDiskSimple(time_t *ndHbs, uint32 hwl, time_t baseTime, uint32 timeout)
{
const uint32 fixLen = 6;
size_t bufLen = (fixLen + 1) * hwl + 2;
char *buf = (char *)malloc(bufLen);
if (buf == NULL) {
write_runlog(ERROR, "can't alloc mem for node disk stats, needed:%u\n", (uint32)bufLen);
return NULL;
}
error_t rc = memset_s(buf, bufLen, 0, bufLen);
securec_check_errno(rc, (void)rc);
buf[strlen(buf)] = '|';
for (uint32 j = 0; j < hwl; j++) {
const char *stat = IsRhbTimeout(ndHbs[j], baseTime, (int32)timeout) ? " N |" : " Y |";
rc = strncat_s(buf, bufLen, stat, strlen(stat));
securec_check_errno(rc, (void)rc);
}
PrintRhb(ndHbs, hwl, "NodeDisk");
return buf;
}
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);
struct tm result;
GetLocalTime(&ack->baseTime, &result);
const uint32 timeBufMaxLen = 128;
char timeBuf[timeBufMaxLen] = {0};
(void)strftime(timeBuf, timeBufMaxLen, "%Y-%m-%d %H:%M:%S", &result);
(void)printf("Current CMServer time: %s\n", timeBuf);
(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_AND_RESET(rs);
return CM_SUCCESS;
}