diff --git a/pkg/controller/volume/persistentvolume/binder_test.go b/pkg/controller/volume/persistentvolume/binder_test.go index 07fe19ca306..5a26deed51f 100644 --- a/pkg/controller/volume/persistentvolume/binder_test.go +++ b/pkg/controller/volume/persistentvolume/binder_test.go @@ -254,12 +254,33 @@ func TestSync(t *testing.T) { // unbound, but does not match the selector. Check it gets bound // and no annBoundByController is set. "2-8 - claim prebound to unbound volume that does not match the selector", - newVolumeArray("volume2-3", "1Gi", "", "", v1.VolumePending, v1.PersistentVolumeReclaimRetain, classEmpty), - newVolumeArray("volume2-3", "1Gi", "uid2-3", "claim2-3", v1.VolumeBound, v1.PersistentVolumeReclaimRetain, classEmpty, annBoundByController), - withLabelSelector(labels, newClaimArray("claim2-3", "uid2-3", "1Gi", "volume2-3", v1.ClaimPending, nil)), - withLabelSelector(labels, newClaimArray("claim2-3", "uid2-3", "1Gi", "volume2-3", v1.ClaimBound, nil, annBindCompleted)), + newVolumeArray("volume2-8", "1Gi", "", "", v1.VolumePending, v1.PersistentVolumeReclaimRetain, classEmpty), + newVolumeArray("volume2-8", "1Gi", "uid2-8", "claim2-8", v1.VolumeBound, v1.PersistentVolumeReclaimRetain, classEmpty, annBoundByController), + withLabelSelector(labels, newClaimArray("claim2-8", "uid2-8", "1Gi", "volume2-8", v1.ClaimPending, nil)), + withLabelSelector(labels, newClaimArray("claim2-8", "uid2-8", "1Gi", "volume2-8", v1.ClaimBound, nil, annBindCompleted)), noevents, noerrors, testSyncClaim, }, + { + // syncClaim with claim pre-bound to a PV that exists and is + // unbound, but its size is smaller than requested. + //Check that the claim status is reset to Pending + "2-9 - claim prebound to unbound volume that size is smaller than requested", + newVolumeArray("volume2-9", "1Gi", "", "", v1.VolumePending, v1.PersistentVolumeReclaimRetain, classEmpty), + newVolumeArray("volume2-9", "1Gi", "", "", v1.VolumePending, v1.PersistentVolumeReclaimRetain, classEmpty), + newClaimArray("claim2-9", "uid2-9", "2Gi", "volume2-9", v1.ClaimBound, nil), + newClaimArray("claim2-9", "uid2-9", "2Gi", "volume2-9", v1.ClaimPending, nil), + []string{"Warning VolumeMismatch"}, noerrors, testSyncClaim, + }, + { + // syncClaim with claim pre-bound to a PV that exists and is + // unbound, but its class does not match. Check that the claim status is reset to Pending + "2-10 - claim prebound to unbound volume that class is different", + newVolumeArray("volume2-10", "1Gi", "1", "", v1.VolumePending, v1.PersistentVolumeReclaimRetain, classGold), + newVolumeArray("volume2-10", "1Gi", "", "", v1.VolumePending, v1.PersistentVolumeReclaimRetain, classGold), + newClaimArray("claim2-10", "uid2-10", "1Gi", "volume2-10", v1.ClaimBound, nil), + newClaimArray("claim2-10", "uid2-10", "1Gi", "volume2-10", v1.ClaimPending, nil), + []string{"Warning VolumeMismatch"}, noerrors, testSyncClaim, + }, // [Unit test set 3] Syncing bound claim { diff --git a/pkg/controller/volume/persistentvolume/pv_controller.go b/pkg/controller/volume/persistentvolume/pv_controller.go index de1708ea256..b165b2ea380 100644 --- a/pkg/controller/volume/persistentvolume/pv_controller.go +++ b/pkg/controller/volume/persistentvolume/pv_controller.go @@ -225,6 +225,25 @@ func (ctrl *PersistentVolumeController) syncClaim(claim *v1.PersistentVolumeClai } } +//checkVolumeSatisfyClaim checks if the volume requested by the claim satisfies the requirements of the claim +func checkVolumeSatisfyClaim(volume *v1.PersistentVolume, claim *v1.PersistentVolumeClaim) error { + requestedQty := claim.Spec.Resources.Requests[v1.ResourceName(v1.ResourceStorage)] + requestedSize := requestedQty.Value() + + volumeQty := volume.Spec.Capacity[v1.ResourceStorage] + volumeSize := volumeQty.Value() + if volumeSize < requestedSize { + return fmt.Errorf("Storage capacity of volume[%s] requested by claim[%v] is not enough", volume.Name, claimToClaimKey(claim)) + } + + requestedClass := v1.GetPersistentVolumeClaimClass(claim) + if v1.GetPersistentVolumeClass(volume) != requestedClass { + return fmt.Errorf("Class of volume[%s] is not the same as claim[%v]", volume.Name, claimToClaimKey(claim)) + } + + return nil +} + // syncUnboundClaim is the main controller method to decide what to do with an // unbound claim. func (ctrl *PersistentVolumeController) syncUnboundClaim(claim *v1.PersistentVolumeClaim) error { @@ -295,7 +314,15 @@ func (ctrl *PersistentVolumeController) syncUnboundClaim(claim *v1.PersistentVol // User asked for a PV that is not claimed // OBSERVATION: pvc is "Pending", pv is "Available" glog.V(4).Infof("synchronizing unbound PersistentVolumeClaim[%s]: volume is unbound, binding", claimToClaimKey(claim)) - if err = ctrl.bind(volume, claim); err != nil { + if err = checkVolumeSatisfyClaim(volume, claim); err != nil { + glog.V(4).Infof("Can't bind the claim to volume %q: %v", volume.Name, err) + //send a event + ctrl.eventRecorder.Event(volume, v1.EventTypeWarning, "VolumeMismatch", "Volume's size is smaller than requested or volume's class does not match with claim") + //volume does not satisfy the requirements of the claim + if _, err = ctrl.updateClaimStatus(claim, v1.ClaimPending, nil); err != nil { + return err + } + } else if err = ctrl.bind(volume, claim); err != nil { // On any error saving the volume or the claim, subsequent // syncClaim will finish the binding. return err