Fixed persistent volume claim controllers processing an old claim.

Fixes #19860 (it may be easier to look at the issue to see exact sequence
to reproduce the bug and understand the fix).

When PersistentVolumeProvisionerController.reconcileClaim() is called with the
same claim in short succession (e.g. the claim is created by an user and
at the same time periodic check of all claims is scheduled), the second
reconcileClaim() call gets an old copy of the claim as its parameter.

The method should always reload the claim to get a fresh copy with all
annotations, possibly added by previous reconcileClaim() call.


The same applies to PersistentVolumeClaimBinder.syncClaim().


Also update all the test to store claims in "fake" API server before calling
syncClaim and reconcileClaim.
This commit is contained in:
Jan Safranek
2016-02-01 11:02:28 +01:00
parent 71ae2736c0
commit 1edf34a4e5
5 changed files with 81 additions and 5 deletions

View File

@@ -123,7 +123,6 @@ func TestClaimRace(t *testing.T) {
plugMgr := volume.VolumePluginMgr{}
plugMgr.InitPlugins(host_path.ProbeRecyclableVolumePlugins(newMockRecycler, volume.VolumeConfig{}), volume.NewFakeVolumeHost(tmpDir, nil, nil))
// adds the volume to the index, making the volume available
syncVolume(volumeIndex, mockClient, v)
if mockClient.volume.Status.Phase != api.VolumeAvailable {
@@ -133,6 +132,8 @@ func TestClaimRace(t *testing.T) {
t.Errorf("Expected to find volume in index but it did not exist")
}
// add the claim to fake API server
mockClient.UpdatePersistentVolumeClaim(c1)
// an initial sync for a claim matches the volume
err = syncClaim(volumeIndex, mockClient, c1)
if err != nil {
@@ -143,6 +144,8 @@ func TestClaimRace(t *testing.T) {
}
// before the volume gets updated w/ claimRef, a 2nd claim can attempt to bind and find the same volume
// add the 2nd claim to fake API server
mockClient.UpdatePersistentVolumeClaim(c2)
err = syncClaim(volumeIndex, mockClient, c2)
if err != nil {
t.Errorf("unexpected error for unmatched claim: %v", err)
@@ -408,6 +411,8 @@ func TestBindingWithExamples(t *testing.T) {
t.Errorf("Expected phase %s but got %s", api.VolumeAvailable, mockClient.volume.Status.Phase)
}
// add the claim to fake API server
mockClient.UpdatePersistentVolumeClaim(claim)
// an initial sync for a claim will bind it to an unbound volume
syncClaim(volumeIndex, mockClient, claim)
@@ -477,6 +482,14 @@ func TestCasting(t *testing.T) {
Status: api.PersistentVolumeClaimStatus{Phase: api.ClaimBound},
}
// Inject mockClient into the binder. This prevents weird errors on stderr
// as the binder wants to load PV/PVC from API server.
mockClient := &mockBinderClient{
volume: pv,
claim: pvc,
}
binder.client = mockClient
// none of these should fail casting.
// the real test is not failing when passed DeletedFinalStateUnknown in the deleteHandler
binder.addVolume(pv)