Added PersistentVolumeController
This commit is contained in:
@@ -86,8 +86,7 @@ func NewPersistentVolumeClaimBinder(kubeClient client.Interface, syncPeriod time
|
||||
framework.ResourceEventHandlerFuncs{
|
||||
AddFunc: binder.addClaim,
|
||||
UpdateFunc: binder.updateClaim,
|
||||
// no DeleteFunc needed. a claim requires no clean-up.
|
||||
// syncVolume handles the missing claim
|
||||
DeleteFunc: binder.deleteClaim,
|
||||
},
|
||||
)
|
||||
|
||||
@@ -145,6 +144,33 @@ func (binder *PersistentVolumeClaimBinder) updateClaim(oldObj, newObj interface{
|
||||
}
|
||||
}
|
||||
|
||||
func (binder *PersistentVolumeClaimBinder) deleteClaim(obj interface{}) {
|
||||
binder.lock.Lock()
|
||||
defer binder.lock.Unlock()
|
||||
var volume *api.PersistentVolume
|
||||
if pvc, ok := obj.(*api.PersistentVolumeClaim); ok {
|
||||
if pvObj, exists, _ := binder.volumeIndex.GetByKey(pvc.Spec.VolumeName); exists {
|
||||
if pv, ok := pvObj.(*api.PersistentVolume); ok {
|
||||
volume = pv
|
||||
}
|
||||
}
|
||||
}
|
||||
if unk, ok := obj.(cache.DeletedFinalStateUnknown); ok && unk.Obj != nil {
|
||||
if pv, ok := unk.Obj.(*api.PersistentVolume); ok {
|
||||
volume = pv
|
||||
}
|
||||
}
|
||||
|
||||
// sync the volume when its claim is deleted. Explicitly sync'ing the volume here in response to
|
||||
// claim deletion prevents the volume from waiting until the next sync period for its Release.
|
||||
if volume != nil {
|
||||
err := syncVolume(binder.volumeIndex, binder.client, volume)
|
||||
if err != nil {
|
||||
glog.Errorf("PVClaimBinder could not update volume %s from deleteClaim handler: %+v", volume.Name, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func syncVolume(volumeIndex *persistentVolumeOrderedIndex, binderClient binderClient, volume *api.PersistentVolume) (err error) {
|
||||
glog.V(5).Infof("Synchronizing PersistentVolume[%s], current phase: %s\n", volume.Name, volume.Status.Phase)
|
||||
|
||||
@@ -166,6 +192,11 @@ func syncVolume(volumeIndex *persistentVolumeOrderedIndex, binderClient binderCl
|
||||
volumeIndex.Add(volume)
|
||||
}
|
||||
|
||||
if isBeingProvisioned(volume) {
|
||||
glog.V(4).Infof("Skipping PersistentVolume[%s], waiting for provisioning to finish", volume.Name)
|
||||
return nil
|
||||
}
|
||||
|
||||
switch currentPhase {
|
||||
case api.VolumePending:
|
||||
|
||||
@@ -275,38 +306,46 @@ func syncClaim(volumeIndex *persistentVolumeOrderedIndex, binderClient binderCli
|
||||
|
||||
switch claim.Status.Phase {
|
||||
case api.ClaimPending:
|
||||
// claims w/ a storage-class annotation for provisioning with *only* match volumes with a ClaimRef of the claim.
|
||||
volume, err := volumeIndex.findBestMatchForClaim(claim)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if volume == nil {
|
||||
glog.V(5).Infof("A volume match does not exist for persistent claim: %s", claim.Name)
|
||||
return nil
|
||||
}
|
||||
|
||||
// create a reference to the claim and assign it to the volume being bound.
|
||||
// the volume is a pointer and assigning the reference fixes a race condition where another
|
||||
// claim might match this volume but before the claimRef is persistent in the next case statement
|
||||
if isBeingProvisioned(volume) {
|
||||
glog.V(5).Infof("PersistentVolume[%s] for PersistentVolumeClaim[%s/%s] is still being provisioned.", volume.Name, claim.Namespace, claim.Name)
|
||||
return nil
|
||||
}
|
||||
|
||||
claimRef, err := api.GetReference(claim)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Unexpected error getting claim reference: %v\n", err)
|
||||
}
|
||||
|
||||
// make a binding reference to the claim and ensure to update the local index to prevent dupe bindings
|
||||
clone, err := conversion.NewCloner().DeepCopy(volume)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error cloning pv: %v", err)
|
||||
}
|
||||
volumeClone, ok := clone.(*api.PersistentVolume)
|
||||
if !ok {
|
||||
return fmt.Errorf("Unexpected pv cast error : %v\n", volumeClone)
|
||||
}
|
||||
volumeClone.Spec.ClaimRef = claimRef
|
||||
if updatedVolume, err := binderClient.UpdatePersistentVolume(volumeClone); err != nil {
|
||||
return fmt.Errorf("Unexpected error saving PersistentVolume.Status: %+v", err)
|
||||
} else {
|
||||
volume = updatedVolume
|
||||
volumeIndex.Update(updatedVolume)
|
||||
// Make a binding reference to the claim by persisting claimRef on the volume.
|
||||
// The local cache must be updated with the new bind to prevent subsequent
|
||||
// claims from binding to the volume.
|
||||
if volume.Spec.ClaimRef == nil {
|
||||
clone, err := conversion.NewCloner().DeepCopy(volume)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error cloning pv: %v", err)
|
||||
}
|
||||
volumeClone, ok := clone.(*api.PersistentVolume)
|
||||
if !ok {
|
||||
return fmt.Errorf("Unexpected pv cast error : %v\n", volumeClone)
|
||||
}
|
||||
volumeClone.Spec.ClaimRef = claimRef
|
||||
if updatedVolume, err := binderClient.UpdatePersistentVolume(volumeClone); err != nil {
|
||||
return fmt.Errorf("Unexpected error saving PersistentVolume.Status: %+v", err)
|
||||
} else {
|
||||
volume = updatedVolume
|
||||
volumeIndex.Update(updatedVolume)
|
||||
}
|
||||
}
|
||||
|
||||
// the bind is persisted on the volume above and will always match the claim in a search.
|
||||
@@ -341,6 +380,14 @@ func syncClaim(volumeIndex *persistentVolumeOrderedIndex, binderClient binderCli
|
||||
return nil
|
||||
}
|
||||
|
||||
func isBeingProvisioned(volume *api.PersistentVolume) bool {
|
||||
value, found := volume.Annotations[pvProvisioningRequiredAnnotationKey]
|
||||
if found && value != pvProvisioningCompletedAnnotationValue {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Run starts all of this binder's control loops
|
||||
func (controller *PersistentVolumeClaimBinder) Run() {
|
||||
glog.V(5).Infof("Starting PersistentVolumeClaimBinder\n")
|
||||
|
Reference in New Issue
Block a user