github.com/umeshredd/helm@v3.0.0-alpha.1+incompatible/pkg/action/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 action 18 19 import ( 20 "fmt" 21 "regexp" 22 23 "github.com/gosuri/uitable" 24 25 "helm.sh/helm/pkg/release" 26 "helm.sh/helm/pkg/releaseutil" 27 ) 28 29 // ListStates represents zero or more status codes that a list item may have set 30 // 31 // Because this is used as a bitmask filter, more than one one bit can be flipped 32 // in the ListStates. 33 type ListStates uint 34 35 const ( 36 // ListDeployed filters on status "deployed" 37 ListDeployed ListStates = 1 << iota 38 // ListUninstalled filters on status "uninstalled" 39 ListUninstalled 40 // ListUninstalling filters on status "uninstalling" (uninstall in progress) 41 ListUninstalling 42 // ListPendingInstall filters on status "pending" (deployment in progress) 43 ListPendingInstall 44 // ListPendingUpgrade filters on status "pending_upgrade" (upgrade in progress) 45 ListPendingUpgrade 46 // ListPendingRollback filters on status "pending_rollback" (rollback in progres) 47 ListPendingRollback 48 // ListSuperseded filters on status "superseded" (historical release version that is no longer deployed) 49 ListSuperseded 50 // ListFailed filters on status "failed" (release version not deployed because of error) 51 ListFailed 52 // ListUnknown filters on an unknown status 53 ListUnknown 54 ) 55 56 // FromName takes a state name and returns a ListStates representation. 57 // 58 // Currently, there are only names for individual flipped bits, so the returned 59 // ListStates will only match one of the constants. However, it is possible that 60 // this behavior could change in the future. 61 func (s ListStates) FromName(str string) ListStates { 62 switch str { 63 case "deployed": 64 return ListDeployed 65 case "uninstalled": 66 return ListUninstalled 67 case "superseded": 68 return ListSuperseded 69 case "failed": 70 return ListFailed 71 case "uninstalling": 72 return ListUninstalling 73 case "pending-install": 74 return ListPendingInstall 75 case "pending-upgrade": 76 return ListPendingUpgrade 77 case "pending-rollback": 78 return ListPendingRollback 79 } 80 return ListUnknown 81 } 82 83 // ListAll is a convenience for enabling all list filters 84 const ListAll = ListDeployed | ListUninstalled | ListUninstalling | ListPendingInstall | ListPendingRollback | ListPendingUpgrade | ListSuperseded | ListFailed 85 86 // Sorter is a top-level sort 87 type Sorter uint 88 89 const ( 90 // ByDate sorts by date 91 ByDate Sorter = iota 92 // ByNameAsc sorts by ascending lexicographic order 93 ByNameAsc 94 // ByNameDesc sorts by descending lexicographic order 95 ByNameDesc 96 ) 97 98 // List is the action for listing releases. 99 // 100 // It provides, for example, the implementation of 'helm list'. 101 type List struct { 102 cfg *Configuration 103 104 // All ignores the limit/offset 105 All bool 106 // AllNamespaces searches across namespaces 107 AllNamespaces bool 108 // Sort indicates the sort to use 109 // 110 // see pkg/releaseutil for several useful sorters 111 Sort Sorter 112 // StateMask accepts a bitmask of states for items to show. 113 // The default is ListDeployed 114 StateMask ListStates 115 // Limit is the number of items to return per Run() 116 Limit int 117 // Offset is the starting index for the Run() call 118 Offset int 119 // Filter is a filter that is applied to the results 120 Filter string 121 Short bool 122 ByDate bool 123 SortDesc bool 124 Uninstalled bool 125 Superseded bool 126 Uninstalling bool 127 Deployed bool 128 Failed bool 129 Pending bool 130 } 131 132 // NewList constructs a new *List 133 func NewList(cfg *Configuration) *List { 134 return &List{ 135 StateMask: ListDeployed | ListFailed, 136 cfg: cfg, 137 } 138 } 139 140 func (l *List) SetConfiguration(cfg *Configuration) { 141 l.cfg = cfg 142 } 143 144 // Run executes the list command, returning a set of matches. 145 func (l *List) Run() ([]*release.Release, error) { 146 var filter *regexp.Regexp 147 if l.Filter != "" { 148 var err error 149 filter, err = regexp.Compile(l.Filter) 150 if err != nil { 151 return nil, err 152 } 153 } 154 155 results, err := l.cfg.Releases.List(func(rel *release.Release) bool { 156 // Skip anything that the mask doesn't cover 157 currentStatus := l.StateMask.FromName(rel.Info.Status.String()) 158 if l.StateMask¤tStatus == 0 { 159 return false 160 } 161 162 // Skip anything that doesn't match the filter. 163 if filter != nil && !filter.MatchString(rel.Name) { 164 return false 165 } 166 return true 167 }) 168 169 if results == nil { 170 return results, nil 171 } 172 173 // Unfortunately, we have to sort before truncating, which can incur substantial overhead 174 l.sort(results) 175 176 // Guard on offset 177 if l.Offset >= len(results) { 178 return []*release.Release{}, nil 179 } 180 181 // Calculate the limit and offset, and then truncate results if necessary. 182 limit := len(results) 183 if l.Limit > 0 && l.Limit < limit { 184 limit = l.Limit 185 } 186 last := l.Offset + limit 187 if l := len(results); l < last { 188 last = l 189 } 190 results = results[l.Offset:last] 191 192 return results, err 193 } 194 195 // sort is an in-place sort where order is based on the value of a.Sort 196 func (l *List) sort(rels []*release.Release) { 197 switch l.Sort { 198 case ByDate: 199 releaseutil.SortByDate(rels) 200 case ByNameDesc: 201 releaseutil.Reverse(rels, releaseutil.SortByName) 202 default: 203 releaseutil.SortByName(rels) 204 } 205 } 206 207 // setStateMask calculates the state mask based on parameters. 208 func (l *List) SetStateMask() { 209 if l.All { 210 l.StateMask = ListAll 211 return 212 } 213 214 state := ListStates(0) 215 if l.Deployed { 216 state |= ListDeployed 217 } 218 if l.Uninstalled { 219 state |= ListUninstalled 220 } 221 if l.Uninstalling { 222 state |= ListUninstalling 223 } 224 if l.Pending { 225 state |= ListPendingInstall | ListPendingRollback | ListPendingUpgrade 226 } 227 if l.Failed { 228 state |= ListFailed 229 } 230 231 // Apply a default 232 if state == 0 { 233 state = ListDeployed | ListFailed 234 } 235 236 l.StateMask = state 237 } 238 239 func FormatList(rels []*release.Release) string { 240 table := uitable.New() 241 table.AddRow("NAME", "NAMESPACE", "REVISION", "UPDATED", "STATUS", "CHART") 242 for _, r := range rels { 243 md := r.Chart.Metadata 244 c := fmt.Sprintf("%s-%s", md.Name, md.Version) 245 t := "-" 246 if tspb := r.Info.LastDeployed; !tspb.IsZero() { 247 t = tspb.String() 248 } 249 s := r.Info.Status.String() 250 v := r.Version 251 n := r.Namespace 252 table.AddRow(r.Name, n, v, t, s, c) 253 } 254 return table.String() 255 }