github.com/defensepoint-snyk-test/helm-new@v0.0.0-20211130153739-c57ea64d6603/cmd/helm/list.go (about) 1 /* 2 Copyright The Helm Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package main 18 19 import ( 20 "encoding/json" 21 "fmt" 22 "io" 23 "strings" 24 25 "github.com/ghodss/yaml" 26 "github.com/gosuri/uitable" 27 "github.com/spf13/cobra" 28 29 "k8s.io/helm/pkg/helm" 30 "k8s.io/helm/pkg/proto/hapi/release" 31 "k8s.io/helm/pkg/proto/hapi/services" 32 "k8s.io/helm/pkg/timeconv" 33 ) 34 35 var listHelp = ` 36 This command lists all of the releases. 37 38 By default, it lists only releases that are deployed or failed. Flags like 39 '--deleted' and '--all' will alter this behavior. Such flags can be combined: 40 '--deleted --failed'. 41 42 By default, items are sorted alphabetically. Use the '-d' flag to sort by 43 release date. 44 45 If an argument is provided, it will be treated as a filter. Filters are 46 regular expressions (Perl compatible) that are applied to the list of releases. 47 Only items that match the filter will be returned. 48 49 $ helm list 'ara[a-z]+' 50 NAME UPDATED CHART 51 maudlin-arachnid Mon May 9 16:07:08 2016 alpine-0.1.0 52 53 If no results are found, 'helm list' will exit 0, but with no output (or in 54 the case of no '-q' flag, only headers). 55 56 By default, up to 256 items may be returned. To limit this, use the '--max' flag. 57 Setting '--max' to 0 will not return all results. Rather, it will return the 58 server's default, which may be much higher than 256. Pairing the '--max' 59 flag with the '--offset' flag allows you to page through results. 60 ` 61 62 type listCmd struct { 63 filter string 64 short bool 65 limit int 66 offset string 67 byDate bool 68 sortDesc bool 69 out io.Writer 70 all bool 71 deleted bool 72 deleting bool 73 deployed bool 74 failed bool 75 namespace string 76 superseded bool 77 pending bool 78 client helm.Interface 79 colWidth uint 80 output string 81 byChartName bool 82 } 83 84 type listResult struct { 85 Next string 86 Releases []listRelease 87 } 88 89 type listRelease struct { 90 Name string 91 Revision int32 92 Updated string 93 Status string 94 Chart string 95 AppVersion string 96 Namespace string 97 } 98 99 func newListCmd(client helm.Interface, out io.Writer) *cobra.Command { 100 list := &listCmd{ 101 out: out, 102 client: client, 103 } 104 105 cmd := &cobra.Command{ 106 Use: "list [flags] [FILTER]", 107 Short: "list releases", 108 Long: listHelp, 109 Aliases: []string{"ls"}, 110 PreRunE: func(_ *cobra.Command, _ []string) error { return setupConnection() }, 111 RunE: func(cmd *cobra.Command, args []string) error { 112 if len(args) > 0 { 113 list.filter = strings.Join(args, " ") 114 } 115 if list.client == nil { 116 list.client = newClient() 117 } 118 return list.run() 119 }, 120 } 121 122 f := cmd.Flags() 123 settings.AddFlagsTLS(f) 124 f.BoolVarP(&list.short, "short", "q", false, "output short (quiet) listing format") 125 f.BoolVarP(&list.byDate, "date", "d", false, "sort by release date") 126 f.BoolVarP(&list.sortDesc, "reverse", "r", false, "reverse the sort order") 127 f.IntVarP(&list.limit, "max", "m", 256, "maximum number of releases to fetch") 128 f.StringVarP(&list.offset, "offset", "o", "", "next release name in the list, used to offset from start value") 129 f.BoolVarP(&list.all, "all", "a", false, "show all releases, not just the ones marked DEPLOYED") 130 f.BoolVar(&list.deleted, "deleted", false, "show deleted releases") 131 f.BoolVar(&list.deleting, "deleting", false, "show releases that are currently being deleted") 132 f.BoolVar(&list.deployed, "deployed", false, "show deployed releases. If no other is specified, this will be automatically enabled") 133 f.BoolVar(&list.failed, "failed", false, "show failed releases") 134 f.BoolVar(&list.pending, "pending", false, "show pending releases") 135 f.StringVar(&list.namespace, "namespace", "", "show releases within a specific namespace") 136 f.UintVar(&list.colWidth, "col-width", 60, "specifies the max column width of output") 137 f.StringVar(&list.output, "output", "", "output the specified format (json or yaml)") 138 f.BoolVarP(&list.byChartName, "chart-name", "c", false, "sort by chart name") 139 140 // TODO: Do we want this as a feature of 'helm list'? 141 //f.BoolVar(&list.superseded, "history", true, "show historical releases") 142 143 // set defaults from environment 144 settings.InitTLS(f) 145 146 return cmd 147 } 148 149 func (l *listCmd) run() error { 150 sortBy := services.ListSort_NAME 151 if l.byDate { 152 sortBy = services.ListSort_LAST_RELEASED 153 } 154 if l.byChartName { 155 sortBy = services.ListSort_CHART_NAME 156 } 157 158 sortOrder := services.ListSort_ASC 159 if l.sortDesc { 160 sortOrder = services.ListSort_DESC 161 } 162 163 stats := l.statusCodes() 164 165 res, err := l.client.ListReleases( 166 helm.ReleaseListLimit(l.limit), 167 helm.ReleaseListOffset(l.offset), 168 helm.ReleaseListFilter(l.filter), 169 helm.ReleaseListSort(int32(sortBy)), 170 helm.ReleaseListOrder(int32(sortOrder)), 171 helm.ReleaseListStatuses(stats), 172 helm.ReleaseListNamespace(l.namespace), 173 ) 174 175 if err != nil { 176 return prettyError(err) 177 } 178 if res == nil { 179 return nil 180 } 181 182 rels := filterList(res.GetReleases()) 183 184 result := getListResult(rels, res.Next) 185 186 output, err := formatResult(l.output, l.short, result, l.colWidth) 187 188 if err != nil { 189 return prettyError(err) 190 } 191 192 fmt.Fprintln(l.out, output) 193 return nil 194 } 195 196 // filterList returns a list scrubbed of old releases. 197 func filterList(rels []*release.Release) []*release.Release { 198 idx := map[string]int32{} 199 200 for _, r := range rels { 201 name, version := r.GetName(), r.GetVersion() 202 if max, ok := idx[name]; ok { 203 // check if we have a greater version already 204 if max > version { 205 continue 206 } 207 } 208 idx[name] = version 209 } 210 211 uniq := make([]*release.Release, 0, len(idx)) 212 for _, r := range rels { 213 if idx[r.GetName()] == r.GetVersion() { 214 uniq = append(uniq, r) 215 } 216 } 217 return uniq 218 } 219 220 // statusCodes gets the list of status codes that are to be included in the results. 221 func (l *listCmd) statusCodes() []release.Status_Code { 222 if l.all { 223 return []release.Status_Code{ 224 release.Status_UNKNOWN, 225 release.Status_DEPLOYED, 226 release.Status_DELETED, 227 release.Status_DELETING, 228 release.Status_FAILED, 229 release.Status_PENDING_INSTALL, 230 release.Status_PENDING_UPGRADE, 231 release.Status_PENDING_ROLLBACK, 232 } 233 } 234 status := []release.Status_Code{} 235 if l.deployed { 236 status = append(status, release.Status_DEPLOYED) 237 } 238 if l.deleted { 239 status = append(status, release.Status_DELETED) 240 } 241 if l.deleting { 242 status = append(status, release.Status_DELETING) 243 } 244 if l.failed { 245 status = append(status, release.Status_FAILED) 246 } 247 if l.superseded { 248 status = append(status, release.Status_SUPERSEDED) 249 } 250 if l.pending { 251 status = append(status, release.Status_PENDING_INSTALL, release.Status_PENDING_UPGRADE, release.Status_PENDING_ROLLBACK) 252 } 253 254 // Default case. 255 if len(status) == 0 { 256 status = append(status, release.Status_DEPLOYED, release.Status_FAILED) 257 } 258 return status 259 } 260 261 func getListResult(rels []*release.Release, next string) listResult { 262 listReleases := []listRelease{} 263 for _, r := range rels { 264 md := r.GetChart().GetMetadata() 265 t := "-" 266 if tspb := r.GetInfo().GetLastDeployed(); tspb != nil { 267 t = timeconv.String(tspb) 268 } 269 270 lr := listRelease{ 271 Name: r.GetName(), 272 Revision: r.GetVersion(), 273 Updated: t, 274 Status: r.GetInfo().GetStatus().GetCode().String(), 275 Chart: fmt.Sprintf("%s-%s", md.GetName(), md.GetVersion()), 276 AppVersion: md.GetAppVersion(), 277 Namespace: r.GetNamespace(), 278 } 279 listReleases = append(listReleases, lr) 280 } 281 282 return listResult{ 283 Releases: listReleases, 284 Next: next, 285 } 286 } 287 288 func shortenListResult(result listResult) []string { 289 names := []string{} 290 for _, r := range result.Releases { 291 names = append(names, r.Name) 292 } 293 294 return names 295 } 296 297 func formatResult(format string, short bool, result listResult, colWidth uint) (string, error) { 298 var output string 299 var err error 300 301 var shortResult []string 302 var finalResult interface{} 303 if short { 304 shortResult = shortenListResult(result) 305 finalResult = shortResult 306 } else { 307 finalResult = result 308 } 309 310 switch format { 311 case "": 312 if short { 313 output = formatTextShort(shortResult) 314 } else { 315 output = formatText(result, colWidth) 316 } 317 case "json": 318 o, e := json.Marshal(finalResult) 319 if e != nil { 320 err = fmt.Errorf("Failed to Marshal JSON output: %s", e) 321 } else { 322 output = string(o) 323 } 324 case "yaml": 325 o, e := yaml.Marshal(finalResult) 326 if e != nil { 327 err = fmt.Errorf("Failed to Marshal YAML output: %s", e) 328 } else { 329 output = string(o) 330 } 331 default: 332 err = fmt.Errorf("Unknown output format \"%s\"", format) 333 } 334 return output, err 335 } 336 337 func formatText(result listResult, colWidth uint) string { 338 nextOutput := "" 339 if result.Next != "" { 340 nextOutput = fmt.Sprintf("\tnext: %s\n", result.Next) 341 } 342 343 table := uitable.New() 344 table.MaxColWidth = colWidth 345 table.AddRow("NAME", "REVISION", "UPDATED", "STATUS", "CHART", "APP VERSION", "NAMESPACE") 346 for _, lr := range result.Releases { 347 table.AddRow(lr.Name, lr.Revision, lr.Updated, lr.Status, lr.Chart, lr.AppVersion, lr.Namespace) 348 } 349 350 return fmt.Sprintf("%s%s", nextOutput, table.String()) 351 } 352 353 func formatTextShort(shortResult []string) string { 354 return strings.Join(shortResult, "\n") 355 }