github.com/minio/mc@v0.0.0-20240503112107-b471de8d1882/cmd/ilm-tier-list.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  	"cmp"
    22  	"fmt"
    23  	"slices"
    24  
    25  	"github.com/charmbracelet/lipgloss"
    26  	"github.com/charmbracelet/lipgloss/table"
    27  	"github.com/minio/cli"
    28  	json "github.com/minio/colorjson"
    29  	madmin "github.com/minio/madmin-go/v3"
    30  	"github.com/minio/mc/pkg/probe"
    31  )
    32  
    33  var adminTierListCmd = cli.Command{
    34  	Name:         "list",
    35  	ShortName:    "ls",
    36  	Usage:        "list configured remote tier targets",
    37  	Action:       mainAdminTierList,
    38  	OnUsageError: onUsageError,
    39  	Before:       setGlobalsFromContext,
    40  	Flags:        globalFlags,
    41  	CustomHelpTemplate: `NAME:
    42    {{.HelpName}} - {{.Usage}}
    43  
    44  USAGE:
    45    {{.HelpName}} ALIAS
    46  
    47  FLAGS:
    48    {{range .VisibleFlags}}{{.}}
    49    {{end}}
    50  
    51  EXAMPLES:
    52    1. List remote tier targets configured on 'myminio':
    53       {{.Prompt}} {{.HelpName}} myminio
    54  `,
    55  }
    56  
    57  // checkAdminTierListSyntax - validate all the passed arguments
    58  func checkAdminTierListSyntax(ctx *cli.Context) {
    59  	argsNr := len(ctx.Args())
    60  	if argsNr < 1 {
    61  		showCommandHelpAndExit(ctx, 1) // last argument is exit code
    62  	}
    63  	if argsNr > 1 {
    64  		fatalIf(errInvalidArgument().Trace(ctx.Args().Tail()...),
    65  			"Incorrect number of arguments for tier-ls subcommand.")
    66  	}
    67  }
    68  
    69  func storageClass(t *madmin.TierConfig) string {
    70  	switch t.Type {
    71  	case madmin.S3:
    72  		return t.S3.StorageClass
    73  	case madmin.Azure:
    74  		return t.Azure.StorageClass
    75  	case madmin.GCS:
    76  		return t.GCS.StorageClass
    77  	default:
    78  		return ""
    79  	}
    80  }
    81  
    82  type tierListMessage struct {
    83  	Status  string               `json:"status"`
    84  	Context *cli.Context         `json:"-"`
    85  	Tiers   []*madmin.TierConfig `json:"tiers"`
    86  }
    87  
    88  // String method returns a tabular listing of remote tier configurations.
    89  func (msg *tierListMessage) String() string {
    90  	return "" // Not used in rendering; only to satisfy msg interface
    91  }
    92  
    93  // JSON method returns JSON encoding of msg.
    94  func (msg *tierListMessage) JSON() string {
    95  	b, _ := json.Marshal(msg)
    96  	return string(b)
    97  }
    98  
    99  func mainAdminTierList(ctx *cli.Context) error {
   100  	checkAdminTierListSyntax(ctx)
   101  
   102  	args := ctx.Args()
   103  	aliasedURL := args.Get(0)
   104  
   105  	// Create a new MinIO Admin Client
   106  	client, cerr := newAdminClient(aliasedURL)
   107  	fatalIf(cerr, "Unable to initialize admin connection.")
   108  
   109  	tiers, e := client.ListTiers(globalContext)
   110  	fatalIf(probe.NewError(e).Trace(args...), "Unable to list configured remote tier targets")
   111  
   112  	if globalJSON {
   113  		printMsg(&tierListMessage{
   114  			Status:  "success",
   115  			Context: ctx,
   116  			Tiers:   tiers,
   117  		})
   118  		return nil
   119  	}
   120  
   121  	tableData := tierTable(tiers)
   122  	slices.SortFunc(tableData, func(a, b *madmin.TierConfig) int {
   123  		return cmp.Compare(a.Name, b.Name)
   124  	})
   125  	tbl := table.New().
   126  		Border(lipgloss.NormalBorder()).
   127  		Headers(tableData.Headers()...).
   128  		StyleFunc(func(row, _ int) lipgloss.Style {
   129  			switch {
   130  			case row == 0:
   131  				return lipgloss.NewStyle().Bold(true).Align(lipgloss.Center)
   132  			case row%2 == 0:
   133  				return lipgloss.NewStyle().Foreground(lipgloss.Color("3")).Align(lipgloss.Center)
   134  			default:
   135  				return lipgloss.NewStyle().Foreground(lipgloss.Color("4")).Align(lipgloss.Center)
   136  			}
   137  		}).
   138  		Data(tableData)
   139  	fmt.Println(tbl)
   140  	return nil
   141  }
   142  
   143  type tierTable []*madmin.TierConfig
   144  
   145  var _ table.Data = tierTable(nil)
   146  
   147  func (tt tierTable) Headers() []string {
   148  	return []string{
   149  		"Name",
   150  		"Type",
   151  		"Endpoint",
   152  		"Bucket",
   153  		"Prefix",
   154  		"Region",
   155  		"Storage-Class",
   156  	}
   157  }
   158  
   159  func (tt tierTable) At(row, col int) string {
   160  	tc := []*madmin.TierConfig(tt)
   161  	cell := ""
   162  	switch col {
   163  	case 0:
   164  		cell = tc[row].Name
   165  	case 1:
   166  		cell = tc[row].Type.String()
   167  	case 2:
   168  		cell = tc[row].Endpoint()
   169  	case 3:
   170  		cell = tc[row].Bucket()
   171  	case 4:
   172  		cell = tc[row].Prefix()
   173  	case 5:
   174  		cell = tc[row].Region()
   175  	case 6:
   176  		cell = storageClass(tc[row])
   177  	}
   178  	if cell == "" {
   179  		return "-"
   180  	}
   181  	return cell
   182  }
   183  
   184  func (tt tierTable) Rows() int {
   185  	return len(tt)
   186  }
   187  
   188  func (tt tierTable) Columns() int {
   189  	return len(tt.Headers())
   190  }