github.com/wangchanggan/helm@v0.0.0-20211020154240-11b1b7d5406d/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 // 检查客户端需要查询的Release状态码。 32 if len(req.StatusCodes) == 0 { 33 req.StatusCodes = []release.Status_Code{release.Status_DEPLOYED} 34 } 35 36 //rels, err := s.env.Releases.ListDeployed() 37 // 调用s.env.Releases.ListFilterAll查询对应的Release。 38 rels, err := s.env.Releases.ListFilterAll(func(r *release.Release) bool { 39 for _, sc := range req.StatusCodes { 40 if sc == r.Info.Status.Code { 41 return true 42 } 43 } 44 return false 45 }) 46 if err != nil { 47 return err 48 } 49 50 // 根据命名空间判断是否是需要的Release。 51 if req.Namespace != "" { 52 rels, err = filterByNamespace(req.Namespace, rels) 53 if err != nil { 54 return err 55 } 56 } 57 58 // 根据客户端传递来的过滤值进行对应的过滤。 59 if len(req.Filter) != 0 { 60 rels, err = filterReleases(req.Filter, rels) 61 if err != nil { 62 return err 63 } 64 } 65 66 total := int64(len(rels)) 67 68 // 根据客户端传递过来的排序方法进行排序。 69 switch req.SortBy { 70 case services.ListSort_NAME: 71 relutil.SortByName(rels) 72 case services.ListSort_LAST_RELEASED: 73 relutil.SortByDate(rels) 74 case services.ListSort_CHART_NAME: 75 relutil.SortByChartName(rels) 76 } 77 78 if req.SortOrder == services.ListSort_DESC { 79 ll := len(rels) 80 rr := make([]*release.Release, ll) 81 for i, item := range rels { 82 rr[ll-i-1] = item 83 } 84 rels = rr 85 } 86 87 l := int64(len(rels)) 88 if req.Offset != "" { 89 90 i := -1 91 for ii, cur := range rels { 92 if cur.Name == req.Offset { 93 i = ii 94 } 95 } 96 if i == -1 { 97 return fmt.Errorf("offset %q not found", req.Offset) 98 } 99 100 if len(rels) < i { 101 return fmt.Errorf("no items after %q", req.Offset) 102 } 103 104 rels = rels[i:] 105 l = int64(len(rels)) 106 } 107 108 if req.Limit == 0 { 109 req.Limit = ListDefaultLimit 110 } 111 112 next := "" 113 if l > req.Limit { 114 next = rels[req.Limit].Name 115 rels = rels[0:req.Limit] 116 l = int64(len(rels)) 117 } 118 res := &services.ListReleasesResponse{ 119 Next: next, 120 Count: l, 121 Total: total, 122 } 123 chunks := s.partition(rels[:min(len(rels), int(req.Limit))], maxMsgSize-proto.Size(res)) 124 for res.Releases = range chunks { 125 if err := stream.Send(res); err != nil { 126 for range chunks { // drain 127 } 128 return err 129 } 130 } 131 return nil 132 } 133 134 // partition packs releases into slices up to the capacity cap in bytes. 135 func (s *ReleaseServer) partition(rels []*release.Release, cap int) <-chan []*release.Release { 136 chunks := make(chan []*release.Release, 1) 137 go func() { 138 var ( 139 fill = 0 // fill is space available to fill 140 size int // size is size of a release 141 ) 142 var chunk []*release.Release 143 for _, rls := range rels { 144 if size = proto.Size(rls); size+fill > cap { 145 // Over-cap, push chunk onto channel to send over gRPC stream 146 s.Log("partitioned at %d with %d releases (cap=%d)", fill, len(chunk), cap) 147 chunks <- chunk 148 // reset partitioning state 149 chunk = nil 150 fill = 0 151 } 152 chunk = append(chunk, rls) 153 fill += size 154 } 155 if len(chunk) > 0 { 156 // send remaining if any 157 chunks <- chunk 158 } 159 close(chunks) 160 }() 161 return chunks 162 } 163 164 func filterByNamespace(namespace string, rels []*release.Release) ([]*release.Release, error) { 165 matches := []*release.Release{} 166 for _, r := range rels { 167 if namespace == r.Namespace { 168 matches = append(matches, r) 169 } 170 } 171 return matches, nil 172 } 173 174 func filterReleases(filter string, rels []*release.Release) ([]*release.Release, error) { 175 preg, err := regexp.Compile(filter) 176 if err != nil { 177 return rels, err 178 } 179 matches := []*release.Release{} 180 for _, r := range rels { 181 if preg.MatchString(r.Name) { 182 matches = append(matches, r) 183 } 184 } 185 return matches, nil 186 }