github.com/palisadeinc/bor@v0.0.0-20230615125219-ab7196213d15/internal/cli/bor_fingerprint.go (about) 1 package cli 2 3 import ( 4 "fmt" 5 "math" 6 "os/exec" 7 "strings" 8 9 "github.com/ethereum/go-ethereum/params" 10 11 "github.com/mitchellh/cli" 12 "github.com/shirou/gopsutil/cpu" 13 "github.com/shirou/gopsutil/disk" 14 "github.com/shirou/gopsutil/host" 15 "github.com/shirou/gopsutil/mem" 16 ) 17 18 // VersionCommand is the command to show the version of the agent 19 type FingerprintCommand struct { 20 UI cli.Ui 21 } 22 23 // MarkDown implements cli.MarkDown interface 24 func (c *FingerprintCommand) MarkDown() string { 25 items := []string{ 26 "# Fingerprint", 27 "Display the system fingerprint", 28 } 29 30 return strings.Join(items, "\n\n") 31 } 32 33 // Help implements the cli.Command interface 34 func (c *FingerprintCommand) Help() string { 35 return `Usage: bor fingerprint 36 37 Display the system fingerprint` 38 } 39 40 // Synopsis implements the cli.Command interface 41 func (c *FingerprintCommand) Synopsis() string { 42 return "Display the system fingerprint" 43 } 44 45 func getCoresCount(cp []cpu.InfoStat) int { 46 cores := 0 47 for i := 0; i < len(cp); i++ { 48 cores += int(cp[i].Cores) 49 } 50 51 return cores 52 } 53 54 type MemoryDetails struct { 55 TotalMem float64 `json:"totalMem"` 56 FreeMem float64 `json:"freeMem"` 57 UsedMem float64 `json:"usedMem"` 58 } 59 60 type DiskDetails struct { 61 TotalDisk float64 `json:"totalDisk"` 62 FreeDisk float64 `json:"freeDisk"` 63 UsedDisk float64 `json:"usedDisk"` 64 } 65 66 type BorFingerprint struct { 67 CoresCount int `json:"coresCount"` 68 OsName string `json:"osName"` 69 OsVer string `json:"osVer"` 70 DiskDetails *DiskDetails `json:"diskDetails"` 71 MemoryDetails *MemoryDetails `json:"memoryDetails"` 72 } 73 74 func formatFingerprint(borFingerprint *BorFingerprint) string { 75 base := formatKV([]string{ 76 fmt.Sprintf("Bor Version : %s", params.VersionWithMeta), 77 fmt.Sprintf("CPU : %d cores", borFingerprint.CoresCount), 78 fmt.Sprintf("OS : %s %s ", borFingerprint.OsName, borFingerprint.OsVer), 79 fmt.Sprintf("RAM :: total : %v GB, free : %v GB, used : %v GB", borFingerprint.MemoryDetails.TotalMem, borFingerprint.MemoryDetails.FreeMem, borFingerprint.MemoryDetails.UsedMem), 80 fmt.Sprintf("STORAGE :: total : %v GB, free : %v GB, used : %v GB", borFingerprint.DiskDetails.TotalDisk, borFingerprint.DiskDetails.FreeDisk, borFingerprint.DiskDetails.UsedDisk), 81 }) 82 83 return base 84 } 85 86 func convertBytesToGB(bytesValue uint64) float64 { 87 return math.Floor(float64(bytesValue)/(1024*1024*1024)*100) / 100 88 } 89 90 // Checks if fio exists on the node 91 func (c *FingerprintCommand) checkFio() error { 92 cmd := exec.Command("/bin/sh", "-c", "fio -v") 93 94 _, err := cmd.CombinedOutput() 95 if err != nil { 96 message := "\nFio package not installed. Install Fio for IOPS Benchmarking :\n\nDebianOS : 'sudo apt-get update && sudo apt-get install fio -y'\nAWS AMI/CentOS : 'sudo yum install fio -y'\nOracle LinuxOS : 'sudo dnf install fio -y'\n" 97 c.UI.Output(message) 98 99 return err 100 } 101 102 return nil 103 } 104 105 // Run the IOPS benchmark for the node 106 func (c *FingerprintCommand) benchmark() error { 107 var b []byte 108 109 err := c.checkFio() 110 111 if err != nil { 112 // Missing Fio is not a fatal error. A message will be logged in console when it is missing in "checkFio()". 113 return nil //nolint:nilerr 114 } 115 116 c.UI.Output("\nRunning a 10 second test...\n") 117 118 cmd := exec.Command("/bin/sh", "-c", "sudo fio --filename=/file --size=2GB --direct=1 --rw=randrw --bs=64k --ioengine=libaio --iodepth=64 --runtime=10 --numjobs=4 --time_based --group_reporting --name=throughput-test-job --eta-newline=1 | grep -e 'read:' -e 'write:' | awk '{print $1,$2}' ") 119 120 b, err = cmd.CombinedOutput() 121 if err != nil { 122 return err 123 } 124 125 out := string(b) 126 c.UI.Output(out) 127 128 return nil 129 } 130 131 // Run implements the cli.Command interface 132 func (c *FingerprintCommand) Run(args []string) int { 133 v, err := mem.VirtualMemory() 134 if err != nil { 135 c.UI.Error(err.Error()) 136 return 1 137 } 138 139 h, err := host.Info() 140 if err != nil { 141 c.UI.Error(err.Error()) 142 return 1 143 } 144 145 cp, err := cpu.Info() 146 if err != nil { 147 c.UI.Error(err.Error()) 148 return 1 149 } 150 151 d, err := disk.Usage("/") 152 if err != nil { 153 c.UI.Error(err.Error()) 154 return 1 155 } 156 157 diskDetails := &DiskDetails{ 158 TotalDisk: convertBytesToGB(d.Total), 159 FreeDisk: convertBytesToGB(d.Free), 160 UsedDisk: convertBytesToGB(d.Used), 161 } 162 163 memoryDetails := &MemoryDetails{ 164 TotalMem: convertBytesToGB(v.Total), 165 FreeMem: convertBytesToGB(v.Available), 166 UsedMem: convertBytesToGB(v.Used), 167 } 168 169 borFingerprint := &BorFingerprint{ 170 CoresCount: getCoresCount(cp), 171 OsName: h.OS, 172 OsVer: h.Platform + " - " + h.PlatformVersion + " - " + h.KernelArch, 173 DiskDetails: diskDetails, 174 MemoryDetails: memoryDetails, 175 } 176 177 c.UI.Output(formatFingerprint(borFingerprint)) 178 179 if borFingerprint.OsName == "linux" { 180 err = c.benchmark() 181 if err != nil { 182 c.UI.Error(err.Error()) 183 return 1 184 } 185 } 186 187 return 0 188 }