github.com/minio/mc@v0.0.0-20240503112107-b471de8d1882/cmd/support-top-drive.go (about)

     1  // Copyright (c) 2015-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  	"context"
    22  	"time"
    23  
    24  	tea "github.com/charmbracelet/bubbletea"
    25  	"github.com/minio/cli"
    26  	"github.com/minio/madmin-go/v3"
    27  	"github.com/minio/mc/pkg/probe"
    28  )
    29  
    30  var supportTopDriveFlags = []cli.Flag{
    31  	cli.IntFlag{
    32  		Name:  "count, c",
    33  		Usage: "show up to N drives",
    34  		Value: 10,
    35  	},
    36  }
    37  
    38  var supportTopDriveCmd = cli.Command{
    39  	Name:            "drive",
    40  	Aliases:         []string{"disk"},
    41  	HiddenAliases:   true,
    42  	Usage:           "show real-time drive metrics",
    43  	Action:          mainSupportTopDrive,
    44  	OnUsageError:    onUsageError,
    45  	Before:          setGlobalsFromContext,
    46  	Flags:           append(supportTopDriveFlags, supportGlobalFlags...),
    47  	HideHelpCommand: true,
    48  	CustomHelpTemplate: `NAME:
    49    {{.HelpName}} - {{.Usage}}
    50  
    51  USAGE:
    52    {{.HelpName}} [FLAGS] TARGET
    53  
    54  FLAGS:
    55    {{range .VisibleFlags}}{{.}}
    56    {{end}}
    57  EXAMPLES:
    58     1. Display drive metrics
    59        {{.Prompt}} {{.HelpName}} myminio/
    60  `,
    61  }
    62  
    63  // checkSupportTopDriveSyntax - validate all the passed arguments
    64  func checkSupportTopDriveSyntax(ctx *cli.Context) {
    65  	if len(ctx.Args()) == 0 || len(ctx.Args()) > 1 {
    66  		showCommandHelpAndExit(ctx, 1) // last argument is exit code
    67  	}
    68  }
    69  
    70  func mainSupportTopDrive(ctx *cli.Context) error {
    71  	checkSupportTopDriveSyntax(ctx)
    72  
    73  	aliasedURL := ctx.Args().Get(0)
    74  	alias, _ := url2Alias(aliasedURL)
    75  	validateClusterRegistered(alias, false)
    76  
    77  	// Create a new MinIO Admin Client
    78  	client, err := newAdminClient(aliasedURL)
    79  	if err != nil {
    80  		fatalIf(err.Trace(aliasedURL), "Unable to initialize admin client.")
    81  		return nil
    82  	}
    83  
    84  	ctxt, cancel := context.WithCancel(globalContext)
    85  	defer cancel()
    86  
    87  	info, e := client.ServerInfo(ctxt)
    88  	fatalIf(probe.NewError(e).Trace(aliasedURL), "Unable to initialize admin client.")
    89  
    90  	var disks []madmin.Disk
    91  	for _, srv := range info.Servers {
    92  		disks = append(disks, srv.Disks...)
    93  	}
    94  
    95  	// MetricsOptions are options provided to Metrics call.
    96  	opts := madmin.MetricsOptions{
    97  		Type:     madmin.MetricsDisk,
    98  		Interval: time.Second,
    99  		ByDisk:   true,
   100  		N:        ctx.Int("count"),
   101  	}
   102  
   103  	p := tea.NewProgram(initTopDriveUI(disks, ctx.Int("count")))
   104  	go func() {
   105  		out := func(m madmin.RealtimeMetrics) {
   106  			for name, metric := range m.ByDisk {
   107  				p.Send(topDriveResult{
   108  					diskName: name,
   109  					stats:    metric.IOStats,
   110  				})
   111  			}
   112  		}
   113  
   114  		e := client.Metrics(ctxt, opts, out)
   115  		if e != nil {
   116  			fatalIf(probe.NewError(e), "Unable to fetch top drives events")
   117  		}
   118  		p.Quit()
   119  	}()
   120  
   121  	if _, e := p.Run(); e != nil {
   122  		cancel()
   123  		fatalIf(probe.NewError(e).Trace(aliasedURL), "Unable to fetch top drive events")
   124  	}
   125  
   126  	return nil
   127  }