github.com/minio/mc@v0.0.0-20240503112107-b471de8d1882/cmd/support-perf-client.go (about) 1 // Copyright (c) 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 "os" 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 func mainAdminSpeedTestClientPerf(ctx *cli.Context, aliasedURL string, outCh chan<- PerfTestResult) error { 32 client, perr := newAdminClient(aliasedURL) 33 if perr != nil { 34 fatalIf(perr.Trace(aliasedURL), "Unable to initialize admin client.") 35 return nil 36 } 37 38 ctxt, cancel := context.WithCancel(globalContext) 39 defer cancel() 40 41 duration, e := time.ParseDuration(ctx.String("duration")) 42 if e != nil { 43 fatalIf(probe.NewError(e), "Unable to parse duration") 44 return nil 45 } 46 if duration <= 0 { 47 fatalIf(errInvalidArgument(), "duration cannot be 0 or negative") 48 return nil 49 } 50 51 resultCh := make(chan madmin.ClientPerfResult) 52 errorCh := make(chan error) 53 go func() { 54 defer close(resultCh) 55 defer close(errorCh) 56 result, e := client.ClientPerf(ctxt, duration) 57 if e != nil { 58 errorCh <- e 59 } 60 resultCh <- result 61 }() 62 if globalJSON { 63 var rsl PerfTestOutput 64 select { 65 case e := <-errorCh: 66 rsl = convertPerfResult(PerfTestResult{ 67 Type: ClientPerfTest, 68 Err: e.Error(), 69 Final: true, 70 }) 71 case result := <-resultCh: 72 rsl = convertPerfResult(PerfTestResult{ 73 Type: ClientPerfTest, 74 ClientResult: &result, 75 Final: true, 76 }) 77 } 78 printMsg(rsl) 79 return nil 80 } 81 82 done := make(chan struct{}) 83 84 p := tea.NewProgram(initSpeedTestUI()) 85 go func() { 86 if _, e := p.Run(); e != nil { 87 os.Exit(1) 88 } 89 close(done) 90 }() 91 92 go func() { 93 for { 94 select { 95 case e := <-errorCh: 96 r := PerfTestResult{ 97 Type: ClientPerfTest, 98 Err: e.Error(), 99 Final: true, 100 } 101 p.Send(r) 102 if outCh != nil { 103 outCh <- r 104 } 105 return 106 case result := <-resultCh: 107 r := PerfTestResult{ 108 Type: ClientPerfTest, 109 ClientResult: &result, 110 Final: true, 111 } 112 p.Send(r) 113 if outCh != nil { 114 outCh <- r 115 } 116 return 117 default: 118 p.Send(PerfTestResult{ 119 Type: ClientPerfTest, 120 ClientResult: &madmin.ClientPerfResult{}, 121 }) 122 time.Sleep(100 * time.Millisecond) 123 } 124 } 125 }() 126 127 <-done 128 129 return nil 130 }