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 }