github.com/minio/mc@v0.0.0-20240503112107-b471de8d1882/cmd/support-top-net.go (about) 1 // Copyright (c) 2015-2023 MinIO, Inc. 2 // 3 // This file is part of MinIO Object Storage stack 4 // 5 // This program is free software: you can redistribute it and/or modify 6 // it under the terms of the GNU Affero General Public License as published by 7 // the Free Software Foundation, either version 3 of the License, or 8 // (at your option) any later version. 9 // 10 // This program is distributed in the hope that it will be useful 11 // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 // GNU Affero General Public License for more details. 14 // 15 // You should have received a copy of the GNU Affero General Public License 16 // along with this program. If not, see <http://www.gnu.org/licenses/>. 17 18 package cmd 19 20 import ( 21 "context" 22 "errors" 23 "time" 24 25 tea "github.com/charmbracelet/bubbletea" 26 "github.com/minio/cli" 27 "github.com/minio/madmin-go/v3" 28 "github.com/minio/mc/pkg/probe" 29 ) 30 31 var supportTopNetFlags = []cli.Flag{ 32 cli.IntFlag{ 33 Name: "interval", 34 Usage: "interval between requests in seconds", 35 Value: 1, 36 }, 37 } 38 39 var supportTopNetCmd = cli.Command{ 40 Name: "net", 41 Aliases: []string{"network"}, 42 HiddenAliases: true, 43 Usage: "show real-time net metrics", 44 Action: mainSupportTopNet, 45 OnUsageError: onUsageError, 46 Before: setGlobalsFromContext, 47 Flags: append(supportTopNetFlags, supportGlobalFlags...), 48 HideHelpCommand: true, 49 CustomHelpTemplate: `NAME: 50 {{.HelpName}} - {{.Usage}} 51 52 USAGE: 53 {{.HelpName}} [FLAGS] TARGET 54 55 FLAGS: 56 {{range .VisibleFlags}}{{.}} 57 {{end}} 58 EXAMPLES: 59 1. Display net metrics 60 {{.Prompt}} {{.HelpName}} myminio/ 61 `, 62 } 63 64 // checkSupportTopNetSyntax - validate all the passed arguments 65 func checkSupportTopNetSyntax(ctx *cli.Context) { 66 if len(ctx.Args()) == 0 || len(ctx.Args()) > 1 { 67 showCommandHelpAndExit(ctx, 1) // last argument is exit code 68 } 69 } 70 71 func mainSupportTopNet(ctx *cli.Context) error { 72 checkSupportTopNetSyntax(ctx) 73 74 aliasedURL := ctx.Args().Get(0) 75 alias, _ := url2Alias(aliasedURL) 76 validateClusterRegistered(alias, false) 77 78 // Create a new MinIO Admin Client 79 client, err := newAdminClient(aliasedURL) 80 if err != nil { 81 fatalIf(err.Trace(aliasedURL), "Unable to initialize admin client.") 82 return nil 83 } 84 85 ctxt, cancel := context.WithCancel(globalContext) 86 defer cancel() 87 info, e := client.ServerInfo(ctxt) 88 fatalIf(probe.NewError(e).Trace(aliasedURL), "Unable to initialize admin client.") 89 hosts := make([]string, 0, len(info.Servers)) 90 for _, s := range info.Servers { 91 hosts = append(hosts, s.Endpoint) 92 } 93 // MetricsOptions are options provided to Metrics call. 94 opts := madmin.MetricsOptions{ 95 Type: madmin.MetricNet, 96 Interval: time.Duration(ctx.Int("interval")) * time.Second, 97 ByHost: true, 98 Hosts: hosts, 99 } 100 101 p := tea.NewProgram(initTopNetUI()) 102 go func() { 103 if globalJSON { 104 e := client.Metrics(ctxt, opts, func(metrics madmin.RealtimeMetrics) { 105 printMsg(metricsMessage{RealtimeMetrics: metrics}) 106 }) 107 if e != nil && !errors.Is(e, context.Canceled) { 108 fatalIf(probe.NewError(e).Trace(aliasedURL), "Unable to fetch scanner metrics") 109 } 110 } else { 111 out := func(m madmin.RealtimeMetrics) { 112 for endPoint, metric := range m.ByHost { 113 if metric.Net != nil { 114 p.Send(topNetResult{ 115 endPoint: endPoint, 116 stats: *metric.Net, 117 }) 118 } 119 } 120 if len(m.Errors) != 0 && len(m.Hosts) != 0 { 121 p.Send(topNetResult{ 122 endPoint: m.Hosts[0], 123 error: m.Errors[0], 124 }) 125 } 126 } 127 128 e := client.Metrics(ctxt, opts, out) 129 if e != nil { 130 fatalIf(probe.NewError(e), "Unable to fetch top net events") 131 } 132 } 133 p.Quit() 134 }() 135 136 if _, e := p.Run(); e != nil { 137 cancel() 138 fatalIf(probe.NewError(e).Trace(aliasedURL), "Unable to fetch top net events") 139 } 140 141 return nil 142 }