mirror of
https://github.com/cubefs/cubefs.git
synced 2026-08-02 02:00:56 +00:00
1073 lines
46 KiB
Go
1073 lines
46 KiB
Go
// Copyright 2018 The CubeFS Authors.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
// implied. See the License for the specific language governing
|
|
// permissions and limitations under the License.
|
|
|
|
package cmd
|
|
|
|
import (
|
|
"fmt"
|
|
"math"
|
|
"strconv"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/cubefs/cubefs/proto"
|
|
"github.com/cubefs/cubefs/util/strutil"
|
|
)
|
|
|
|
func formatAddr(ipAddr string, domainAddr string) (addr string) {
|
|
if len(domainAddr) != 0 {
|
|
addr = fmt.Sprintf("%v(%v)", ipAddr, domainAddr)
|
|
} else {
|
|
addr = ipAddr
|
|
}
|
|
return
|
|
}
|
|
|
|
func formatClusterView(cv *proto.ClusterView, cn *proto.ClusterNodeInfo, cp *proto.ClusterIP) string {
|
|
sb := strings.Builder{}
|
|
sb.WriteString(fmt.Sprintf(" Cluster name : %v\n", cv.Name))
|
|
sb.WriteString(fmt.Sprintf(" Master leader : %v\n", cv.LeaderAddr))
|
|
for _, master := range cv.MasterNodes {
|
|
sb.WriteString(fmt.Sprintf(" Master-%d : %v\n", master.ID, master.Addr))
|
|
}
|
|
sb.WriteString(fmt.Sprintf(" Auto allocate : %v\n", formatEnabledDisabled(!cv.DisableAutoAlloc)))
|
|
|
|
metaNodeActiveCnt := 0
|
|
for _, node := range cv.MetaNodes {
|
|
if node.Status {
|
|
metaNodeActiveCnt += 1
|
|
}
|
|
}
|
|
sb.WriteString(fmt.Sprintf(" MetaNode count (active/total) : %v/%v\n", metaNodeActiveCnt, len(cv.MetaNodes)))
|
|
sb.WriteString(fmt.Sprintf(" MetaNode used : %v GB\n", cv.MetaNodeStatInfo.UsedGB))
|
|
sb.WriteString(fmt.Sprintf(" MetaNode available : %v GB\n", cv.MetaNodeStatInfo.AvailGB))
|
|
sb.WriteString(fmt.Sprintf(" MetaNode total : %v GB\n", cv.MetaNodeStatInfo.TotalGB))
|
|
|
|
dataNodeActiveCnt := 0
|
|
for _, node := range cv.DataNodes {
|
|
if node.Status {
|
|
dataNodeActiveCnt += 1
|
|
}
|
|
}
|
|
sb.WriteString(fmt.Sprintf(" DataNode count (active/total) : %v/%v\n", dataNodeActiveCnt, len(cv.DataNodes)))
|
|
sb.WriteString(fmt.Sprintf(" DataNode used : %v GB\n", cv.DataNodeStatInfo.UsedGB))
|
|
sb.WriteString(fmt.Sprintf(" DataNode available : %v GB\n", cv.DataNodeStatInfo.AvailGB))
|
|
sb.WriteString(fmt.Sprintf(" DataNode total : %v GB\n", cv.DataNodeStatInfo.TotalGB))
|
|
|
|
sb.WriteString(fmt.Sprintf(" Volume count : %v\n", len(cv.VolStatInfo)))
|
|
sb.WriteString(fmt.Sprintf(" Allow Mp Decomm : %v\n", formatEnabledDisabled(!cv.ForbidMpDecommission)))
|
|
sb.WriteString(fmt.Sprintf(" EbsAddr : %v\n", cp.EbsAddr))
|
|
sb.WriteString(fmt.Sprintf(" LoadFactor : %v\n", cn.LoadFactor))
|
|
sb.WriteString(fmt.Sprintf(" DpRepairTimeout : %v\n", cv.DpRepairTimeout))
|
|
sb.WriteString(fmt.Sprintf(" DataPartitionTimeout : %v\n", cv.DpTimeout))
|
|
sb.WriteString(fmt.Sprintf(" volDeletionDelayTime : %v h\n", cv.VolDeletionDelayTimeHour))
|
|
sb.WriteString(fmt.Sprintf(" EnableAutoDecommission : %v\n", cv.EnableAutoDecommission))
|
|
sb.WriteString(fmt.Sprintf(" AutoDecommissionDiskInterval : %v\n", cv.AutoDecommissionDiskInterval))
|
|
sb.WriteString(fmt.Sprintf(" EnableAutoDpMetaRepair : %v\n", cv.EnableAutoDpMetaRepair))
|
|
sb.WriteString(fmt.Sprintf(" AutoDpMetaRepairParallelCnt : %v\n", cv.AutoDpMetaRepairParallelCnt))
|
|
sb.WriteString(fmt.Sprintf(" MarkDiskBrokenThreshold : %v\n", strutil.FormatPercent(cv.MarkDiskBrokenThreshold)))
|
|
sb.WriteString(fmt.Sprintf(" DecommissionDpLimit : %v\n", cv.DecommissionLimit))
|
|
sb.WriteString(fmt.Sprintf(" DecommissionDiskLimit : %v\n", cv.DecommissionDiskLimit))
|
|
sb.WriteString(fmt.Sprintf(" DpBackupTimeout : %v\n", cv.DpBackupTimeout))
|
|
return sb.String()
|
|
}
|
|
|
|
var (
|
|
statInfoTablePattern = " %-15v %-15v %-15v %-15v\n"
|
|
statInfoTableHeader = fmt.Sprintf(statInfoTablePattern,
|
|
"TOTAL/GB", "USED/GB", "INCREASED/GB", "USED RATIO")
|
|
zoneStatInfoTablePattern = " %-10v %-10v %-15v %-15v %-15v %-15v %-10v %-10v\n"
|
|
zoneStatInfoTableHeader = fmt.Sprintf(zoneStatInfoTablePattern,
|
|
"ZONE NAME", "ROLE", "TOTAL/GB", "USED/GB", "AVAILABLE/GB ", "USED RATIO", "TOTAL NODES", "WRITEBLE NODES")
|
|
)
|
|
|
|
func formatClusterStat(cs *proto.ClusterStatInfo) string {
|
|
sb := strings.Builder{}
|
|
sb.WriteString("\n")
|
|
sb.WriteString("DataNode Status:\n")
|
|
sb.WriteString(statInfoTableHeader)
|
|
sb.WriteString(fmt.Sprintf(statInfoTablePattern, cs.DataNodeStatInfo.TotalGB, cs.DataNodeStatInfo.UsedGB, cs.DataNodeStatInfo.IncreasedGB, cs.DataNodeStatInfo.UsedRatio))
|
|
sb.WriteString("\n")
|
|
sb.WriteString("MetaNode Status:\n")
|
|
sb.WriteString(statInfoTableHeader)
|
|
sb.WriteString(fmt.Sprintf(statInfoTablePattern, cs.MetaNodeStatInfo.TotalGB, cs.MetaNodeStatInfo.UsedGB, cs.MetaNodeStatInfo.IncreasedGB, cs.MetaNodeStatInfo.UsedRatio))
|
|
sb.WriteString("\n")
|
|
sb.WriteString("Zone List:\n")
|
|
sb.WriteString(zoneStatInfoTableHeader)
|
|
for zoneName, zoneStat := range cs.ZoneStatInfo {
|
|
sb.WriteString(fmt.Sprintf(zoneStatInfoTablePattern, zoneName, "DATANODE", zoneStat.DataNodeStat.Total, zoneStat.DataNodeStat.Used, zoneStat.DataNodeStat.Avail, zoneStat.DataNodeStat.UsedRatio, zoneStat.DataNodeStat.TotalNodes, zoneStat.DataNodeStat.WritableNodes))
|
|
sb.WriteString(fmt.Sprintf(zoneStatInfoTablePattern, "", "METANODE", zoneStat.MetaNodeStat.Total, zoneStat.MetaNodeStat.Used, zoneStat.MetaNodeStat.Avail, zoneStat.MetaNodeStat.UsedRatio, zoneStat.MetaNodeStat.TotalNodes, zoneStat.MetaNodeStat.WritableNodes))
|
|
}
|
|
return sb.String()
|
|
}
|
|
|
|
var nodeViewTableRowPattern = "%-6v %-65v %-8v %-8v %-8v"
|
|
|
|
func formatNodeViewTableHeader() string {
|
|
return fmt.Sprintf(nodeViewTableRowPattern, "ID", "ADDRESS", "WRITABLE", "ACTIVE", "MEDIA")
|
|
}
|
|
|
|
func formatNodeView(view *proto.NodeView, tableRow bool) string {
|
|
if tableRow {
|
|
return fmt.Sprintf(nodeViewTableRowPattern, view.ID, formatAddr(view.Addr, view.DomainAddr),
|
|
formatYesNo(view.IsWritable), formatNodeStatus(view.Status), formatNodeMediaType(view.MediaType))
|
|
}
|
|
sb := strings.Builder{}
|
|
sb.WriteString(fmt.Sprintf(" ID : %v\n", view.ID))
|
|
sb.WriteString(fmt.Sprintf(" Address : %v\n", formatAddr(view.Addr, view.DomainAddr)))
|
|
sb.WriteString(fmt.Sprintf(" Writable: %v\n", formatYesNo(view.IsWritable)))
|
|
sb.WriteString(fmt.Sprintf(" Active : %v", formatNodeStatus(view.Status)))
|
|
sb.WriteString(fmt.Sprintf(" MEDIA : %v", formatNodeMediaType(view.MediaType)))
|
|
return sb.String()
|
|
}
|
|
|
|
var nodeViewTableRowPatternForNodeSet = "%-6v %-65v %-8v %-8v %-10v %-10v %-10v"
|
|
|
|
func formatNodeViewTableHeaderForNodeSet() string {
|
|
return fmt.Sprintf(nodeViewTableRowPatternForNodeSet, "ID", "ADDRESS", "WRITABLE", "STATUS", "TOTAL", "USED", "AVAIL")
|
|
}
|
|
|
|
func formatNodeViewForNodeSet(view *proto.NodeStatView) string {
|
|
return fmt.Sprintf(nodeViewTableRowPatternForNodeSet, view.ID, formatAddr(view.Addr, view.DomainAddr),
|
|
formatYesNo(view.IsWritable), formatNodeStatus(view.Status),
|
|
formatSize(view.Total),
|
|
formatSize(view.Used),
|
|
formatSize(view.Avail))
|
|
}
|
|
|
|
func formatSimpleVolView(svv *proto.SimpleVolView) string {
|
|
sb := strings.Builder{}
|
|
sb.WriteString(fmt.Sprintf(" ID : %v\n", svv.ID))
|
|
sb.WriteString(fmt.Sprintf(" Name : %v\n", svv.Name))
|
|
sb.WriteString(fmt.Sprintf(" Owner : %v\n", svv.Owner))
|
|
sb.WriteString(fmt.Sprintf(" Authenticate : %v\n", formatEnabledDisabled(svv.Authenticate)))
|
|
sb.WriteString(fmt.Sprintf(" Capacity : %v GB\n", svv.Capacity))
|
|
sb.WriteString(fmt.Sprintf(" Create time : %v\n", svv.CreateTime))
|
|
sb.WriteString(fmt.Sprintf(" DeleteLockTime : %v\n", svv.DeleteLockTime))
|
|
sb.WriteString(fmt.Sprintf(" Cross zone : %v\n", formatEnabledDisabled(svv.CrossZone)))
|
|
sb.WriteString(fmt.Sprintf(" DefaultPriority : %v\n", svv.DefaultPriority))
|
|
sb.WriteString(fmt.Sprintf(" Dentry count : %v\n", svv.DentryCount))
|
|
sb.WriteString(fmt.Sprintf(" Description : %v\n", string([]rune(svv.Description)[:])))
|
|
sb.WriteString(fmt.Sprintf(" DpCnt : %v\n", svv.DpCnt))
|
|
sb.WriteString(fmt.Sprintf(" DpReplicaNum : %v\n", svv.DpReplicaNum))
|
|
sb.WriteString(fmt.Sprintf(" Follower read : %v\n", formatEnabledDisabled(svv.FollowerRead)))
|
|
sb.WriteString(fmt.Sprintf(" Inode count : %v\n", svv.InodeCount))
|
|
sb.WriteString(fmt.Sprintf(" Max metaPartition ID : %v\n", svv.MaxMetaPartitionID))
|
|
sb.WriteString(fmt.Sprintf(" MpCnt : %v\n", svv.MpCnt))
|
|
sb.WriteString(fmt.Sprintf(" MpReplicaNum : %v\n", svv.MpReplicaNum))
|
|
sb.WriteString(fmt.Sprintf(" NeedToLowerReplica : %v\n", formatEnabledDisabled(svv.NeedToLowerReplica)))
|
|
sb.WriteString(fmt.Sprintf(" RwDpCnt : %v\n", svv.RwDpCnt))
|
|
sb.WriteString(fmt.Sprintf(" Status : %v\n", formatVolumeStatus(svv.Status)))
|
|
sb.WriteString(fmt.Sprintf(" ZoneName : %v\n", svv.ZoneName))
|
|
sb.WriteString(fmt.Sprintf(" VolType : %v\n", svv.VolType))
|
|
sb.WriteString(fmt.Sprintf(" DpReadOnlyWhenVolFull : %v\n", svv.DpReadOnlyWhenVolFull))
|
|
sb.WriteString(fmt.Sprintf(" Transaction Mask : %v\n", svv.EnableTransactionV1))
|
|
sb.WriteString(fmt.Sprintf(" Transaction timeout : %v\n", svv.TxTimeout))
|
|
sb.WriteString(fmt.Sprintf(" Tx conflict retry num : %v\n", svv.TxConflictRetryNum))
|
|
sb.WriteString(fmt.Sprintf(" Tx conflict retry interval(ms) : %v\n", svv.TxConflictRetryInterval))
|
|
sb.WriteString(fmt.Sprintf(" Tx limit interval(s) : %v\n", svv.TxOpLimit))
|
|
sb.WriteString(fmt.Sprintf(" Forbidden : %v\n", svv.Forbidden))
|
|
sb.WriteString(fmt.Sprintf(" DisableAuditLog : %v\n", svv.DisableAuditLog))
|
|
sb.WriteString(fmt.Sprintf(" TrashInterval : %v\n", time.Duration(svv.TrashInterval)*time.Minute))
|
|
sb.WriteString(fmt.Sprintf(" DpRepairBlockSize : %v\n", strutil.FormatSize(svv.DpRepairBlockSize)))
|
|
sb.WriteString(fmt.Sprintf(" EnableAutoDpMetaRepair : %v\n", svv.EnableAutoDpMetaRepair))
|
|
sb.WriteString(fmt.Sprintf(" Quota : %v\n", formatEnabledDisabled(svv.EnableQuota)))
|
|
sb.WriteString(fmt.Sprintf(" AccessTimeValidInterval : %v\n", time.Duration(svv.AccessTimeInterval)*time.Second))
|
|
sb.WriteString(fmt.Sprintf(" EnablePersistAccessTime : %v\n", svv.EnablePersistAccessTime))
|
|
if svv.Forbidden && svv.Status == 1 {
|
|
sb.WriteString(fmt.Sprintf(" DeleteDelayTime : %v\n", time.Until(svv.DeleteExecTime)))
|
|
}
|
|
allowedStorageClassStr := make([]string, 0)
|
|
for _, asc := range svv.AllowedStorageClass {
|
|
allowedStorageClassStr = append(allowedStorageClassStr, proto.StorageClassString(asc))
|
|
}
|
|
sb.WriteString(fmt.Sprintf(" VolStorageClass : %v\n", proto.StorageClassString(svv.VolStorageClass)))
|
|
sb.WriteString(fmt.Sprintf(" AllowedStorageClass : %v\n", allowedStorageClassStr))
|
|
sb.WriteString(fmt.Sprintf(" CacheDpStorageClass : %v\n", proto.StorageClassString(svv.CacheDpStorageClass)))
|
|
|
|
if svv.VolType == 1 {
|
|
sb.WriteString(fmt.Sprintf(" ObjBlockSize : %v byte\n", svv.ObjBlockSize))
|
|
sb.WriteString(fmt.Sprintf(" CacheCapacity : %v G\n", svv.CacheCapacity))
|
|
sb.WriteString(fmt.Sprintf(" CacheAction : %v\n", svv.CacheAction))
|
|
sb.WriteString(fmt.Sprintf(" CacheThreshold : %v byte\n", svv.CacheThreshold))
|
|
sb.WriteString(fmt.Sprintf(" CacheLruInterval : %v min\n", svv.CacheLruInterval))
|
|
sb.WriteString(fmt.Sprintf(" CacheTtl : %v day\n", svv.CacheTtl))
|
|
sb.WriteString(fmt.Sprintf(" CacheLowWater : %v\n", svv.CacheLowWater))
|
|
sb.WriteString(fmt.Sprintf(" CacheHighWater : %v\n", svv.CacheHighWater))
|
|
sb.WriteString(fmt.Sprintf(" CacheRule : %v\n", svv.CacheRule))
|
|
}
|
|
return sb.String()
|
|
}
|
|
|
|
func formatVolumeStatus(status uint8) string {
|
|
switch status {
|
|
case 0:
|
|
return "Normal"
|
|
case 1:
|
|
return "Marked delete"
|
|
default:
|
|
return "Unknown"
|
|
}
|
|
}
|
|
|
|
var (
|
|
volumeInfoTablePattern = "%-63v %-20v %-8v %-8v %-8v %-10v"
|
|
volumeInfoTableHeader = fmt.Sprintf(volumeInfoTablePattern, "VOLUME", "OWNER", "USED", "TOTAL", "STATUS", "CREATE TIME")
|
|
)
|
|
|
|
func formatVolInfoTableRow(vi *proto.VolInfo) string {
|
|
return fmt.Sprintf(volumeInfoTablePattern,
|
|
vi.Name, vi.Owner, formatSize(vi.UsedSize), formatSize(vi.TotalSize),
|
|
formatVolumeStatus(vi.Status), time.Unix(vi.CreateTime, 0).Local().Format(time.RFC1123))
|
|
}
|
|
|
|
var (
|
|
volumeVersionPattern = "%-20v %-40v %-8v %-8v"
|
|
volumeVersionTableHeader = fmt.Sprintf(volumeVersionPattern, "VER", "CTIME", "STATUS", "OTHER")
|
|
)
|
|
|
|
var (
|
|
volumeAclPattern = "%-20v %-40v %-8v"
|
|
volumeAclTableHeader = fmt.Sprintf(volumeAclPattern, "IP", "CTIME", "OTHER")
|
|
)
|
|
|
|
func formatAclInfoTableRow(aclInfo *proto.AclIpInfo) string {
|
|
return fmt.Sprintf(volumeAclPattern,
|
|
aclInfo.Ip, time.Unix(aclInfo.CTime, 0).Format(time.RFC1123), "")
|
|
}
|
|
|
|
var (
|
|
volumeUidPattern = "%-20v %-40v %-8v %-8v %-8v %-8v"
|
|
volumeUidTableHeader = fmt.Sprintf(volumeUidPattern, "UID", "CTIME", "ENABLED", "LIMITED", "LIMITSIZE", "USED")
|
|
)
|
|
|
|
func formatUidInfoTableRow(uidInfo *proto.UidSpaceInfo) string {
|
|
return fmt.Sprintf(volumeUidPattern,
|
|
uidInfo.Uid, time.Unix(uidInfo.CTime, 0).Format(time.RFC1123), uidInfo.Enabled, uidInfo.Limited, uidInfo.LimitSize, uidInfo.UsedSize)
|
|
}
|
|
|
|
func formatVerInfoTableRow(verInfo *proto.VolVersionInfo) string {
|
|
return fmt.Sprintf(volumeVersionPattern,
|
|
verInfo.Ver, time.UnixMicro(int64(verInfo.Ver)).Local().Format(time.RFC1123), verInfo.Status, "")
|
|
}
|
|
|
|
var (
|
|
dataPartitionTablePattern = "%-8v %-8v %-10v %-10v %-10v %-18v %-18v"
|
|
dataPartitionTableHeader = fmt.Sprintf(dataPartitionTablePattern,
|
|
"ID", "REPLICAS", "STATUS", "ISRECOVER", "MEDIA", "LEADER", "MEMBERS")
|
|
)
|
|
|
|
func formatDataPartitionTableRow(view *proto.DataPartitionResponse) string {
|
|
return fmt.Sprintf(dataPartitionTablePattern,
|
|
view.PartitionID, view.ReplicaNum, formatDataPartitionStatus(view.Status), view.IsRecover,
|
|
proto.MediaTypeString(view.MediaType), view.LeaderAddr, strings.Join(view.Hosts, ","))
|
|
}
|
|
|
|
var (
|
|
partitionInfoTablePattern = "%-8v %-8v %-10v %-12v %-12v %-18v"
|
|
partitionInfoTableHeader = fmt.Sprintf(partitionInfoTablePattern,
|
|
"ID", "VOLUME", "REPLICAS", "STATUS", "MediaType", "MEMBERS")
|
|
|
|
badReplicaPartitionInfoTablePattern = "%-8v %-8v %-8v %-8v %-24v %-24v"
|
|
badReplicaPartitionInfoTableHeader = fmt.Sprintf(badReplicaPartitionInfoTablePattern,
|
|
"ID", "VOLUME", "REPLICAS", "STATUS", "MEMBERS", "UNAVAILABLE_REPLICAS")
|
|
|
|
repFileCountDifferPartitionInfoTablePattern = "%-8v %-8v %-8v %-8v %-24v"
|
|
RepFileCountDifferInfoTableHeader = fmt.Sprintf(repFileCountDifferPartitionInfoTablePattern,
|
|
"DP_ID", "VOLUME", "REPLICAS", "DP_STATUS", "MEMBERS(fileCount)")
|
|
|
|
repUsedSizeDifferPartitionInfoTablePattern = "%-8v %-8v %-8v %-8v %-24v"
|
|
RepUsedSizeDifferInfoTableHeader = fmt.Sprintf(repUsedSizeDifferPartitionInfoTablePattern,
|
|
"DP_ID", "VOLUME", "REPLICAS", "DP_STATUS", "MEMBERS(usedSize)")
|
|
|
|
inodeCountNotEqualInfoTablePattern = "%-8v %-8v %-8v %-8v %-24v"
|
|
inodeCountNotEqualInfoTableHeader = fmt.Sprintf(inodeCountNotEqualInfoTablePattern,
|
|
"ID", "VOLUME", "REPLICAS", "STATUS", "MEMBERS(inodeCount)")
|
|
maxInodeNotEqualInfoTableHeader = fmt.Sprintf(inodeCountNotEqualInfoTablePattern,
|
|
"ID", "VOLUME", "REPLICAS", "STATUS", "MEMBERS(maxInode)")
|
|
|
|
dentryCountNotEqualInfoTablePattern = "%-8v %-8v %-8v %-8v %-24v"
|
|
dentryCountNotEqualInfoTableHeader = fmt.Sprintf(dentryCountNotEqualInfoTablePattern,
|
|
"ID", "VOLUME", "REPLICAS", "STATUS", "MEMBERS(dentryCount)")
|
|
|
|
diskErrorReplicaPartitionInfoTablePattern = "%-8v %-8v %-8v %-8v %-24v %-24v"
|
|
diskErrorReplicaPartitionInfoTableHeader = fmt.Sprintf(badReplicaPartitionInfoTablePattern,
|
|
"DP_ID", "VOLUME", "REPLICAS", "DP_STATUS", "MEMBERS", "DiskError_REPLICAS")
|
|
)
|
|
|
|
func formatDataPartitionInfoRow(partition *proto.DataPartitionInfo) string {
|
|
return fmt.Sprintf(partitionInfoTablePattern, partition.PartitionID, partition.VolName, partition.ReplicaNum,
|
|
formatDataPartitionStatus(partition.Status), proto.MediaTypeString(partition.MediaType), strings.Join(partition.Hosts, ", "))
|
|
}
|
|
|
|
func formatBadReplicaDpInfoRow(partition *proto.DataPartitionInfo) string {
|
|
sb := strings.Builder{}
|
|
sb.WriteString("[")
|
|
firstItem := true
|
|
for _, replica := range partition.Replicas {
|
|
if replica.Status == proto.Unavailable {
|
|
if !firstItem {
|
|
sb.WriteString(",")
|
|
}
|
|
|
|
sb.WriteString(fmt.Sprintf("%v", replica.Addr))
|
|
firstItem = false
|
|
}
|
|
}
|
|
sb.WriteString("]")
|
|
return fmt.Sprintf(badReplicaPartitionInfoTablePattern, partition.PartitionID, partition.VolName, partition.ReplicaNum,
|
|
formatDataPartitionStatus(partition.Status), "["+strings.Join(partition.Hosts, ", ")+"]", sb.String())
|
|
}
|
|
|
|
func formatReplicaFileCountDiffDpInfoRow(partition *proto.DataPartitionInfo) string {
|
|
sb := strings.Builder{}
|
|
sb.WriteString("[")
|
|
firstItem := true
|
|
for _, replica := range partition.Replicas {
|
|
if !firstItem {
|
|
sb.WriteString(",")
|
|
}
|
|
|
|
if replica.IsLeader {
|
|
sb.WriteString(fmt.Sprintf("%v(%v isLeader)", replica.Addr, replica.FileCount))
|
|
} else {
|
|
sb.WriteString(fmt.Sprintf("%v(%v)", replica.Addr, replica.FileCount))
|
|
}
|
|
firstItem = false
|
|
}
|
|
sb.WriteString("]")
|
|
return fmt.Sprintf(repFileCountDifferPartitionInfoTablePattern, partition.PartitionID, partition.VolName, partition.ReplicaNum,
|
|
formatDataPartitionStatus(partition.Status), sb.String())
|
|
}
|
|
|
|
func formatReplicaSizeDiffDpInfoRow(partition *proto.DataPartitionInfo) string {
|
|
sb := strings.Builder{}
|
|
sb.WriteString("[")
|
|
firstItem := true
|
|
for _, replica := range partition.Replicas {
|
|
if !firstItem {
|
|
sb.WriteString(",")
|
|
}
|
|
|
|
if replica.IsLeader {
|
|
sb.WriteString(fmt.Sprintf("%v(%v isLeader)", replica.Addr, replica.Used))
|
|
} else {
|
|
sb.WriteString(fmt.Sprintf("%v(%v)", replica.Addr, replica.Used))
|
|
}
|
|
firstItem = false
|
|
}
|
|
sb.WriteString("]")
|
|
return fmt.Sprintf(repUsedSizeDifferPartitionInfoTablePattern, partition.PartitionID, partition.VolName, partition.ReplicaNum,
|
|
formatDataPartitionStatus(partition.Status), sb.String())
|
|
}
|
|
|
|
func formatMetaPartitionReplicaInodeNotEqualInfoRow(partition *proto.MetaPartitionInfo) string {
|
|
sb := strings.Builder{}
|
|
sb.WriteString("[")
|
|
firstItem := true
|
|
for _, replica := range partition.Replicas {
|
|
if !firstItem {
|
|
sb.WriteString(",")
|
|
}
|
|
|
|
if replica.IsLeader {
|
|
sb.WriteString(fmt.Sprintf("%v(%v isLeader)", replica.Addr, replica.InodeCount))
|
|
} else {
|
|
sb.WriteString(fmt.Sprintf("%v(%v)", replica.Addr, replica.InodeCount))
|
|
}
|
|
firstItem = false
|
|
}
|
|
sb.WriteString("]")
|
|
return fmt.Sprintf(inodeCountNotEqualInfoTablePattern, partition.PartitionID, partition.VolName, partition.ReplicaNum,
|
|
formatDataPartitionStatus(partition.Status), sb.String())
|
|
}
|
|
|
|
func formatMetaPartitionReplicaDentryNotEqualInfoRow(partition *proto.MetaPartitionInfo) string {
|
|
sb := strings.Builder{}
|
|
sb.WriteString("[")
|
|
firstItem := true
|
|
for _, replica := range partition.Replicas {
|
|
if !firstItem {
|
|
sb.WriteString(",")
|
|
}
|
|
|
|
if replica.IsLeader {
|
|
sb.WriteString(fmt.Sprintf("%v(%v isLeader)", replica.Addr, replica.DentryCount))
|
|
} else {
|
|
sb.WriteString(fmt.Sprintf("%v(%v)", replica.Addr, replica.DentryCount))
|
|
}
|
|
firstItem = false
|
|
}
|
|
sb.WriteString("]")
|
|
return fmt.Sprintf(dentryCountNotEqualInfoTablePattern, partition.PartitionID, partition.VolName, partition.ReplicaNum,
|
|
formatDataPartitionStatus(partition.Status), sb.String())
|
|
}
|
|
|
|
func formatMetaPartitionInfoRow(partition *proto.MetaPartitionInfo) string {
|
|
return fmt.Sprintf(partitionInfoTablePattern,
|
|
partition.PartitionID, partition.VolName, partition.ReplicaNum,
|
|
formatDataPartitionStatus(partition.Status), "N/A", strings.Join(partition.Hosts, ", "))
|
|
}
|
|
|
|
func formatBadReplicaMpInfoRow(partition *proto.MetaPartitionInfo) string {
|
|
sb := strings.Builder{}
|
|
sb.WriteString("[")
|
|
firstItem := true
|
|
for _, replica := range partition.Replicas {
|
|
if replica.Status == proto.Unavailable {
|
|
if !firstItem {
|
|
sb.WriteString(", ")
|
|
}
|
|
|
|
sb.WriteString(fmt.Sprintf("%v", replica.Addr))
|
|
firstItem = false
|
|
}
|
|
}
|
|
sb.WriteString("]")
|
|
if sb.String() == "[]" {
|
|
return ""
|
|
}
|
|
return fmt.Sprintf(badReplicaPartitionInfoTablePattern, partition.PartitionID, partition.VolName, partition.ReplicaNum,
|
|
formatDataPartitionStatus(partition.Status), "["+strings.Join(partition.Hosts, ", ")+"]", sb.String())
|
|
}
|
|
|
|
func formatDataPartitionInfo(partition *proto.DataPartitionInfo) string {
|
|
sb := strings.Builder{}
|
|
sb.WriteString("\n")
|
|
sb.WriteString(fmt.Sprintf("volume name : %v\n", partition.VolName))
|
|
sb.WriteString(fmt.Sprintf("volume ID : %v\n", partition.VolID))
|
|
sb.WriteString(fmt.Sprintf("PartitionID : %v\n", partition.PartitionID))
|
|
sb.WriteString(fmt.Sprintf("PartitionType : %v\n", partition.PartitionType))
|
|
sb.WriteString(fmt.Sprintf("Status : %v\n", formatDataPartitionStatus(partition.Status)))
|
|
sb.WriteString(fmt.Sprintf("LastLoadedTime: %v\n", formatTime(partition.LastLoadedTime)))
|
|
sb.WriteString(fmt.Sprintf("OfflinePeerID : %v\n", partition.OfflinePeerID))
|
|
sb.WriteString(fmt.Sprintf("ISRdOnly : %v\n", partition.RdOnly))
|
|
sb.WriteString(fmt.Sprintf("IsDiscard : %v\n", partition.IsDiscard))
|
|
sb.WriteString(fmt.Sprintf("ReplicaNum : %v\n", partition.ReplicaNum))
|
|
sb.WriteString(fmt.Sprintf("Forbidden : %v\n", partition.Forbidden))
|
|
sb.WriteString(fmt.Sprintf("MediaType : %v\n", proto.MediaTypeString(partition.MediaType)))
|
|
sb.WriteString("Replicas : \n")
|
|
sb.WriteString(fmt.Sprintf("%v\n", formatDataReplicaTableHeader()))
|
|
for idx, replica := range partition.Replicas {
|
|
sb.WriteString(fmt.Sprintf("%v\n", formatDataReplica(idx, replica, true)))
|
|
}
|
|
|
|
sb.WriteString("\n")
|
|
sb.WriteString("FileInCoreMap : \n")
|
|
sb.WriteString(fmt.Sprintf("%v\n", formatDataFileInCoreTableHeader()))
|
|
sb.WriteString(fmt.Sprintf("%v\n", formatDataFileMetadateTableHeader()))
|
|
for id, fileCore := range partition.FileInCoreMap {
|
|
sb.WriteString(formatDataFileInCoreMap(id, "", fileCore, true))
|
|
}
|
|
|
|
sb.WriteString("\n")
|
|
sb.WriteString("Peers :\n")
|
|
sb.WriteString(fmt.Sprintf("%v\n", formatPeerTableHeader()))
|
|
for _, peer := range partition.Peers {
|
|
sb.WriteString(fmt.Sprintf("%v\n", formatPeer(peer)))
|
|
}
|
|
sb.WriteString("\n")
|
|
sb.WriteString("Hosts :\n")
|
|
for _, host := range partition.Hosts {
|
|
sb.WriteString(fmt.Sprintf(" [%v]", host))
|
|
}
|
|
sb.WriteString("\n")
|
|
sb.WriteString("Zones :\n")
|
|
for _, zone := range partition.Zones {
|
|
sb.WriteString(fmt.Sprintf(" [%v]", zone))
|
|
}
|
|
sb.WriteString("\n")
|
|
sb.WriteString("NodeSets :\n")
|
|
for _, nodeSet := range partition.NodeSets {
|
|
sb.WriteString(fmt.Sprintf(" [%v]", nodeSet))
|
|
}
|
|
sb.WriteString("\n")
|
|
sb.WriteString("\n")
|
|
sb.WriteString("MissingNodes :\n")
|
|
for partitionHost, id := range partition.MissingNodes {
|
|
sb.WriteString(fmt.Sprintf(" [%v, %v]\n", partitionHost, id))
|
|
}
|
|
sb.WriteString("FilesWithMissingReplica : \n")
|
|
for file, id := range partition.FilesWithMissingReplica {
|
|
sb.WriteString(fmt.Sprintf(" [%v, %v]\n", file, id))
|
|
}
|
|
return sb.String()
|
|
}
|
|
|
|
func formatMetaPartitionInfo(partition *proto.MetaPartitionInfo) string {
|
|
sb := strings.Builder{}
|
|
sb.WriteString("\n")
|
|
sb.WriteString(fmt.Sprintf("volume name : %v\n", partition.VolName))
|
|
sb.WriteString(fmt.Sprintf("PartitionID : %v\n", partition.PartitionID))
|
|
sb.WriteString(fmt.Sprintf("Status : %v\n", formatMetaPartitionStatus(partition.Status)))
|
|
sb.WriteString(fmt.Sprintf("Recovering : %v\n", formatIsRecover(partition.IsRecover)))
|
|
sb.WriteString(fmt.Sprintf("Start : %v\n", partition.Start))
|
|
sb.WriteString(fmt.Sprintf("End : %v\n", partition.End))
|
|
sb.WriteString(fmt.Sprintf("MaxInodeID : %v\n", partition.MaxInodeID))
|
|
sb.WriteString(fmt.Sprintf("Forbidden : %v\n", partition.Forbidden))
|
|
sb.WriteString("\n")
|
|
sb.WriteString("Replicas : \n")
|
|
sb.WriteString(fmt.Sprintf("%v\n", formatMetaReplicaTableHeader()))
|
|
for _, replica := range partition.Replicas {
|
|
sb.WriteString(fmt.Sprintf("%v\n", formatMetaReplica("", replica, true)))
|
|
}
|
|
sb.WriteString("\n")
|
|
sb.WriteString("Peers :\n")
|
|
for _, peer := range partition.Peers {
|
|
sb.WriteString(fmt.Sprintf("%v\n", formatPeer(peer)))
|
|
}
|
|
sb.WriteString("\n")
|
|
sb.WriteString("Hosts :\n")
|
|
for _, host := range partition.Hosts {
|
|
sb.WriteString(fmt.Sprintf(" [%v]", host))
|
|
}
|
|
sb.WriteString("\n")
|
|
sb.WriteString("Zones :\n")
|
|
for _, zone := range partition.Zones {
|
|
sb.WriteString(fmt.Sprintf(" [%v]", zone))
|
|
}
|
|
sb.WriteString("\n")
|
|
sb.WriteString("NodeSets :\n")
|
|
for _, nodeSet := range partition.NodeSets {
|
|
sb.WriteString(fmt.Sprintf(" [%v]", nodeSet))
|
|
}
|
|
sb.WriteString("\n")
|
|
sb.WriteString("\n")
|
|
sb.WriteString("MissingNodes :\n")
|
|
for partitionHost, id := range partition.MissNodes {
|
|
sb.WriteString(fmt.Sprintf(" [%v, %v]\n", partitionHost, id))
|
|
}
|
|
return sb.String()
|
|
}
|
|
|
|
var (
|
|
metaPartitionTablePattern = "%-8v %-12v %-10v %-12v %-12v %-12v %-8v %-12v %-18v"
|
|
metaPartitionTableHeader = fmt.Sprintf(metaPartitionTablePattern,
|
|
"ID", "MAX INODE", "DENTRY COUNT", "INODE COUNT", "START", "END", "STATUS", "LEADER", "MEMBERS")
|
|
)
|
|
|
|
func formatMetaPartitionTableRow(view *proto.MetaPartitionView) string {
|
|
rangeToString := func(num uint64) string {
|
|
if num >= math.MaxInt64 {
|
|
return "unlimited"
|
|
}
|
|
return strconv.FormatUint(num, 10)
|
|
}
|
|
return fmt.Sprintf(metaPartitionTablePattern,
|
|
view.PartitionID, view.MaxInodeID, view.DentryCount, view.InodeCount, view.Start, rangeToString(view.End), formatMetaPartitionStatus(view.Status),
|
|
view.LeaderAddr, strings.Join(view.Members, ","))
|
|
}
|
|
|
|
var (
|
|
userInfoTablePattern = "%-20v %-6v %-16v %-32v %-10v"
|
|
userInfoTableHeader = fmt.Sprintf(userInfoTablePattern,
|
|
"ID", "TYPE", "ACCESS KEY", "SECRET KEY", "CREATE TIME")
|
|
)
|
|
|
|
func formatUserInfoTableRow(userInfo *proto.UserInfo) string {
|
|
return fmt.Sprintf(userInfoTablePattern,
|
|
userInfo.UserID, formatUserType(userInfo.UserType), userInfo.AccessKey, userInfo.SecretKey, userInfo.CreateTime)
|
|
}
|
|
|
|
func formatDataPartitionStatus(status int8) string {
|
|
switch status {
|
|
case proto.Recovering:
|
|
return "Recovering"
|
|
case proto.ReadOnly:
|
|
return "ReadOnly"
|
|
case proto.ReadWrite:
|
|
return "ReadWrite"
|
|
case proto.Unavailable:
|
|
return "Unavailable"
|
|
default:
|
|
return "Unknown"
|
|
}
|
|
}
|
|
|
|
func formatIsRecover(isRecover bool) string {
|
|
switch isRecover {
|
|
case true:
|
|
return "Yes"
|
|
default:
|
|
return "No"
|
|
}
|
|
}
|
|
|
|
func formatMetaPartitionStatus(status int8) string {
|
|
switch status {
|
|
case 1:
|
|
return "Read only"
|
|
case 2:
|
|
return "Writable"
|
|
case -1:
|
|
return "Unavailable"
|
|
default:
|
|
return "Unknown"
|
|
}
|
|
}
|
|
|
|
func formatUserType(userType proto.UserType) string {
|
|
switch userType {
|
|
case proto.UserTypeRoot:
|
|
return "Root"
|
|
case proto.UserTypeAdmin:
|
|
return "Admin"
|
|
case proto.UserTypeNormal:
|
|
return "Normal"
|
|
default:
|
|
}
|
|
return "Unknown"
|
|
}
|
|
|
|
func formatYesNo(b bool) string {
|
|
if b {
|
|
return "Yes"
|
|
}
|
|
return "No"
|
|
}
|
|
|
|
func formatEnabledDisabled(b bool) string {
|
|
if b {
|
|
return "Enabled"
|
|
}
|
|
return "Disabled"
|
|
}
|
|
|
|
func formatNodeStatus(status bool) string {
|
|
if status {
|
|
return "Active"
|
|
}
|
|
return "Inactive"
|
|
}
|
|
|
|
func formatNodeOfflineStatus(status bool) string {
|
|
if status {
|
|
return "True"
|
|
}
|
|
return "False"
|
|
}
|
|
|
|
func formatNodeMediaType(mediaType uint32) string {
|
|
if mediaType == proto.MediaType_Unspecified {
|
|
return "N/A"
|
|
}
|
|
return proto.MediaTypeString(mediaType)
|
|
}
|
|
|
|
var (
|
|
units = []string{"B", "KB", "MB", "GB", "TB", "PB"}
|
|
step float64 = 1024
|
|
)
|
|
|
|
func fixUnit(curSize float64, curUnitIndex int) (newSize float64, newUnitIndex int) {
|
|
if curSize >= step && curUnitIndex < len(units)-1 {
|
|
return fixUnit(curSize/step, curUnitIndex+1)
|
|
}
|
|
return curSize, curUnitIndex
|
|
}
|
|
|
|
func formatSize(size uint64) string {
|
|
fixedSize, fixedUnitIndex := fixUnit(float64(size), 0)
|
|
return fmt.Sprintf("%.2f %v", fixedSize, units[fixedUnitIndex])
|
|
}
|
|
|
|
func formatTime(timeUnix int64) string {
|
|
return time.Unix(timeUnix, 0).Format("2006-01-02 15:04:05")
|
|
}
|
|
|
|
func formatTimeToString(t time.Time) string {
|
|
return t.Format("2006-01-02 15:04:05")
|
|
}
|
|
|
|
var dataReplicaTableRowPattern = "%-65v %-12v %-12v %-12v %-12v %-12v %-12v %-12v %-18v %-10v"
|
|
|
|
func formatDataReplicaTableHeader() string {
|
|
return fmt.Sprintf(dataReplicaTableRowPattern, "ADDR", "USEDSIZE", "TOTALSIZE", "ISLEADER", "FILECOUNT", "HASLOADRESPONSE", "NEEDSTOCOMPARE", "STATUS", "DISKPATH", "REPORT TIME")
|
|
}
|
|
|
|
var dataFileInCoreTableRowPattern = "%-12v %-12v %-10v %-10v"
|
|
|
|
func formatDataFileInCoreTableHeader() string {
|
|
return fmt.Sprintf(dataFileInCoreTableRowPattern, "KEY", "NAME", "LASTMODIFY", "FILEMETADATE")
|
|
}
|
|
|
|
var dataFileMetadateTableRowPattern = "%-12v %-12v %-10v %-10v %-10v %-18v"
|
|
|
|
func formatDataFileMetadateTableHeader() string {
|
|
return fmt.Sprintf(dataFileMetadateTableRowPattern, "", "", "", "CRC", "SIZE", "LOCADDR")
|
|
}
|
|
|
|
func formatDataFileInCoreMap(id string, indentation string, fileCore *proto.FileInCore, rowTable bool) string {
|
|
sb := strings.Builder{}
|
|
if rowTable {
|
|
sb.WriteString(fmt.Sprintf(dataFileInCoreTableRowPattern, id, fileCore.Name, fileCore.LastModify, ""))
|
|
for _, v := range fileCore.MetadataArray {
|
|
sb.WriteString("\n")
|
|
sb.WriteString(formatDataFileMetadate("", v))
|
|
}
|
|
sb.WriteString("\n")
|
|
return sb.String()
|
|
}
|
|
sb.WriteString(fmt.Sprintf("%v- Name : %v\n", indentation, fileCore.Name))
|
|
sb.WriteString(fmt.Sprintf("%v LastModify : %v\n", indentation, fileCore.LastModify))
|
|
sb.WriteString(fmt.Sprintf("%v FileMetadate : %v\n", indentation, fileCore.MetadataArray))
|
|
return sb.String()
|
|
}
|
|
|
|
func formatDataFileMetadate(indentation string, fileMeta *proto.FileMetadata) string {
|
|
return fmt.Sprintf(dataFileMetadateTableRowPattern, "", "", "", fileMeta.Crc, fileMeta.Size, fileMeta.LocAddr)
|
|
}
|
|
|
|
func formatDataReplica(index int, replica *proto.DataReplica, rowTable bool) string {
|
|
if rowTable {
|
|
return fmt.Sprintf(dataReplicaTableRowPattern, formatAddr(replica.Addr, replica.DomainAddr),
|
|
formatSize(replica.Used), formatSize(replica.Total), replica.IsLeader, replica.FileCount,
|
|
replica.HasLoadResponse, replica.NeedsToCompare, formatDataPartitionStatus(replica.Status),
|
|
replica.DiskPath, formatTime(replica.ReportTime))
|
|
}
|
|
return alignColumnIndex(index,
|
|
arow("Addr", formatAddr(replica.Addr, replica.DomainAddr)),
|
|
arow("Allocated", formatSize(replica.Used)),
|
|
arow("Total", formatSize(replica.Total)),
|
|
arow("IsLeader", replica.IsLeader),
|
|
arow("FileCount", replica.FileCount),
|
|
arow("HasLoadResponse", replica.HasLoadResponse),
|
|
arow("NeedsToCompare", replica.NeedsToCompare),
|
|
arow("Status", formatDataPartitionStatus(replica.Status)),
|
|
arow("DiskPath", replica.DiskPath),
|
|
arow("ReportTime", formatTime(replica.ReportTime)),
|
|
)
|
|
}
|
|
|
|
var metaReplicaTableRowPattern = "%-65v %-6v %-6v %-6v %-10v"
|
|
|
|
func formatMetaReplicaTableHeader() string {
|
|
return fmt.Sprintf(metaReplicaTableRowPattern, "ADDRESS", "MaxInodeID", "ISLEADER", "STATUS", "REPORT TIME")
|
|
}
|
|
|
|
func formatMetaReplica(indentation string, replica *proto.MetaReplicaInfo, rowTable bool) string {
|
|
if rowTable {
|
|
return fmt.Sprintf(metaReplicaTableRowPattern, formatAddr(replica.Addr, replica.DomainAddr), replica.MaxInodeID,
|
|
replica.IsLeader, formatMetaPartitionStatus(replica.Status), formatTime(replica.ReportTime))
|
|
}
|
|
sb := strings.Builder{}
|
|
sb.WriteString(fmt.Sprintf("%v- Addr : %v\n", indentation, formatAddr(replica.Addr, replica.DomainAddr)))
|
|
sb.WriteString(fmt.Sprintf("%v- MaxInodeID : %v\n", indentation, replica.MaxInodeID))
|
|
sb.WriteString(fmt.Sprintf("%v Status : %v\n", indentation, formatMetaPartitionStatus(replica.Status)))
|
|
sb.WriteString(fmt.Sprintf("%v IsLeader : %v\n", indentation, replica.IsLeader))
|
|
sb.WriteString(fmt.Sprintf("%v ReportTime : %v\n", indentation, formatTime(replica.ReportTime)))
|
|
return sb.String()
|
|
}
|
|
|
|
var peerTableRowPattern = "%-6v %-18v"
|
|
|
|
func formatPeerTableHeader() string {
|
|
return fmt.Sprintf(peerTableRowPattern, "ID", "PEER")
|
|
}
|
|
|
|
func formatPeer(peer proto.Peer) string {
|
|
return fmt.Sprintf(peerTableRowPattern, peer.ID, peer.Addr)
|
|
}
|
|
|
|
var dataNodeDetailTableRowPattern = "%-6v %-6v %-65v %-6v %-6v %-6v %-10v"
|
|
|
|
func formatDataNodeDetailTableHeader() string {
|
|
return fmt.Sprintf(dataNodeDetailTableRowPattern, "ID", "ZONE", "ADDRESS", "USED", "TOTAL", "STATUS", "REPORT TIME")
|
|
}
|
|
|
|
func formatDataNodeDetail(dn *proto.DataNodeInfo, rowTable bool) string {
|
|
if rowTable {
|
|
return fmt.Sprintf(dataNodeDetailTableRowPattern, dn.ID, dn.ZoneName, formatAddr(dn.Addr, dn.DomainAddr),
|
|
formatSize(dn.Used), formatSize(dn.Total), formatNodeStatus(dn.IsActive), formatTimeToString(dn.ReportTime))
|
|
}
|
|
sb := strings.Builder{}
|
|
sb.WriteString(fmt.Sprintf(" ID : %v\n", dn.ID))
|
|
sb.WriteString(fmt.Sprintf(" Address : %v\n", formatAddr(dn.Addr, dn.DomainAddr)))
|
|
sb.WriteString(fmt.Sprintf(" Allocated ratio : %v\n", dn.UsageRatio))
|
|
sb.WriteString(fmt.Sprintf(" Allocated : %v\n", formatSize(dn.Used)))
|
|
sb.WriteString(fmt.Sprintf(" Available : %v\n", formatSize(dn.AvailableSpace)))
|
|
sb.WriteString(fmt.Sprintf(" Total : %v\n", formatSize(dn.Total)))
|
|
sb.WriteString(fmt.Sprintf(" Zone : %v\n", dn.ZoneName))
|
|
sb.WriteString(fmt.Sprintf(" Rdonly : %v\n", dn.RdOnly))
|
|
sb.WriteString(fmt.Sprintf(" Status : %v\n", formatNodeStatus(dn.IsActive)))
|
|
sb.WriteString(fmt.Sprintf(" MediaType : %v\n", proto.MediaTypeString(dn.MediaType)))
|
|
sb.WriteString(fmt.Sprintf(" ToBeOffline : %v\n", formatNodeOfflineStatus(dn.ToBeOffline)))
|
|
sb.WriteString(fmt.Sprintf(" Report time : %v\n", formatTimeToString(dn.ReportTime)))
|
|
sb.WriteString(fmt.Sprintf(" Partition count : %v\n", dn.DataPartitionCount))
|
|
sb.WriteString(fmt.Sprintf(" Bad disks : %v\n", dn.BadDisks))
|
|
sb.WriteString(fmt.Sprintf(" Decommissioned disks: %v\n", dn.DecommissionedDisk))
|
|
sb.WriteString(fmt.Sprintf(" Persist partitions : %v\n", dn.PersistenceDataPartitions))
|
|
sb.WriteString(fmt.Sprintf(" Backup partitions : %v\n", dn.BackupDataPartitions))
|
|
sb.WriteString(fmt.Sprintf(" Can alloc partition : %v\n", dn.CanAllocPartition))
|
|
sb.WriteString(fmt.Sprintf(" Max partition count : %v\n", dn.MaxDpCntLimit))
|
|
sb.WriteString(fmt.Sprintf(" CpuUtil : %.1f%%\n", dn.CpuUtil))
|
|
sb.WriteString(" IoUtils :\n")
|
|
for device, used := range dn.IoUtils {
|
|
sb.WriteString(fmt.Sprintf(" %v:%.1f%%\n", device, used))
|
|
}
|
|
return sb.String()
|
|
}
|
|
|
|
var metaNodeDetailTableRowPattern = "%-6v %-6v %-65v %-6v %-6v %-6v %-10v"
|
|
|
|
func formatMetaNodeDetailTableHeader() string {
|
|
return fmt.Sprintf(metaNodeDetailTableRowPattern, "ID", "ZONE", "ADDRESS", "USED", "TOTAL", "STATUS", "REPORT TIME")
|
|
}
|
|
|
|
func formatMetaNodeDetail(mn *proto.MetaNodeInfo, rowTable bool) string {
|
|
if rowTable {
|
|
return fmt.Sprintf(metaNodeDetailTableRowPattern, mn.ID, mn.ZoneName, formatAddr(mn.Addr, mn.DomainAddr),
|
|
mn.Used, mn.Total, mn.IsActive, formatTimeToString(mn.ReportTime))
|
|
}
|
|
sb := strings.Builder{}
|
|
sb.WriteString(fmt.Sprintf(" ID : %v\n", mn.ID))
|
|
sb.WriteString(fmt.Sprintf(" Address : %v\n", formatAddr(mn.Addr, mn.DomainAddr)))
|
|
sb.WriteString(fmt.Sprintf(" Threshold : %v\n", mn.Threshold))
|
|
sb.WriteString(fmt.Sprintf(" MaxMemAvailWeight : %v\n", formatSize(mn.MaxMemAvailWeight)))
|
|
sb.WriteString(fmt.Sprintf(" Allocated : %v\n", formatSize(mn.Used)))
|
|
sb.WriteString(fmt.Sprintf(" Total : %v\n", formatSize(mn.Total)))
|
|
sb.WriteString(fmt.Sprintf(" Zone : %v\n", mn.ZoneName))
|
|
sb.WriteString(fmt.Sprintf(" Status : %v\n", formatNodeStatus(mn.IsActive)))
|
|
sb.WriteString(fmt.Sprintf(" Rdonly : %v\n", mn.RdOnly))
|
|
sb.WriteString(fmt.Sprintf(" Report time : %v\n", formatTimeToString(mn.ReportTime)))
|
|
sb.WriteString(fmt.Sprintf(" Partition count : %v\n", mn.MetaPartitionCount))
|
|
sb.WriteString(fmt.Sprintf(" Persist partitions : %v\n", mn.PersistenceMetaPartitions))
|
|
sb.WriteString(fmt.Sprintf(" Can alloc partition : %v\n", mn.CanAllowPartition))
|
|
sb.WriteString(fmt.Sprintf(" Max partition count : %v\n", mn.MaxMpCntLimit))
|
|
sb.WriteString(fmt.Sprintf(" CpuUtil : %.1f%%\n", mn.CpuUtil))
|
|
return sb.String()
|
|
}
|
|
|
|
func formatNodeSetView(ns *proto.NodeSetStatInfo) string {
|
|
sb := strings.Builder{}
|
|
sb.WriteString(fmt.Sprintf("NodeSet ID: %v\n", ns.ID))
|
|
sb.WriteString(fmt.Sprintf("Capacity: %v\n", ns.Capacity))
|
|
sb.WriteString(fmt.Sprintf("Zone: %v\n", ns.Zone))
|
|
sb.WriteString(fmt.Sprintf("CanAllocDataNode: %v\n", ns.CanAllocDataNodeCnt))
|
|
sb.WriteString(fmt.Sprintf("CanAllocMetaNode: %v\n", ns.CanAllocMetaNodeCnt))
|
|
sb.WriteString(fmt.Sprintf("DataNodeSelector: %v\n", ns.DataNodeSelector))
|
|
sb.WriteString(fmt.Sprintf("MetaNodeSelector: %v\n", ns.MetaNodeSelector))
|
|
var dataTotal, dataUsed, dataAvail, metaTotal, metaUsed, metaAvail uint64
|
|
for _, dn := range ns.DataNodes {
|
|
dataTotal += dn.Total
|
|
dataUsed += dn.Used
|
|
dataAvail += dn.Avail
|
|
}
|
|
for _, mn := range ns.MetaNodes {
|
|
metaTotal += mn.Total
|
|
metaUsed += mn.Used
|
|
metaAvail += mn.Avail
|
|
}
|
|
sb.WriteString(fmt.Sprintf("DataTotal: %v\n", formatSize(dataTotal)))
|
|
sb.WriteString(fmt.Sprintf("DataUsed: %v\n", formatSize(dataUsed)))
|
|
sb.WriteString(fmt.Sprintf("DataAvail: %v\n", formatSize(dataAvail)))
|
|
sb.WriteString(fmt.Sprintf("MetaTotal: %v\n", formatSize(metaTotal)))
|
|
sb.WriteString(fmt.Sprintf("MetaUsed: %v\n", formatSize(metaUsed)))
|
|
sb.WriteString(fmt.Sprintf("MetaAvail: %v\n", formatSize(metaAvail)))
|
|
sb.WriteString("\n")
|
|
sb.WriteString(fmt.Sprintf("DataNodes[%v]:\n", len(ns.DataNodes)))
|
|
sb.WriteString(fmt.Sprintf(" %v\n", formatNodeViewTableHeaderForNodeSet()))
|
|
for _, dn := range ns.DataNodes {
|
|
sb.WriteString(fmt.Sprintf(" %v\n", formatNodeViewForNodeSet(dn)))
|
|
}
|
|
sb.WriteString("\n")
|
|
sb.WriteString(fmt.Sprintf("MetaNodes[%v]:\n", len(ns.MetaNodes)))
|
|
sb.WriteString(fmt.Sprintf(" %v\n", formatNodeViewTableHeaderForNodeSet()))
|
|
for _, mn := range ns.MetaNodes {
|
|
sb.WriteString(fmt.Sprintf(" %v\n", formatNodeViewForNodeSet(mn)))
|
|
}
|
|
return sb.String()
|
|
}
|
|
|
|
func formatZoneView(zv *proto.ZoneView) string {
|
|
sb := strings.Builder{}
|
|
sb.WriteString(fmt.Sprintf("Zone Name: %v\n", zv.Name))
|
|
sb.WriteString(fmt.Sprintf("Status: %v\n", zv.Status))
|
|
sb.WriteString(fmt.Sprintf("DataMediaType: %v\n", zv.DataMediaType))
|
|
sb.WriteString("Nodeset Selector:\n")
|
|
sb.WriteString(fmt.Sprintf(" Data:%v\n", zv.DataNodesetSelector))
|
|
sb.WriteString(fmt.Sprintf(" Meta:%v\n", zv.MetaNodesetSelector))
|
|
sb.WriteString("\n")
|
|
for index, ns := range zv.NodeSet {
|
|
sb.WriteString(fmt.Sprintf("NodeSet-%v:\n", index))
|
|
sb.WriteString(fmt.Sprintf(" DataNodes[%v]:\n", ns.DataNodeLen))
|
|
sb.WriteString(fmt.Sprintf(" %v\n", formatNodeViewTableHeader()))
|
|
for _, nv := range ns.DataNodes {
|
|
sb.WriteString(fmt.Sprintf(" %v\n", formatNodeView(&nv, true)))
|
|
}
|
|
sb.WriteString("\n")
|
|
sb.WriteString(fmt.Sprintf(" MetaNodes[%v]:\n", ns.MetaNodeLen))
|
|
sb.WriteString(fmt.Sprintf(" %v\n", formatNodeViewTableHeader()))
|
|
for _, nv := range ns.MetaNodes {
|
|
sb.WriteString(fmt.Sprintf(" %v\n", formatNodeView(&nv, true)))
|
|
}
|
|
}
|
|
return sb.String()
|
|
}
|
|
|
|
var quotaTableRowPattern = "%-6v %-30v %-15v %-20v %-15v %-10v %-12v %-12v %-10v %-10v %-10v %-10v"
|
|
|
|
func formatQuotaTableHeader() string {
|
|
return fmt.Sprintf(quotaTableRowPattern, "ID", "PATH", "VOL", "CTIME",
|
|
"PID", "RINODE", "LIMITEDFILES", "LIMITEDBYTES", "USEDFILES", "USEDBYTES", "MAXFILES", "MAXBYTES")
|
|
}
|
|
|
|
func formatQuotaInfo(info *proto.QuotaInfo) string {
|
|
t := time.Unix(info.CTime, 0)
|
|
var ret string
|
|
firstLine := true
|
|
for _, pathInfo := range info.PathInfos {
|
|
if firstLine {
|
|
ret = fmt.Sprintf(quotaTableRowPattern, info.QuotaId, pathInfo.FullPath, info.VolName, t.Format("2006-01-02 15:04:05"), pathInfo.PartitionId,
|
|
pathInfo.RootInode, info.LimitedInfo.LimitedFiles, info.LimitedInfo.LimitedBytes, info.UsedInfo.UsedFiles, info.UsedInfo.UsedBytes,
|
|
info.MaxFiles, info.MaxBytes)
|
|
firstLine = false
|
|
} else {
|
|
ret += "\n"
|
|
ret += fmt.Sprintf(quotaTableRowPattern, "", pathInfo.FullPath, "", "", pathInfo.PartitionId, pathInfo.RootInode,
|
|
"", "", "", "", "", "")
|
|
}
|
|
}
|
|
return ret
|
|
}
|
|
|
|
func formatBadDisks(disks []proto.DiskInfo) string {
|
|
if len(disks) == 0 {
|
|
return ""
|
|
}
|
|
diskRows := table{
|
|
arow("Address", "Path", "TotalPartitionCnt", "DiskErrPartitionCnt", "PartitionIdsWithDiskErr"),
|
|
}
|
|
for _, d := range disks {
|
|
diskRows = diskRows.append(arow(d.Address, d.Path, d.TotalPartitionCnt, len(d.DiskErrPartitionList), d.DiskErrPartitionList))
|
|
}
|
|
return alignTable(diskRows...)
|
|
}
|
|
|
|
func formatDiskList(disks []proto.DiskInfo) string {
|
|
if len(disks) == 0 {
|
|
return ""
|
|
}
|
|
diskRows := table{
|
|
arow("NodeId", "Address", "Path", "Status", "TotalPartitionCnt"),
|
|
}
|
|
for _, d := range disks {
|
|
diskRows = diskRows.append(arow(d.NodeId, d.Address, d.Path, d.Status, d.TotalPartitionCnt))
|
|
}
|
|
return alignTable(diskRows...)
|
|
}
|
|
|
|
func formatDiskDetailSummary(detail *proto.DiskInfo) string {
|
|
errDataPartitions := fmt.Sprintf("%v", detail.DiskErrPartitionList)
|
|
sb := strings.Builder{}
|
|
sb.WriteString(fmt.Sprintf(" NodeId : %v\n", detail.NodeId))
|
|
sb.WriteString(fmt.Sprintf(" Address : %v\n", detail.Address))
|
|
sb.WriteString(fmt.Sprintf(" Path : %v\n", detail.Path))
|
|
sb.WriteString(fmt.Sprintf(" Status : %v\n", detail.Status))
|
|
sb.WriteString(fmt.Sprintf(" Total : %v\n", formatSize(detail.Total)))
|
|
sb.WriteString(fmt.Sprintf(" Used : %v\n", formatSize(detail.Used)))
|
|
sb.WriteString(fmt.Sprintf(" Available : %v\n", formatSize(detail.Available)))
|
|
sb.WriteString(fmt.Sprintf(" IOUtil : %v\n", fmt.Sprintf("%.1f%%", detail.IOUtil)))
|
|
sb.WriteString(fmt.Sprintf(" DataPartitionCnt : %v\n", detail.TotalPartitionCnt))
|
|
sb.WriteString(fmt.Sprintf(" ErrDataPartitions : %v\n", errDataPartitions))
|
|
|
|
return sb.String()
|
|
}
|
|
|
|
var (
|
|
diskDataPartitionTablePattern = "%-8v %-8v %-8v %-8v %-8v %-8v %-8v %-8v %-8v"
|
|
diskDataPartitionTableHeader = fmt.Sprintf(diskDataPartitionTablePattern,
|
|
"DpID", "Vol", "Stat", "Total", "Used", "IsLeader", "ExtentCnt", "NeedCompare", "DecommRepairProgress")
|
|
)
|
|
|
|
func formatDiskDataPartitionTableRow(view *proto.DataPartitionReport) string {
|
|
return fmt.Sprintf(diskDataPartitionTablePattern,
|
|
view.PartitionID, view.VolName, formatDataPartitionStatus(int8(view.PartitionStatus)),
|
|
formatSize(view.Total), formatSize(view.Used), view.IsLeader, view.ExtentCount, view.NeedCompare, view.DecommissionRepairProgress)
|
|
}
|
|
|
|
func formatDecommissionProgress(progress *proto.DecommissionProgress) string {
|
|
sb := strings.Builder{}
|
|
sb.WriteString(fmt.Sprintf("Status: %v\n", progress.StatusMessage))
|
|
sb.WriteString(fmt.Sprintf("Progress: %v\n", progress.Progress))
|
|
if len(progress.FailedDps) != 0 {
|
|
sb.WriteString("Failed Dps: \n")
|
|
for i, info := range progress.FailedDps {
|
|
sb.WriteString(fmt.Sprintf(" [%v/%v] Partition Id : %v\n", i+1, len(progress.FailedDps), info.PartitionID))
|
|
sb.WriteString(fmt.Sprintf(" Error Message : %v\n", info.ErrMsg))
|
|
}
|
|
}
|
|
return sb.String()
|
|
}
|
|
|
|
func formatDataPartitionDecommissionProgress(info *proto.DecommissionDataPartitionInfo) string {
|
|
sb := strings.Builder{}
|
|
sb.WriteString(fmt.Sprintf("Status: %v\n", info.Status))
|
|
sb.WriteString(fmt.Sprintf("SpecialStep: %v\n", info.SpecialStep))
|
|
sb.WriteString(fmt.Sprintf("Retry: %v\n", info.Retry))
|
|
sb.WriteString(fmt.Sprintf("RaftForce: %v\n", info.RaftForce))
|
|
sb.WriteString(fmt.Sprintf("Recover: %v\n", info.Recover))
|
|
sb.WriteString(fmt.Sprintf("SrcAddress: %v\n", info.SrcAddress))
|
|
sb.WriteString(fmt.Sprintf("SrcDiskPath: %v\n", info.SrcDiskPath))
|
|
sb.WriteString(fmt.Sprintf("DstAddress: %v\n", info.DstAddress))
|
|
sb.WriteString(fmt.Sprintf("Term: %v\n", info.Term))
|
|
sb.WriteString(fmt.Sprintf("Replicas: %v\n", info.Replicas))
|
|
sb.WriteString(fmt.Sprintf("NeedRollbackTimes: %v\n", info.NeedRollbackTimes))
|
|
sb.WriteString(fmt.Sprintf("ErrorMessage: %v\n", info.ErrorMessage))
|
|
return sb.String()
|
|
}
|
|
|
|
func formatDiskErrorReplicaDpInfoRow(partition *proto.DataPartitionInfo, infos []proto.DiskErrReplicaInfo) string {
|
|
sb := strings.Builder{}
|
|
sb.WriteString("[")
|
|
firstItem := true
|
|
for _, info := range infos {
|
|
if !firstItem {
|
|
sb.WriteString(",")
|
|
}
|
|
// if dp is not loaded, remove replica cannot delete dp from disk heartbeat report
|
|
if replicaInHost(partition.Hosts, info.Addr) {
|
|
sb.WriteString(fmt.Sprintf("%v(%v)", info.Addr, info.Disk))
|
|
firstItem = false
|
|
}
|
|
}
|
|
sb.WriteString("]")
|
|
return fmt.Sprintf(diskErrorReplicaPartitionInfoTablePattern, partition.PartitionID, partition.VolName, partition.ReplicaNum,
|
|
formatDataPartitionStatus(partition.Status), "["+strings.Join(partition.Hosts, ", ")+"]", sb.String())
|
|
}
|
|
|
|
func formatDecommissionFailedDiskInfo(info *proto.DecommissionFailedDiskInfo) string {
|
|
sb := strings.Builder{}
|
|
sb.WriteString(fmt.Sprintf("SrcAddr: %v\n", info.SrcAddr))
|
|
sb.WriteString(fmt.Sprintf("DiskPath: %v\n", info.DiskPath))
|
|
sb.WriteString(fmt.Sprintf("DpTotal: %v\n", info.DecommissionDpTotal))
|
|
sb.WriteString(fmt.Sprintf("RaftForce: %v\n", info.DecommissionRaftForce))
|
|
sb.WriteString(fmt.Sprintf("Retry: %v\n", info.DecommissionTimes))
|
|
sb.WriteString(fmt.Sprintf("AutoDecommission: %v\n", info.IsAutoDecommission))
|
|
return sb.String()
|
|
}
|
|
|
|
func replicaInHost(hosts []string, replica string) bool {
|
|
for _, host := range hosts {
|
|
if replica == host {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
func formatDecommissionTokenStatus(status *proto.DecommissionTokenStatus) string {
|
|
return fmt.Sprintf("Nodeset %v: %v/%v", status.NodesetID, status.CurTokenNum, status.MaxTokenNum)
|
|
}
|