github.com/minio/mc@v0.0.0-20240503112107-b471de8d1882/cmd/admin-rebalance-status.go (about) 1 // Copyright (c) 2022 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 "encoding/json" 22 "fmt" 23 "strings" 24 "time" 25 26 humanize "github.com/dustin/go-humanize" 27 "github.com/fatih/color" 28 "github.com/minio/cli" 29 "github.com/minio/mc/pkg/probe" 30 "github.com/minio/pkg/v2/console" 31 ) 32 33 var adminRebalanceStatusCmd = cli.Command{ 34 Name: "status", 35 Usage: "summarize an ongoing rebalance operation", 36 Action: mainAdminRebalanceStatus, 37 OnUsageError: onUsageError, 38 Before: setGlobalsFromContext, 39 Flags: globalFlags, 40 CustomHelpTemplate: `NAME: 41 {{.HelpName}} - {{.Usage}} 42 43 USAGE: 44 {{.HelpName}} ALIAS 45 46 FLAGS: 47 {{range .VisibleFlags}}{{.}} 48 {{end}} 49 EXAMPLES: 50 1. Summarize ongoing rebalance on a MinIO deployment with alias myminio 51 {{.Prompt}} {{.HelpName}} myminio 52 `, 53 } 54 55 func mainAdminRebalanceStatus(ctx *cli.Context) error { 56 if len(ctx.Args()) != 1 { 57 showCommandHelpAndExit(ctx, 1) 58 } 59 60 args := ctx.Args() 61 aliasedURL := args.Get(0) 62 63 client, err := newAdminClient(aliasedURL) 64 if err != nil { 65 fatalIf(err.Trace(aliasedURL), "Unable to initialize admin client") 66 return err.ToGoError() 67 } 68 69 rInfo, e := client.RebalanceStatus(globalContext) 70 fatalIf(probe.NewError(e), "Unable to get rebalance status") 71 72 if globalJSON { 73 b, e := json.Marshal(rInfo) 74 fatalIf(probe.NewError(e), "Unable to marshal json") 75 console.Println(string(b)) 76 return nil 77 } 78 79 console.Println("Per-pool usage:") 80 // col-headers 81 colHeaders := make([]string, len(rInfo.Pools)) 82 for i := range rInfo.Pools { 83 colHeaders[i] = fmt.Sprintf("Pool-%d", i) 84 } 85 var ( 86 totalBytes, totalObjects, totalVersions uint64 87 maxElapsed, maxETA time.Duration 88 ) 89 row := make([]string, len(rInfo.Pools)) 90 for idx, pool := range rInfo.Pools { 91 statusStr := fmt.Sprintf("%.2f%%", pool.Used*100) 92 if pool.Status == "Started" { 93 statusStr += " *" // indicating rebalance is in progress in this pool 94 } 95 row[idx] = statusStr 96 97 // For summary values 98 totalBytes += pool.Progress.Bytes 99 totalObjects += pool.Progress.NumObjects 100 totalVersions += pool.Progress.NumVersions 101 if maxElapsed == 0 || maxElapsed < pool.Progress.Elapsed { 102 maxElapsed = pool.Progress.Elapsed 103 } 104 if maxETA == 0 || maxETA < pool.Progress.ETA { 105 maxETA = pool.Progress.ETA 106 } 107 } 108 109 dspOrder := []col{colGreen, colGrey} 110 var printColors []*color.Color 111 for _, c := range dspOrder { 112 printColors = append(printColors, getPrintCol(c)) 113 } 114 alignRights := make([]bool, len(rInfo.Pools)) 115 tbl := console.NewTable(printColors, alignRights, 0) 116 117 e = tbl.DisplayTable([][]string{colHeaders, row}) 118 fatalIf(probe.NewError(e), "Unable to render table view") 119 120 var b strings.Builder 121 fmt.Fprintf(&b, "Summary: \n") 122 fmt.Fprintf(&b, "Data: %s (%d objects, %d versions) \n", humanize.IBytes(totalBytes), totalObjects, totalVersions) 123 fmt.Fprintf(&b, "Time: %s (%s to completion)", maxElapsed, maxETA) 124 console.Println(b.String()) 125 return nil 126 }