/
ilm-ls.go
281 lines (239 loc) · 7.74 KB
/
ilm-ls.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
// Copyright (c) 2015-2021 MinIO, Inc.
//
// This file is part of MinIO Object Storage stack
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package cmd
import (
"bytes"
"context"
"errors"
"strconv"
"strings"
"github.com/minio/cli"
json "github.com/minio/colorjson"
"github.com/filswan/fs3-mc/cmd/ilm"
"github.com/filswan/fs3-mc/pkg/probe"
"github.com/minio/minio-go/v7/pkg/lifecycle"
"github.com/minio/minio/pkg/console"
)
var ilmListFlags = []cli.Flag{
cli.BoolFlag{
Name: "expiry",
Usage: "display only expiration fields",
},
cli.BoolFlag{
Name: "transition",
Usage: "display only transition fields",
},
}
var ilmLsCmd = cli.Command{
Name: "ls",
Usage: "lists lifecycle configuration rules set on a bucket",
Action: mainILMList,
OnUsageError: onUsageError,
Before: setGlobalsFromContext,
Flags: append(ilmListFlags, globalFlags...),
CustomHelpTemplate: `NAME:
{{.HelpName}} - {{.Usage}}
USAGE:
{{.HelpName}} [FLAGS] TARGET
FLAGS:
{{range .VisibleFlags}}{{.}}
{{end}}
DESCRIPTION:
List lifecycle configuration rules set on a bucket.
EXAMPLES:
1. List the lifecycle management rules (all fields) for mybucket on alias 'myminio'.
{{.Prompt}} {{.HelpName}} myminio/mybucket
2. List the lifecycle management rules (expration date/days fields) for mybucket on alias 'myminio'.
{{.Prompt}} {{.HelpName}} --expiry myminio/mybucket
3. List the lifecycle management rules (transition date/days, storage class fields) for mybucket on alias 'myminio'.
{{.Prompt}} {{.HelpName}} --transition myminio/mybucket
4. List the lifecycle management rules in JSON format for mybucket on alias 'myminio'.
{{.Prompt}} {{.HelpName}} --json myminio/mybucket
`,
}
type ilmListMessage struct {
Status string `json:"status"`
Target string `json:"target"`
Context *cli.Context `json:"-"`
Config *lifecycle.Configuration `json:"config"`
}
func (i ilmListMessage) String() string {
showExpiry := i.Context.Bool("expiry")
showTransition := i.Context.Bool("transition")
// If none of the flags are explicitly mentioned, all fields are shown.
showAll := !showExpiry && !showTransition
var hdrLabelIndexMap map[string]int
var alignedHdrLabels []string
var cellDataNoTags [][]string
var cellDataWithTags [][]string
var tagRows map[string][]string
var tbl PrettyTable
ilm.PopulateILMDataForDisplay(i.Config, &hdrLabelIndexMap, &alignedHdrLabels,
&cellDataNoTags, &cellDataWithTags, &tagRows,
showAll, showExpiry, showTransition)
// Entire table content.
var tblContents string
// Fill up fields
var fields []Field
// The header table
for _, hdr := range alignedHdrLabels {
fields = append(fields, Field{ilmThemeHeader, len(hdr)})
}
tbl = newPrettyTable(tableSeperator, fields...)
tblContents = getILMHeader(&tbl, alignedHdrLabels...)
// Reuse the fields
fields = nil
// The data table
var tblRowField *[]string
if len(cellDataNoTags) == 0 {
tblRowField = &cellDataWithTags[0]
} else {
tblRowField = &cellDataNoTags[0]
}
for _, hdr := range *tblRowField {
fields = append(fields, Field{ilmThemeRow, len(hdr)})
}
tbl = newPrettyTable(tableSeperator, fields...)
tblContents += getILMRowsNoTags(&tbl, &cellDataNoTags)
tblContents += getILMRowsWithTags(&tbl, &cellDataWithTags, tagRows)
return tblContents
}
func (i ilmListMessage) JSON() string {
msgBytes, e := json.MarshalIndent(i, "", " ")
fatalIf(probe.NewError(e), "Unable to marshal into JSON.")
return string(msgBytes)
}
// validateILMListFlagSet - Only one of these flags needs to be set for display: --json, --expiry, --transition
func validateILMListFlagSet(ctx *cli.Context) bool {
var flags = [...]bool{ctx.Bool("expiry"), ctx.Bool("transition"), ctx.Bool("json")}
found := false
for _, flag := range flags {
if found && flag {
return false
} else if flag {
found = true
}
}
return true
}
// checkILMListSyntax - validate arguments passed by a user
func checkILMListSyntax(ctx *cli.Context) {
if len(ctx.Args()) != 1 {
cli.ShowCommandHelpAndExit(ctx, "ls", globalErrorExitStatus)
}
if !validateILMListFlagSet(ctx) {
fatalIf(errInvalidArgument(), "only one display field flag is allowed per ls command. Refer mc "+ctx.Command.FullName()+" --help.")
}
}
const tableSeperator = "|"
func getILMHeader(tbl *PrettyTable, alignedHdrLabels ...string) string {
if len(alignedHdrLabels) == 0 {
return ""
}
row := tbl.buildRow(alignedHdrLabels...)
header := console.Colorize(ilmThemeHeader, row+"\n")
lineRow := buildILMTableLineRow(alignedHdrLabels...)
row = tbl.buildRow(lineRow...)
row = console.Colorize(ilmThemeHeader, row+"\n")
header += row
return header
}
func buildILMTableLineRow(rowArr ...string) []string {
lineRowArr := make([]string, len(rowArr))
for index := 0; index < len(rowArr); index++ {
var tagBfr bytes.Buffer
for rowArrChars := 0; rowArrChars < len(rowArr[index]); rowArrChars++ {
tagBfr.WriteByte('-')
}
lineRowArr[index] = tagBfr.String()
}
return lineRowArr
}
func getILMRowsNoTags(tbl *PrettyTable, cellDataNoTags *[][]string) string {
if cellDataNoTags == nil || len(*cellDataNoTags) == 0 {
return ""
}
var rows string
for _, rowArr := range *cellDataNoTags {
var row string // Table row
// Build & print row
row = tbl.buildRow(rowArr...)
row = console.Colorize(ilmThemeRow, row)
rows += row + "\n"
lineRow := buildILMTableLineRow(rowArr...)
row = tbl.buildRow(lineRow...)
row = console.Colorize(ilmThemeRow, row)
rows += row + "\n"
}
return rows
}
func getILMRowsWithTags(tbl *PrettyTable, cellDataWithTags *[][]string, newRows map[string][]string) string {
if cellDataWithTags == nil || len(*cellDataWithTags) == 0 {
return ""
}
var rows string
for _, rowArr := range *cellDataWithTags {
if rowArr == nil {
continue
}
var row string // Table row
// Build & print row
row = tbl.buildRow(rowArr...)
row = console.Colorize(ilmThemeRow, row)
rows += row + "\n"
// Add the extra blank rows & tag value in the right column
if len(newRows) > 0 {
for index := 0; index < len(newRows); index++ {
newRow, ok := newRows[strings.TrimSpace(rowArr[0])+strconv.Itoa(index)]
if ok {
row = tbl.buildRow(newRow...)
row = console.Colorize(ilmThemeRow, row)
rows += row + "\n"
}
}
}
// Build & print the line row
lineRow := buildILMTableLineRow(rowArr...)
row = tbl.buildRow(lineRow...)
row = console.Colorize(ilmThemeRow, row)
rows += row + "\n"
}
return rows
}
func mainILMList(cliCtx *cli.Context) error {
ctx, cancelILMList := context.WithCancel(globalContext)
defer cancelILMList()
checkILMListSyntax(cliCtx)
setILMDisplayColorScheme()
args := cliCtx.Args()
urlStr := args.Get(0)
client, err := newClient(urlStr)
fatalIf(err.Trace(urlStr), "Unable to initialize client for "+urlStr)
ilmCfg, err := client.GetLifecycle(ctx)
fatalIf(err.Trace(args...), "Unable to get lifecycle")
if len(ilmCfg.Rules) == 0 {
fatalIf(probe.NewError(errors.New("lifecycle configuration not set")).Trace(urlStr),
"Unable to ls lifecycle configuration")
}
printMsg(ilmListMessage{
Status: "success",
Target: urlStr,
Context: cliCtx,
Config: ilmCfg,
})
return nil
}