mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-08-12 21:36:24 +00:00
pv_controller change for provisioning
This commit is contained in:
parent
95b530366a
commit
446f36559e
@ -285,6 +285,16 @@ func (ctrl *PersistentVolumeController) shouldDelayBinding(claim *v1.PersistentV
|
|||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if utilfeature.DefaultFeatureGate.Enabled(features.DynamicProvisioningScheduling) {
|
||||||
|
// When feature DynamicProvisioningScheduling enabled,
|
||||||
|
// Scheduler signal to the PV controller to start dynamic
|
||||||
|
// provisioning by setting the "annSelectedNode" annotation
|
||||||
|
// in the PVC
|
||||||
|
if _, ok := claim.Annotations[annSelectedNode]; ok {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
className := v1helper.GetPersistentVolumeClaimClass(claim)
|
className := v1helper.GetPersistentVolumeClaimClass(claim)
|
||||||
if className == "" {
|
if className == "" {
|
||||||
return false, nil
|
return false, nil
|
||||||
@ -299,8 +309,6 @@ func (ctrl *PersistentVolumeController) shouldDelayBinding(claim *v1.PersistentV
|
|||||||
return false, fmt.Errorf("VolumeBindingMode not set for StorageClass %q", className)
|
return false, fmt.Errorf("VolumeBindingMode not set for StorageClass %q", className)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: add check to handle dynamic provisioning later
|
|
||||||
|
|
||||||
return *class.VolumeBindingMode == storage.VolumeBindingWaitForFirstConsumer, nil
|
return *class.VolumeBindingMode == storage.VolumeBindingWaitForFirstConsumer, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -328,7 +336,6 @@ func (ctrl *PersistentVolumeController) syncUnboundClaim(claim *v1.PersistentVol
|
|||||||
// OBSERVATION: pvc is "Pending", will retry
|
// OBSERVATION: pvc is "Pending", will retry
|
||||||
switch {
|
switch {
|
||||||
case delayBinding:
|
case delayBinding:
|
||||||
// TODO: Skip dynamic provisioning for now
|
|
||||||
ctrl.eventRecorder.Event(claim, v1.EventTypeNormal, events.WaitForFirstConsumer, "waiting for first consumer to be created before binding")
|
ctrl.eventRecorder.Event(claim, v1.EventTypeNormal, events.WaitForFirstConsumer, "waiting for first consumer to be created before binding")
|
||||||
case v1helper.GetPersistentVolumeClaimClass(claim) != "":
|
case v1helper.GetPersistentVolumeClaimClass(claim) != "":
|
||||||
if err = ctrl.provisionClaim(claim); err != nil {
|
if err = ctrl.provisionClaim(claim); err != nil {
|
||||||
@ -1428,9 +1435,16 @@ func (ctrl *PersistentVolumeController) provisionClaimOperation(claim *v1.Persis
|
|||||||
}
|
}
|
||||||
|
|
||||||
opComplete := util.OperationCompleteHook(plugin.GetPluginName(), "volume_provision")
|
opComplete := util.OperationCompleteHook(plugin.GetPluginName(), "volume_provision")
|
||||||
|
// TODO: modify the Provision() interface to pass in the allowed topology information
|
||||||
|
// of the provisioned volume.
|
||||||
volume, err = provisioner.Provision()
|
volume, err = provisioner.Provision()
|
||||||
opComplete(&err)
|
opComplete(&err)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
// Other places of failure has nothing to do with DynamicProvisioningScheduling,
|
||||||
|
// so just let controller retry in the next sync. We'll only call func
|
||||||
|
// rescheduleProvisioning here when the underlying provisioning actually failed.
|
||||||
|
ctrl.rescheduleProvisioning(claim)
|
||||||
|
|
||||||
strerr := fmt.Sprintf("Failed to provision volume with StorageClass %q: %v", storageClass.Name, err)
|
strerr := fmt.Sprintf("Failed to provision volume with StorageClass %q: %v", storageClass.Name, err)
|
||||||
glog.V(2).Infof("failed to provision volume for claim %q with StorageClass %q: %v", claimToClaimKey(claim), storageClass.Name, err)
|
glog.V(2).Infof("failed to provision volume for claim %q with StorageClass %q: %v", claimToClaimKey(claim), storageClass.Name, err)
|
||||||
ctrl.eventRecorder.Event(claim, v1.EventTypeWarning, events.ProvisioningFailed, strerr)
|
ctrl.eventRecorder.Event(claim, v1.EventTypeWarning, events.ProvisioningFailed, strerr)
|
||||||
@ -1521,6 +1535,29 @@ func (ctrl *PersistentVolumeController) provisionClaimOperation(claim *v1.Persis
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// rescheduleProvisioning signal back to the scheduler to retry dynamic provisioning
|
||||||
|
// by removing the annSelectedNode annotation
|
||||||
|
func (ctrl *PersistentVolumeController) rescheduleProvisioning(claim *v1.PersistentVolumeClaim) {
|
||||||
|
if _, ok := claim.Annotations[annSelectedNode]; !ok {
|
||||||
|
// Provisioning not triggered by the scheduler, skip
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// The claim from method args can be pointing to watcher cache. We must not
|
||||||
|
// modify these, therefore create a copy.
|
||||||
|
newClaim := claim.DeepCopy()
|
||||||
|
delete(newClaim.Annotations, annSelectedNode)
|
||||||
|
// Try to update the PVC object
|
||||||
|
if _, err := ctrl.kubeClient.CoreV1().PersistentVolumeClaims(newClaim.Namespace).Update(newClaim); err != nil {
|
||||||
|
glog.V(4).Infof("Failed to delete annotation 'annSelectedNode' for PersistentVolumeClaim %q: %v", claimToClaimKey(newClaim), err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if _, err := ctrl.storeClaimUpdate(newClaim); err != nil {
|
||||||
|
// We will get an "claim updated" event soon, this is not a big error
|
||||||
|
glog.V(4).Infof("Updating PersistentVolumeClaim %q: cannot update internal cache: %v", claimToClaimKey(newClaim), err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// getProvisionedVolumeNameForClaim returns PV.Name for the provisioned volume.
|
// getProvisionedVolumeNameForClaim returns PV.Name for the provisioned volume.
|
||||||
// The name must be unique.
|
// The name must be unique.
|
||||||
func (ctrl *PersistentVolumeController) getProvisionedVolumeNameForClaim(claim *v1.PersistentVolumeClaim) string {
|
func (ctrl *PersistentVolumeController) getProvisionedVolumeNameForClaim(claim *v1.PersistentVolumeClaim) string {
|
||||||
|
@ -312,8 +312,8 @@ func TestDelayBinding(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// When feature gate is disabled, should always be delayed
|
// When volumeScheduling feature gate is disabled, should always be delayed
|
||||||
name := "feature-disabled"
|
name := "volumeScheduling-feature-disabled"
|
||||||
shouldDelay, err := ctrl.shouldDelayBinding(makePVCClass(&classWaitMode))
|
shouldDelay, err := ctrl.shouldDelayBinding(makePVCClass(&classWaitMode))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Test %q returned error: %v", name, err)
|
t.Errorf("Test %q returned error: %v", name, err)
|
||||||
@ -322,7 +322,7 @@ func TestDelayBinding(t *testing.T) {
|
|||||||
t.Errorf("Test %q returned true, expected false", name)
|
t.Errorf("Test %q returned true, expected false", name)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Enable feature gate
|
// Enable volumeScheduling feature gate
|
||||||
utilfeature.DefaultFeatureGate.Set("VolumeScheduling=true")
|
utilfeature.DefaultFeatureGate.Set("VolumeScheduling=true")
|
||||||
defer utilfeature.DefaultFeatureGate.Set("VolumeScheduling=false")
|
defer utilfeature.DefaultFeatureGate.Set("VolumeScheduling=false")
|
||||||
|
|
||||||
@ -338,4 +338,43 @@ func TestDelayBinding(t *testing.T) {
|
|||||||
t.Errorf("Test %q returned unexpected %v", name, test.shouldDelay)
|
t.Errorf("Test %q returned unexpected %v", name, test.shouldDelay)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// When dynamicProvisioningScheduling feature gate is disabled, should be delayed,
|
||||||
|
// even if the pvc has selectedNode annotation.
|
||||||
|
provisionedClaim := makePVCClass(&classWaitMode)
|
||||||
|
provisionedClaim.Annotations = map[string]string{annSelectedNode: "node-name"}
|
||||||
|
name = "dynamicProvisioningScheduling-feature-disabled"
|
||||||
|
shouldDelay, err = ctrl.shouldDelayBinding(provisionedClaim)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Test %q returned error: %v", name, err)
|
||||||
|
}
|
||||||
|
if !shouldDelay {
|
||||||
|
t.Errorf("Test %q returned false, expected true", name)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Enable DynamicProvisioningScheduling feature gate
|
||||||
|
utilfeature.DefaultFeatureGate.Set("DynamicProvisioningScheduling=true")
|
||||||
|
defer utilfeature.DefaultFeatureGate.Set("DynamicProvisioningScheduling=false")
|
||||||
|
|
||||||
|
// When the pvc does not have selectedNode annotation, should be delayed,
|
||||||
|
// even if dynamicProvisioningScheduling feature gate is enabled.
|
||||||
|
name = "dynamicProvisioningScheduling-feature-enabled, selectedNode-annotation-not-set"
|
||||||
|
shouldDelay, err = ctrl.shouldDelayBinding(makePVCClass(&classWaitMode))
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Test %q returned error: %v", name, err)
|
||||||
|
}
|
||||||
|
if !shouldDelay {
|
||||||
|
t.Errorf("Test %q returned false, expected true", name)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Should not be delayed when dynamicProvisioningScheduling feature gate is enabled,
|
||||||
|
// and the pvc has selectedNode annotation.
|
||||||
|
name = "dynamicProvisioningScheduling-feature-enabled, selectedNode-annotation-set"
|
||||||
|
shouldDelay, err = ctrl.shouldDelayBinding(provisionedClaim)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Test %q returned error: %v", name, err)
|
||||||
|
}
|
||||||
|
if shouldDelay {
|
||||||
|
t.Errorf("Test %q returned true, expected false", name)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user