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  }