Implement syncClaim with bound claims.

This commit is contained in:
Jan Safranek
2016-05-17 14:55:09 +02:00
parent eff6b50b93
commit 5949b956f5
2 changed files with 222 additions and 21 deletions

View File

@@ -417,8 +417,83 @@ func (ctrl *PersistentVolumeController) syncUnboundClaim(claim *api.PersistentVo
// syncBoundClaim is the main controller method to decide what to do with a
// bound claim.
func (ctrl *PersistentVolumeController) syncBoundClaim(claim *api.PersistentVolumeClaim) error {
// hasAnnotation(pvc, annBindCompleted)
// This PVC has previously been bound
// OBSERVATION: pvc is not "Pending"
// [Unit test set 3]
if claim.Spec.VolumeName == "" {
// Claim was bound before but not any more.
if claim.Status.Phase != api.ClaimLost {
// Log the error only once, when we enter 'Lost' phase
glog.V(3).Infof("synchronizing bound PersistentVolumeClaim[%s]: volume reference lost!", claimToClaimKey(claim))
}
// TODO: emit event and save reason
if _, err := ctrl.updateClaimPhase(claim, api.ClaimLost); err != nil {
return err
}
return nil
}
obj, found, err := ctrl.volumes.store.GetByKey(claim.Spec.VolumeName)
if err != nil {
return err
}
if !found {
// Claim is bound to a non-existing volume.
if claim.Status.Phase != api.ClaimLost {
// Log the error only once, when we enter 'Lost' phase
glog.V(3).Infof("synchronizing bound PersistentVolumeClaim[%s]: volume %q lost!", claimToClaimKey(claim), claim.Spec.VolumeName)
}
// TODO: emit event and save reason
if _, err = ctrl.updateClaimPhase(claim, api.ClaimLost); err != nil {
return err
}
return nil
} else {
volume, ok := obj.(*api.PersistentVolume)
if !ok {
return fmt.Errorf("Cannot convert object from volume cache to volume %q!?: %+v", claim.Spec.VolumeName, obj)
}
glog.V(4).Infof("synchronizing bound PersistentVolumeClaim[%s]: volume %q found: %s", claimToClaimKey(claim), claim.Spec.VolumeName, ctrl.getVolumeStatusForLogging(volume))
if volume.Spec.ClaimRef == nil {
// Claim is bound but volume has come unbound.
// Or, a claim was bound and the controller has not received updated
// volume yet. We can't distinguish these cases.
// Bind the volume again and set all states to Bound.
glog.V(4).Infof("synchronizing bound PersistentVolumeClaim[%s]: volume is unbound, fixing", claimToClaimKey(claim))
if err = ctrl.bind(volume, claim); err != nil {
// Objects not saved, next syncPV or syncClaim will try again
return err
}
return nil
} else if volume.Spec.ClaimRef.UID == claim.UID {
// All is well
// NOTE: syncPV can handle this so it can be left out.
// NOTE: bind() call here will do nothing in most cases as
// everything should be already set.
glog.V(4).Infof("synchronizing bound PersistentVolumeClaim[%s]: claim is already correctly bound", claimToClaimKey(claim))
if err = ctrl.bind(volume, claim); err != nil {
// Objects not saved, next syncPV or syncClaim will try again
return err
}
return nil
} else {
// Claim is bound but volume has a different claimant.
// Set the claim phase to 'Lost', which is a terminal
// phase.
otherClaimName := fmt.Sprintf("%s/%s", volume.Spec.ClaimRef.Namespace, volume.Spec.ClaimRef.Name)
if claim.Status.Phase != api.ClaimLost {
// Log the error only once, when we enter 'Lost' phase
glog.V(3).Infof("synchronizing bound PersistentVolumeClaim[%s]: volume %q bound to another claim %q, this claim is lost!", claimToClaimKey(claim), claim.Spec.VolumeName, otherClaimName)
}
// TODO: emit event and save reason
if _, err = ctrl.updateClaimPhase(claim, api.ClaimLost); err != nil {
return err
}
return nil
}
}
}
// syncVolume is the main controller method to decide what to do with a volume.
// It's invoked by appropriate framework.Controller callbacks when a volume is

View File

@@ -137,26 +137,152 @@ func TestSync(t *testing.T) {
newClaimArray("claim1-9", "uid1-9", "1Gi", "volume1-9", api.ClaimBound, annBoundByController, annBindCompleted),
testSyncClaim,
},
/* TODO: enable when syncClaim with annBindCompleted is implemented
controllerTest{
{
// syncClaim completes binding - simulates controller crash after
// PVC.VolumeName is saved
"10 - complete bind after crash - PVC bound",
[]*api.PersistentVolume{
newVolume("volume1-10", "1Gi", "uid1-10", "claim1-10", api.VolumeBound, annBoundByController),
},
[]*api.PersistentVolume{
newVolume("volume1-10", "1Gi", "uid1-10", "claim1-10", api.VolumeBound, annBoundByController),
},
[]*api.PersistentVolumeClaim{
newClaim("claim1-10", "uid1-10", "1Gi", "volume1-10", api.ClaimPending, annBoundByController, annBindCompleted),
},
[]*api.PersistentVolumeClaim{
newClaim("claim1-10", "uid1-10", "1Gi", "volume1-10", api.ClaimBound, annBoundByController, annBindCompleted),
},
newVolumeArray("volume1-10", "1Gi", "uid1-10", "claim1-10", api.VolumeBound, annBoundByController),
newVolumeArray("volume1-10", "1Gi", "uid1-10", "claim1-10", api.VolumeBound, annBoundByController),
newClaimArray("claim1-10", "uid1-10", "1Gi", "volume1-10", api.ClaimPending, annBoundByController, annBindCompleted),
newClaimArray("claim1-10", "uid1-10", "1Gi", "volume1-10", api.ClaimBound, annBoundByController, annBindCompleted),
testSyncClaim,
},
// [Unit test set 2] User asked for a specific PV.
// Test the binding when pv.ClaimRef is already set by controller or
// by user.
{
// syncClaim with claim pre-bound to a PV that does not exist
"2-1 - claim prebound to non-existing volume - noop",
novolumes,
novolumes,
newClaimArray("claim2-1", "uid2-1", "10Gi", "volume2-1", api.ClaimPending),
newClaimArray("claim2-1", "uid2-1", "10Gi", "volume2-1", api.ClaimPending),
testSyncClaim,
},
{
// syncClaim with claim pre-bound to a PV that does not exist.
// Check that the claim status is reset to Pending
"2-2 - claim prebound to non-existing volume - reset status",
novolumes,
novolumes,
newClaimArray("claim2-2", "uid2-2", "10Gi", "volume2-2", api.ClaimBound),
newClaimArray("claim2-2", "uid2-2", "10Gi", "volume2-2", api.ClaimPending),
testSyncClaim,
},
{
// syncClaim with claim pre-bound to a PV that exists and is
// unbound. Check it gets bound and no annBoundByController is set.
"2-3 - claim prebound to unbound volume",
newVolumeArray("volume2-3", "1Gi", "", "", api.VolumePending),
newVolumeArray("volume2-3", "1Gi", "uid2-3", "claim2-3", api.VolumeBound, annBoundByController),
newClaimArray("claim2-3", "uid2-3", "10Gi", "volume2-3", api.ClaimPending),
newClaimArray("claim2-3", "uid2-3", "10Gi", "volume2-3", api.ClaimBound, annBindCompleted),
testSyncClaim,
},
{
// claim with claim pre-bound to a PV that is pre-bound to the claim
// by name. Check it gets bound and no annBoundByController is set.
"2-4 - claim prebound to prebound volume by name",
newVolumeArray("volume2-4", "1Gi", "", "claim2-4", api.VolumePending),
newVolumeArray("volume2-4", "1Gi", "uid2-4", "claim2-4", api.VolumeBound),
newClaimArray("claim2-4", "uid2-4", "10Gi", "volume2-4", api.ClaimPending),
newClaimArray("claim2-4", "uid2-4", "10Gi", "volume2-4", api.ClaimBound, annBindCompleted),
testSyncClaim,
},
{
// syncClaim with claim pre-bound to a PV that is pre-bound to the
// claim by UID. Check it gets bound and no annBoundByController is
// set.
"2-5 - claim prebound to prebound volume by UID",
newVolumeArray("volume2-5", "1Gi", "uid2-5", "claim2-5", api.VolumePending),
newVolumeArray("volume2-5", "1Gi", "uid2-5", "claim2-5", api.VolumeBound),
newClaimArray("claim2-5", "uid2-5", "10Gi", "volume2-5", api.ClaimPending),
newClaimArray("claim2-5", "uid2-5", "10Gi", "volume2-5", api.ClaimBound, annBindCompleted),
testSyncClaim,
},
{
// syncClaim with claim pre-bound to a PV that is bound to different
// claim. Check it's reset to Pending.
"2-6 - claim prebound to already bound volume",
newVolumeArray("volume2-6", "1Gi", "uid2-6_1", "claim2-6_1", api.VolumeBound),
newVolumeArray("volume2-6", "1Gi", "uid2-6_1", "claim2-6_1", api.VolumeBound),
newClaimArray("claim2-6", "uid2-6", "10Gi", "volume2-6", api.ClaimBound),
newClaimArray("claim2-6", "uid2-6", "10Gi", "volume2-6", api.ClaimPending),
testSyncClaim,
},
{
// syncClaim with claim bound by controller to a PV that is bound to
// different claim. Check it throws an error.
"2-7 - claim bound by controller to already bound volume",
newVolumeArray("volume2-7", "1Gi", "uid2-7_1", "claim2-7_1", api.VolumeBound),
newVolumeArray("volume2-7", "1Gi", "uid2-7_1", "claim2-7_1", api.VolumeBound),
newClaimArray("claim2-7", "uid2-7", "10Gi", "volume2-7", api.ClaimBound, annBoundByController),
newClaimArray("claim2-7", "uid2-7", "10Gi", "volume2-7", api.ClaimBound, annBoundByController),
testSyncClaimError,
},
// [Unit test set 3] Syncing bound claim
{
// syncClaim with claim bound and its claim.Spec.VolumeName is
// removed. Check it's marked as Lost.
"3-1 - bound claim with missing VolumeName",
novolumes,
novolumes,
newClaimArray("claim3-1", "uid3-1", "10Gi", "", api.ClaimBound, annBoundByController, annBindCompleted),
newClaimArray("claim3-1", "uid3-1", "10Gi", "", api.ClaimLost, annBoundByController, annBindCompleted),
testSyncClaim,
},
{
// syncClaim with claim bound to non-exising volume. Check it's
// marked as Lost.
"3-2 - bound claim with missing volume",
novolumes,
novolumes,
newClaimArray("claim3-2", "uid3-2", "10Gi", "volume3-2", api.ClaimBound, annBoundByController, annBindCompleted),
newClaimArray("claim3-2", "uid3-2", "10Gi", "volume3-2", api.ClaimLost, annBoundByController, annBindCompleted),
testSyncClaim,
},
{
// syncClaim with claim bound to unbound volume. Check it's bound.
// Also check that Pending phase is set to Bound
"3-3 - bound claim with unbound volume",
newVolumeArray("volume3-3", "10Gi", "", "", api.VolumePending),
newVolumeArray("volume3-3", "10Gi", "uid3-3", "claim3-3", api.VolumeBound, annBoundByController),
newClaimArray("claim3-3", "uid3-3", "10Gi", "volume3-3", api.ClaimPending, annBoundByController, annBindCompleted),
newClaimArray("claim3-3", "uid3-3", "10Gi", "volume3-3", api.ClaimBound, annBoundByController, annBindCompleted),
testSyncClaim,
},
{
// syncClaim with claim bound to volume with missing (or different)
// volume.Spec.ClaimRef.UID. Check that the claim is marked as lost.
"3-4 - bound claim with prebound volume",
newVolumeArray("volume3-4", "10Gi", "claim3-4-x", "claim3-4", api.VolumePending),
newVolumeArray("volume3-4", "10Gi", "claim3-4-x", "claim3-4", api.VolumePending),
newClaimArray("claim3-4", "uid3-4", "10Gi", "volume3-4", api.ClaimPending, annBoundByController, annBindCompleted),
newClaimArray("claim3-4", "uid3-4", "10Gi", "volume3-4", api.ClaimLost, annBoundByController, annBindCompleted),
testSyncClaim,
},
{
// syncClaim with claim bound to bound volume. Check that the
// controller does not do anything. Also check that Pending phase is
// set to Bound
"3-5 - bound claim with bound volume",
newVolumeArray("volume3-5", "10Gi", "uid3-5", "claim3-5", api.VolumePending),
newVolumeArray("volume3-5", "10Gi", "uid3-5", "claim3-5", api.VolumeBound),
newClaimArray("claim3-5", "uid3-5", "10Gi", "volume3-5", api.ClaimPending, annBindCompleted),
newClaimArray("claim3-5", "uid3-5", "10Gi", "volume3-5", api.ClaimBound, annBindCompleted),
testSyncClaim,
},
{
// syncClaim with claim bound to a volume that is bound to different
// claim. Check that the claim is marked as lost.
// TODO: test that an event is emitted
"3-6 - bound claim with bound volume",
newVolumeArray("volume3-6", "10Gi", "uid3-6-x", "claim3-6-x", api.VolumePending),
newVolumeArray("volume3-6", "10Gi", "uid3-6-x", "claim3-6-x", api.VolumePending),
newClaimArray("claim3-6", "uid3-6", "10Gi", "volume3-6", api.ClaimPending, annBindCompleted),
newClaimArray("claim3-6", "uid3-6", "10Gi", "volume3-6", api.ClaimLost, annBindCompleted),
testSyncClaim,
},
*/
}
runSyncTests(t, tests)
}