Merge pull request #7360 from cristiklein/fix/less-corruption-with-concurrent-executions-v2

fix(tiller): Avoid corrupting storage via a lock
pull/8558/head
Martin Hickey 4 years ago committed by GitHub
commit 73d88af866
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -65,6 +65,8 @@ var (
errInvalidRevision = errors.New("invalid release revision") errInvalidRevision = errors.New("invalid release revision")
//errInvalidName indicates that an invalid release name was provided //errInvalidName indicates that an invalid release name was provided
errInvalidName = errors.New("invalid release name, must match regex ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])+$ and the length must not be longer than 53") errInvalidName = errors.New("invalid release name, must match regex ^(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])+$ and the length must not be longer than 53")
// errPending indicates that Tiller is already applying an operation on a release
errPending = errors.New("another operation (install/upgrade/rollback) is in progress")
) )
// ListDefaultLimit is the default limit for number of items returned in a list. // ListDefaultLimit is the default limit for number of items returned in a list.

@ -93,6 +93,14 @@ func (s *ReleaseServer) prepareUpdate(req *services.UpdateReleaseRequest) (*rele
return nil, nil, err return nil, nil, err
} }
// Concurrent `helm upgrade`s will either fail here with `errPending` or
// when creating the release with "already exists". This should act as a
// pessimistic lock.
sc := lastRelease.Info.Status.Code
if sc == release.Status_PENDING_INSTALL || sc == release.Status_PENDING_UPGRADE || sc == release.Status_PENDING_ROLLBACK {
return nil, nil, errPending
}
// Increment revision count. This is passed to templates, and also stored on // Increment revision count. This is passed to templates, and also stored on
// the release object. // the release object.
revision := lastRelease.Version + 1 revision := lastRelease.Version + 1

@ -104,6 +104,31 @@ func TestUpdateRelease(t *testing.T) {
t.Errorf("Expected description %q, got %q", edesc, got) t.Errorf("Expected description %q, got %q", edesc, got)
} }
} }
func TestUpdateReleasePendingError(t *testing.T) {
c := helm.NewContext()
rs := rsFixture()
rel := releaseStub()
rs.env.Releases.Create(rel)
rel2 := releaseStub()
rel2.Info.Status.Code = release.Status_PENDING_UPGRADE
rel2.Version = 2
rs.env.Releases.Create(rel2)
req := &services.UpdateReleaseRequest{
Name: rel.Name,
Chart: &chart.Chart{
Metadata: &chart.Metadata{Name: "hello"},
Templates: []*chart.Template{
{Name: "templates/hello", Data: []byte("hello: world")},
{Name: "templates/hooks", Data: []byte(manifestWithUpgradeHooks)},
},
},
}
_, err := rs.UpdateRelease(c, req)
if err == nil {
t.Fatalf("Expected failure to update")
}
}
func TestUpdateRelease_ResetValues(t *testing.T) { func TestUpdateRelease_ResetValues(t *testing.T) {
c := helm.NewContext() c := helm.NewContext()
rs := rsFixture() rs := rsFixture()

Loading…
Cancel
Save