Skip to content

Commit 8d40887

Browse files
author
Matthew Fisher
committed
Fix race condition in helm list (helm#4620)
* Fix race in helm list when partitioning Problem: The chunks slice that is passed through the channel is reused for each partition. This means that encoding the release into a message is racing with populating the next partition, causing the results to sometimes not fit in the message, and the release list to be incorrect Solution: Allocate a new slice for each partition Issue helm#3322 Signed-off-by: Brian Marshall <bmarshall13@users.noreply.github.com> (cherry picked from commit a0858e2) * fix import sorting Signed-off-by: Matthew Fisher <matt.fisher@microsoft.com> * ref(release_server_test): use NewReleaseServer() Signed-off-by: Matthew Fisher <matt.fisher@microsoft.com> * add unit test for race condition in `helm list` Signed-off-by: Matthew Fisher <matt.fisher@microsoft.com> (cherry picked from commit 5b23632)
1 parent 67b142a commit 8d40887

File tree

3 files changed

+30
-14
lines changed

3 files changed

+30
-14
lines changed

pkg/tiller/release_list.go

+3-2
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,12 @@ package tiller
1818

1919
import (
2020
"fmt"
21+
"regexp"
22+
2123
"github.com/golang/protobuf/proto"
2224
"k8s.io/helm/pkg/proto/hapi/release"
2325
"k8s.io/helm/pkg/proto/hapi/services"
2426
relutil "k8s.io/helm/pkg/releaseutil"
25-
"regexp"
2627
)
2728

2829
// ListReleases lists the releases found by the server.
@@ -140,7 +141,7 @@ func (s *ReleaseServer) partition(rels []*release.Release, cap int) <-chan []*re
140141
s.Log("partitioned at %d with %d releases (cap=%d)", fill, len(chunk), cap)
141142
chunks <- chunk
142143
// reset paritioning state
143-
chunk = chunk[:0]
144+
chunk = nil
144145
fill = 0
145146
}
146147
chunk = append(chunk, rls)

pkg/tiller/release_list_test.go

+23
Original file line numberDiff line numberDiff line change
@@ -274,3 +274,26 @@ func TestReleasesNamespace(t *testing.T) {
274274
t.Errorf("Expected 2 releases, got %d", len(mrs.val.Releases))
275275
}
276276
}
277+
278+
func TestReleasePartition(t *testing.T) {
279+
var rl []*release.Release
280+
rs := rsFixture()
281+
rs.Log = t.Logf
282+
num := 7
283+
for i := 0; i < num; i++ {
284+
rel := releaseStub()
285+
rel.Name = fmt.Sprintf("rel-%d", i)
286+
rl = append(rl, rel)
287+
}
288+
visited := map[string]bool{}
289+
290+
chunks := rs.partition(rl, 0)
291+
for chunk := range chunks {
292+
for _, rel := range chunk {
293+
if visited[rel.Name] {
294+
t.Errorf("%s was already visited", rel.Name)
295+
}
296+
visited[rel.Name] = true
297+
}
298+
}
299+
}

pkg/tiller/release_server_test.go

+4-12
Original file line numberDiff line numberDiff line change
@@ -112,24 +112,16 @@ data:
112112
name: value
113113
`
114114

115-
func rsFixture() *ReleaseServer {
116-
clientset := fake.NewSimpleClientset()
117-
return &ReleaseServer{
118-
ReleaseModule: &LocalReleaseModule{
119-
clientset: clientset,
120-
},
121-
env: MockEnvironment(),
122-
clientset: clientset,
123-
Log: func(_ string, _ ...interface{}) {},
124-
}
125-
}
126-
127115
type chartOptions struct {
128116
*chart.Chart
129117
}
130118

131119
type chartOption func(*chartOptions)
132120

121+
func rsFixture() *ReleaseServer {
122+
return NewReleaseServer(MockEnvironment(), fake.NewSimpleClientset(), false)
123+
}
124+
133125
func buildChart(opts ...chartOption) *chart.Chart {
134126
c := &chartOptions{
135127
Chart: &chart.Chart{

0 commit comments

Comments
 (0)