github.com/koderover/helm@v2.17.0+incompatible/pkg/tiller/release_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 tiller 18 19 import ( 20 "fmt" 21 "regexp" 22 23 "github.com/golang/protobuf/proto" 24 "k8s.io/helm/pkg/proto/hapi/release" 25 "k8s.io/helm/pkg/proto/hapi/services" 26 relutil "k8s.io/helm/pkg/releaseutil" 27 ) 28 29 // ListReleases lists the releases found by the server. 30 func (s *ReleaseServer) ListReleases(req *services.ListReleasesRequest, stream services.ReleaseService_ListReleasesServer) error { 31 if len(req.StatusCodes) == 0 { 32 req.StatusCodes = []release.Status_Code{release.Status_DEPLOYED} 33 } 34 35 //rels, err := s.env.Releases.ListDeployed() 36 rels, err := s.env.Releases.ListFilterAll(func(r *release.Release) bool { 37 for _, sc := range req.StatusCodes { 38 if sc == r.Info.Status.Code { 39 return true 40 } 41 } 42 return false 43 }) 44 if err != nil { 45 return err 46 } 47 48 if req.Namespace != "" { 49 rels, err = filterByNamespace(req.Namespace, rels) 50 if err != nil { 51 return err 52 } 53 } 54 55 if len(req.Filter) != 0 { 56 rels, err = filterReleases(req.Filter, rels) 57 if err != nil { 58 return err 59 } 60 } 61 62 total := int64(len(rels)) 63 64 switch req.SortBy { 65 case services.ListSort_NAME: 66 relutil.SortByName(rels) 67 case services.ListSort_LAST_RELEASED: 68 relutil.SortByDate(rels) 69 case services.ListSort_CHART_NAME: 70 relutil.SortByChartName(rels) 71 } 72 73 if req.SortOrder == services.ListSort_DESC { 74 ll := len(rels) 75 rr := make([]*release.Release, ll) 76 for i, item := range rels { 77 rr[ll-i-1] = item 78 } 79 rels = rr 80 } 81 82 l := int64(len(rels)) 83 if req.Offset != "" { 84 85 i := -1 86 for ii, cur := range rels { 87 if cur.Name == req.Offset { 88 i = ii 89 } 90 } 91 if i == -1 { 92 return fmt.Errorf("offset %q not found", req.Offset) 93 } 94 95 if len(rels) < i { 96 return fmt.Errorf("no items after %q", req.Offset) 97 } 98 99 rels = rels[i:] 100 l = int64(len(rels)) 101 } 102 103 if req.Limit == 0 { 104 req.Limit = ListDefaultLimit 105 } 106 107 next := "" 108 if l > req.Limit { 109 next = rels[req.Limit].Name 110 rels = rels[0:req.Limit] 111 l = int64(len(rels)) 112 } 113 res := &services.ListReleasesResponse{ 114 Next: next, 115 Count: l, 116 Total: total, 117 } 118 chunks := s.partition(rels[:min(len(rels), int(req.Limit))], maxMsgSize-proto.Size(res)) 119 for res.Releases = range chunks { 120 if err := stream.Send(res); err != nil { 121 for range chunks { // drain 122 } 123 return err 124 } 125 } 126 return nil 127 } 128 129 // partition packs releases into slices up to the capacity cap in bytes. 130 func (s *ReleaseServer) partition(rels []*release.Release, cap int) <-chan []*release.Release { 131 chunks := make(chan []*release.Release, 1) 132 go func() { 133 var ( 134 fill = 0 // fill is space available to fill 135 size int // size is size of a release 136 ) 137 var chunk []*release.Release 138 for _, rls := range rels { 139 if size = proto.Size(rls); size+fill > cap { 140 // Over-cap, push chunk onto channel to send over gRPC stream 141 s.Log("partitioned at %d with %d releases (cap=%d)", fill, len(chunk), cap) 142 chunks <- chunk 143 // reset partitioning state 144 chunk = nil 145 fill = 0 146 } 147 chunk = append(chunk, rls) 148 fill += size 149 } 150 if len(chunk) > 0 { 151 // send remaining if any 152 chunks <- chunk 153 } 154 close(chunks) 155 }() 156 return chunks 157 } 158 159 func filterByNamespace(namespace string, rels []*release.Release) ([]*release.Release, error) { 160 matches := []*release.Release{} 161 for _, r := range rels { 162 if namespace == r.Namespace { 163 matches = append(matches, r) 164 } 165 } 166 return matches, nil 167 } 168 169 func filterReleases(filter string, rels []*release.Release) ([]*release.Release, error) { 170 preg, err := regexp.Compile(filter) 171 if err != nil { 172 return rels, err 173 } 174 matches := []*release.Release{} 175 for _, r := range rels { 176 if preg.MatchString(r.Name) { 177 matches = append(matches, r) 178 } 179 } 180 return matches, nil 181 }