github.com/werf/3p-helm@v2.8.1+incompatible/cmd/helm/list.go (about) 1 /* 2 Copyright 2016 The Kubernetes Authors All rights reserved. 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 "fmt" 21 "io" 22 "strings" 23 24 "github.com/gosuri/uitable" 25 "github.com/spf13/cobra" 26 27 "k8s.io/helm/pkg/helm" 28 "k8s.io/helm/pkg/proto/hapi/release" 29 "k8s.io/helm/pkg/proto/hapi/services" 30 "k8s.io/helm/pkg/timeconv" 31 ) 32 33 var listHelp = ` 34 This command lists all of the releases. 35 36 By default, it lists only releases that are deployed or failed. Flags like 37 '--deleted' and '--all' will alter this behavior. Such flags can be combined: 38 '--deleted --failed'. 39 40 By default, items are sorted alphabetically. Use the '-d' flag to sort by 41 release date. 42 43 If an argument is provided, it will be treated as a filter. Filters are 44 regular expressions (Perl compatible) that are applied to the list of releases. 45 Only items that match the filter will be returned. 46 47 $ helm list 'ara[a-z]+' 48 NAME UPDATED CHART 49 maudlin-arachnid Mon May 9 16:07:08 2016 alpine-0.1.0 50 51 If no results are found, 'helm list' will exit 0, but with no output (or in 52 the case of no '-q' flag, only headers). 53 54 By default, up to 256 items may be returned. To limit this, use the '--max' flag. 55 Setting '--max' to 0 will not return all results. Rather, it will return the 56 server's default, which may be much higher than 256. Pairing the '--max' 57 flag with the '--offset' flag allows you to page through results. 58 ` 59 60 type listCmd struct { 61 filter string 62 short bool 63 limit int 64 offset string 65 byDate bool 66 sortDesc bool 67 out io.Writer 68 all bool 69 deleted bool 70 deleting bool 71 deployed bool 72 failed bool 73 namespace string 74 superseded bool 75 pending bool 76 client helm.Interface 77 colWidth uint 78 } 79 80 func newListCmd(client helm.Interface, out io.Writer) *cobra.Command { 81 list := &listCmd{ 82 out: out, 83 client: client, 84 } 85 86 cmd := &cobra.Command{ 87 Use: "list [flags] [FILTER]", 88 Short: "list releases", 89 Long: listHelp, 90 Aliases: []string{"ls"}, 91 PreRunE: setupConnection, 92 RunE: func(cmd *cobra.Command, args []string) error { 93 if len(args) > 0 { 94 list.filter = strings.Join(args, " ") 95 } 96 if list.client == nil { 97 list.client = newClient() 98 } 99 return list.run() 100 }, 101 } 102 103 f := cmd.Flags() 104 f.BoolVarP(&list.short, "short", "q", false, "output short (quiet) listing format") 105 f.BoolVarP(&list.byDate, "date", "d", false, "sort by release date") 106 f.BoolVarP(&list.sortDesc, "reverse", "r", false, "reverse the sort order") 107 f.IntVarP(&list.limit, "max", "m", 256, "maximum number of releases to fetch") 108 f.StringVarP(&list.offset, "offset", "o", "", "next release name in the list, used to offset from start value") 109 f.BoolVarP(&list.all, "all", "a", false, "show all releases, not just the ones marked DEPLOYED") 110 f.BoolVar(&list.deleted, "deleted", false, "show deleted releases") 111 f.BoolVar(&list.deleting, "deleting", false, "show releases that are currently being deleted") 112 f.BoolVar(&list.deployed, "deployed", false, "show deployed releases. If no other is specified, this will be automatically enabled") 113 f.BoolVar(&list.failed, "failed", false, "show failed releases") 114 f.BoolVar(&list.pending, "pending", false, "show pending releases") 115 f.StringVar(&list.namespace, "namespace", "", "show releases within a specific namespace") 116 f.UintVar(&list.colWidth, "col-width", 60, "specifies the max column width of output") 117 118 // TODO: Do we want this as a feature of 'helm list'? 119 //f.BoolVar(&list.superseded, "history", true, "show historical releases") 120 121 return cmd 122 } 123 124 func (l *listCmd) run() error { 125 sortBy := services.ListSort_NAME 126 if l.byDate { 127 sortBy = services.ListSort_LAST_RELEASED 128 } 129 130 sortOrder := services.ListSort_ASC 131 if l.sortDesc { 132 sortOrder = services.ListSort_DESC 133 } 134 135 stats := l.statusCodes() 136 137 res, err := l.client.ListReleases( 138 helm.ReleaseListLimit(l.limit), 139 helm.ReleaseListOffset(l.offset), 140 helm.ReleaseListFilter(l.filter), 141 helm.ReleaseListSort(int32(sortBy)), 142 helm.ReleaseListOrder(int32(sortOrder)), 143 helm.ReleaseListStatuses(stats), 144 helm.ReleaseListNamespace(l.namespace), 145 ) 146 147 if err != nil { 148 return prettyError(err) 149 } 150 151 if len(res.Releases) == 0 { 152 return nil 153 } 154 155 if res.Next != "" && !l.short { 156 fmt.Fprintf(l.out, "\tnext: %s\n", res.Next) 157 } 158 159 rels := filterList(res.Releases) 160 161 if l.short { 162 for _, r := range rels { 163 fmt.Fprintln(l.out, r.Name) 164 } 165 return nil 166 } 167 fmt.Fprintln(l.out, formatList(rels, l.colWidth)) 168 return nil 169 } 170 171 // filterList returns a list scrubbed of old releases. 172 func filterList(rels []*release.Release) []*release.Release { 173 idx := map[string]int32{} 174 175 for _, r := range rels { 176 name, version := r.GetName(), r.GetVersion() 177 if max, ok := idx[name]; ok { 178 // check if we have a greater version already 179 if max > version { 180 continue 181 } 182 } 183 idx[name] = version 184 } 185 186 uniq := make([]*release.Release, 0, len(idx)) 187 for _, r := range rels { 188 if idx[r.GetName()] == r.GetVersion() { 189 uniq = append(uniq, r) 190 } 191 } 192 return uniq 193 } 194 195 // statusCodes gets the list of status codes that are to be included in the results. 196 func (l *listCmd) statusCodes() []release.Status_Code { 197 if l.all { 198 return []release.Status_Code{ 199 release.Status_UNKNOWN, 200 release.Status_DEPLOYED, 201 release.Status_DELETED, 202 release.Status_DELETING, 203 release.Status_FAILED, 204 release.Status_PENDING_INSTALL, 205 release.Status_PENDING_UPGRADE, 206 release.Status_PENDING_ROLLBACK, 207 } 208 } 209 status := []release.Status_Code{} 210 if l.deployed { 211 status = append(status, release.Status_DEPLOYED) 212 } 213 if l.deleted { 214 status = append(status, release.Status_DELETED) 215 } 216 if l.deleting { 217 status = append(status, release.Status_DELETING) 218 } 219 if l.failed { 220 status = append(status, release.Status_FAILED) 221 } 222 if l.superseded { 223 status = append(status, release.Status_SUPERSEDED) 224 } 225 if l.pending { 226 status = append(status, release.Status_PENDING_INSTALL, release.Status_PENDING_UPGRADE, release.Status_PENDING_ROLLBACK) 227 } 228 229 // Default case. 230 if len(status) == 0 { 231 status = append(status, release.Status_DEPLOYED, release.Status_FAILED) 232 } 233 return status 234 } 235 236 func formatList(rels []*release.Release, colWidth uint) string { 237 table := uitable.New() 238 239 table.MaxColWidth = colWidth 240 table.AddRow("NAME", "REVISION", "UPDATED", "STATUS", "CHART", "NAMESPACE") 241 for _, r := range rels { 242 c := fmt.Sprintf("%s-%s", r.Chart.Metadata.Name, r.Chart.Metadata.Version) 243 t := timeconv.String(r.Info.LastDeployed) 244 s := r.Info.Status.Code.String() 245 v := r.Version 246 n := r.Namespace 247 table.AddRow(r.Name, v, t, s, c, n) 248 } 249 return table.String() 250 }