mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-24 04:06:03 +00:00
Merge pull request #92222 from cofyc/fix92186
Share pod volume binding cache via framework.CycleState
This commit is contained in:
commit
c6d2b223fb
@ -202,7 +202,6 @@ profiles:
|
|||||||
"ReservePlugin": {{Name: "VolumeBinding"}},
|
"ReservePlugin": {{Name: "VolumeBinding"}},
|
||||||
"UnreservePlugin": {{Name: "VolumeBinding"}},
|
"UnreservePlugin": {{Name: "VolumeBinding"}},
|
||||||
"PreBindPlugin": {{Name: "VolumeBinding"}},
|
"PreBindPlugin": {{Name: "VolumeBinding"}},
|
||||||
"PostBindPlugin": {{Name: "VolumeBinding"}},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
testcases := []struct {
|
testcases := []struct {
|
||||||
@ -237,7 +236,6 @@ profiles:
|
|||||||
"ReservePlugin": {{Name: "VolumeBinding"}},
|
"ReservePlugin": {{Name: "VolumeBinding"}},
|
||||||
"UnreservePlugin": {{Name: "VolumeBinding"}},
|
"UnreservePlugin": {{Name: "VolumeBinding"}},
|
||||||
"PreBindPlugin": {{Name: "VolumeBinding"}},
|
"PreBindPlugin": {{Name: "VolumeBinding"}},
|
||||||
"PostBindPlugin": {{Name: "VolumeBinding"}},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -255,7 +253,6 @@ profiles:
|
|||||||
"ReservePlugin": {{Name: "VolumeBinding"}},
|
"ReservePlugin": {{Name: "VolumeBinding"}},
|
||||||
"UnreservePlugin": {{Name: "VolumeBinding"}},
|
"UnreservePlugin": {{Name: "VolumeBinding"}},
|
||||||
"PreBindPlugin": {{Name: "VolumeBinding"}},
|
"PreBindPlugin": {{Name: "VolumeBinding"}},
|
||||||
"PostBindPlugin": {{Name: "VolumeBinding"}},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -338,7 +335,6 @@ profiles:
|
|||||||
"ReservePlugin": {{Name: "VolumeBinding"}},
|
"ReservePlugin": {{Name: "VolumeBinding"}},
|
||||||
"UnreservePlugin": {{Name: "VolumeBinding"}},
|
"UnreservePlugin": {{Name: "VolumeBinding"}},
|
||||||
"PreBindPlugin": {{Name: "VolumeBinding"}},
|
"PreBindPlugin": {{Name: "VolumeBinding"}},
|
||||||
"PostBindPlugin": {{Name: "VolumeBinding"}},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -5,7 +5,6 @@ go_library(
|
|||||||
srcs = [
|
srcs = [
|
||||||
"scheduler_assume_cache.go",
|
"scheduler_assume_cache.go",
|
||||||
"scheduler_binder.go",
|
"scheduler_binder.go",
|
||||||
"scheduler_binder_cache.go",
|
|
||||||
"scheduler_binder_fake.go",
|
"scheduler_binder_fake.go",
|
||||||
],
|
],
|
||||||
importpath = "k8s.io/kubernetes/pkg/controller/volume/scheduling",
|
importpath = "k8s.io/kubernetes/pkg/controller/volume/scheduling",
|
||||||
@ -18,6 +17,7 @@ go_library(
|
|||||||
"//pkg/volume/util:go_default_library",
|
"//pkg/volume/util:go_default_library",
|
||||||
"//staging/src/k8s.io/api/core/v1:go_default_library",
|
"//staging/src/k8s.io/api/core/v1:go_default_library",
|
||||||
"//staging/src/k8s.io/api/storage/v1:go_default_library",
|
"//staging/src/k8s.io/api/storage/v1:go_default_library",
|
||||||
|
"//staging/src/k8s.io/apimachinery/pkg/api/errors:go_default_library",
|
||||||
"//staging/src/k8s.io/apimachinery/pkg/api/meta:go_default_library",
|
"//staging/src/k8s.io/apimachinery/pkg/api/meta:go_default_library",
|
||||||
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||||
"//staging/src/k8s.io/apimachinery/pkg/labels:go_default_library",
|
"//staging/src/k8s.io/apimachinery/pkg/labels:go_default_library",
|
||||||
@ -28,6 +28,7 @@ go_library(
|
|||||||
"//staging/src/k8s.io/client-go/informers/core/v1:go_default_library",
|
"//staging/src/k8s.io/client-go/informers/core/v1:go_default_library",
|
||||||
"//staging/src/k8s.io/client-go/informers/storage/v1:go_default_library",
|
"//staging/src/k8s.io/client-go/informers/storage/v1:go_default_library",
|
||||||
"//staging/src/k8s.io/client-go/kubernetes:go_default_library",
|
"//staging/src/k8s.io/client-go/kubernetes:go_default_library",
|
||||||
|
"//staging/src/k8s.io/client-go/listers/core/v1:go_default_library",
|
||||||
"//staging/src/k8s.io/client-go/listers/storage/v1:go_default_library",
|
"//staging/src/k8s.io/client-go/listers/storage/v1:go_default_library",
|
||||||
"//staging/src/k8s.io/client-go/tools/cache:go_default_library",
|
"//staging/src/k8s.io/client-go/tools/cache:go_default_library",
|
||||||
"//staging/src/k8s.io/csi-translation-lib:go_default_library",
|
"//staging/src/k8s.io/csi-translation-lib:go_default_library",
|
||||||
@ -40,7 +41,6 @@ go_test(
|
|||||||
name = "go_default_test",
|
name = "go_default_test",
|
||||||
srcs = [
|
srcs = [
|
||||||
"scheduler_assume_cache_test.go",
|
"scheduler_assume_cache_test.go",
|
||||||
"scheduler_binder_cache_test.go",
|
|
||||||
"scheduler_binder_test.go",
|
"scheduler_binder_test.go",
|
||||||
],
|
],
|
||||||
embed = [":go_default_library"],
|
embed = [":go_default_library"],
|
||||||
|
@ -25,6 +25,7 @@ import (
|
|||||||
|
|
||||||
v1 "k8s.io/api/core/v1"
|
v1 "k8s.io/api/core/v1"
|
||||||
storagev1 "k8s.io/api/storage/v1"
|
storagev1 "k8s.io/api/storage/v1"
|
||||||
|
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/labels"
|
"k8s.io/apimachinery/pkg/labels"
|
||||||
"k8s.io/apimachinery/pkg/util/sets"
|
"k8s.io/apimachinery/pkg/util/sets"
|
||||||
@ -34,6 +35,7 @@ import (
|
|||||||
coreinformers "k8s.io/client-go/informers/core/v1"
|
coreinformers "k8s.io/client-go/informers/core/v1"
|
||||||
storageinformers "k8s.io/client-go/informers/storage/v1"
|
storageinformers "k8s.io/client-go/informers/storage/v1"
|
||||||
clientset "k8s.io/client-go/kubernetes"
|
clientset "k8s.io/client-go/kubernetes"
|
||||||
|
corelisters "k8s.io/client-go/listers/core/v1"
|
||||||
storagelisters "k8s.io/client-go/listers/storage/v1"
|
storagelisters "k8s.io/client-go/listers/storage/v1"
|
||||||
csitrans "k8s.io/csi-translation-lib"
|
csitrans "k8s.io/csi-translation-lib"
|
||||||
csiplugins "k8s.io/csi-translation-lib/plugins"
|
csiplugins "k8s.io/csi-translation-lib/plugins"
|
||||||
@ -63,6 +65,24 @@ const (
|
|||||||
ErrReasonNodeConflict ConflictReason = "node(s) had volume node affinity conflict"
|
ErrReasonNodeConflict ConflictReason = "node(s) had volume node affinity conflict"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// BindingInfo holds a binding between PV and PVC.
|
||||||
|
type BindingInfo struct {
|
||||||
|
// PVC that needs to be bound
|
||||||
|
pvc *v1.PersistentVolumeClaim
|
||||||
|
|
||||||
|
// Proposed PV to bind to this PVC
|
||||||
|
pv *v1.PersistentVolume
|
||||||
|
}
|
||||||
|
|
||||||
|
// PodVolumes holds pod's volumes information used in volume scheduling.
|
||||||
|
type PodVolumes struct {
|
||||||
|
// StaticBindings are binding decisions for PVCs which can be bound to
|
||||||
|
// pre-provisioned static PVs.
|
||||||
|
StaticBindings []*BindingInfo
|
||||||
|
// DynamicProvisions are PVCs that require dynamic provisioning
|
||||||
|
DynamicProvisions []*v1.PersistentVolumeClaim
|
||||||
|
}
|
||||||
|
|
||||||
// InTreeToCSITranslator contains methods required to check migratable status
|
// InTreeToCSITranslator contains methods required to check migratable status
|
||||||
// and perform translations from InTree PV's to CSI
|
// and perform translations from InTree PV's to CSI
|
||||||
type InTreeToCSITranslator interface {
|
type InTreeToCSITranslator interface {
|
||||||
@ -102,7 +122,8 @@ type SchedulerVolumeBinder interface {
|
|||||||
// and unbound with immediate binding (including prebound)
|
// and unbound with immediate binding (including prebound)
|
||||||
GetPodVolumes(pod *v1.Pod) (boundClaims, unboundClaimsDelayBinding, unboundClaimsImmediate []*v1.PersistentVolumeClaim, err error)
|
GetPodVolumes(pod *v1.Pod) (boundClaims, unboundClaimsDelayBinding, unboundClaimsImmediate []*v1.PersistentVolumeClaim, err error)
|
||||||
|
|
||||||
// FindPodVolumes checks if all of a Pod's PVCs can be satisfied by the node.
|
// FindPodVolumes checks if all of a Pod's PVCs can be satisfied by the
|
||||||
|
// node and returns pod's volumes information.
|
||||||
//
|
//
|
||||||
// If a PVC is bound, it checks if the PV's NodeAffinity matches the Node.
|
// If a PVC is bound, it checks if the PV's NodeAffinity matches the Node.
|
||||||
// Otherwise, it tries to find an available PV to bind to the PVC.
|
// Otherwise, it tries to find an available PV to bind to the PVC.
|
||||||
@ -110,8 +131,8 @@ type SchedulerVolumeBinder interface {
|
|||||||
// It returns an error when something went wrong or a list of reasons why the node is
|
// It returns an error when something went wrong or a list of reasons why the node is
|
||||||
// (currently) not usable for the pod.
|
// (currently) not usable for the pod.
|
||||||
//
|
//
|
||||||
// This function is called by the volume binding scheduler predicate and can be called in parallel
|
// This function is called by the scheduler VolumeBinding plugin and can be called in parallel
|
||||||
FindPodVolumes(pod *v1.Pod, boundClaims, claimsToBind []*v1.PersistentVolumeClaim, node *v1.Node) (reasons ConflictReasons, err error)
|
FindPodVolumes(pod *v1.Pod, boundClaims, claimsToBind []*v1.PersistentVolumeClaim, node *v1.Node) (podVolumes *PodVolumes, reasons ConflictReasons, err error)
|
||||||
|
|
||||||
// AssumePodVolumes will:
|
// AssumePodVolumes will:
|
||||||
// 1. Take the PV matches for unbound PVCs and update the PV cache assuming
|
// 1. Take the PV matches for unbound PVCs and update the PV cache assuming
|
||||||
@ -122,10 +143,10 @@ type SchedulerVolumeBinder interface {
|
|||||||
// It returns true if all volumes are fully bound
|
// It returns true if all volumes are fully bound
|
||||||
//
|
//
|
||||||
// This function is called serially.
|
// This function is called serially.
|
||||||
AssumePodVolumes(assumedPod *v1.Pod, nodeName string) (allFullyBound bool, err error)
|
AssumePodVolumes(assumedPod *v1.Pod, nodeName string, podVolumes *PodVolumes) (allFullyBound bool, err error)
|
||||||
|
|
||||||
// RevertAssumedPodVolumes will revert assumed PV and PVC cache.
|
// RevertAssumedPodVolumes will revert assumed PV and PVC cache.
|
||||||
RevertAssumedPodVolumes(assumedPod *v1.Pod, nodeName string)
|
RevertAssumedPodVolumes(podVolumes *PodVolumes)
|
||||||
|
|
||||||
// BindPodVolumes will:
|
// BindPodVolumes will:
|
||||||
// 1. Initiate the volume binding by making the API call to prebind the PV
|
// 1. Initiate the volume binding by making the API call to prebind the PV
|
||||||
@ -135,28 +156,19 @@ type SchedulerVolumeBinder interface {
|
|||||||
// 3. Wait for PVCs to be completely bound by the PV controller
|
// 3. Wait for PVCs to be completely bound by the PV controller
|
||||||
//
|
//
|
||||||
// This function can be called in parallel.
|
// This function can be called in parallel.
|
||||||
BindPodVolumes(assumedPod *v1.Pod) error
|
BindPodVolumes(assumedPod *v1.Pod, podVolumes *PodVolumes) error
|
||||||
|
|
||||||
// GetBindingsCache returns the cache used (if any) to store volume binding decisions.
|
|
||||||
GetBindingsCache() PodBindingCache
|
|
||||||
|
|
||||||
// DeletePodBindings will delete pod's bindingDecisions in podBindingCache.
|
|
||||||
DeletePodBindings(pod *v1.Pod)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type volumeBinder struct {
|
type volumeBinder struct {
|
||||||
kubeClient clientset.Interface
|
kubeClient clientset.Interface
|
||||||
classLister storagelisters.StorageClassLister
|
classLister storagelisters.StorageClassLister
|
||||||
|
|
||||||
|
podLister corelisters.PodLister
|
||||||
nodeInformer coreinformers.NodeInformer
|
nodeInformer coreinformers.NodeInformer
|
||||||
csiNodeInformer storageinformers.CSINodeInformer
|
csiNodeInformer storageinformers.CSINodeInformer
|
||||||
pvcCache PVCAssumeCache
|
pvcCache PVCAssumeCache
|
||||||
pvCache PVAssumeCache
|
pvCache PVAssumeCache
|
||||||
|
|
||||||
// Stores binding decisions that were made in FindPodVolumes for use in AssumePodVolumes.
|
|
||||||
// AssumePodVolumes modifies the bindings again for use in BindPodVolumes.
|
|
||||||
podBindingCache PodBindingCache
|
|
||||||
|
|
||||||
// Amount of time to wait for the bind operation to succeed
|
// Amount of time to wait for the bind operation to succeed
|
||||||
bindTimeout time.Duration
|
bindTimeout time.Duration
|
||||||
|
|
||||||
@ -166,44 +178,31 @@ type volumeBinder struct {
|
|||||||
// NewVolumeBinder sets up all the caches needed for the scheduler to make volume binding decisions.
|
// NewVolumeBinder sets up all the caches needed for the scheduler to make volume binding decisions.
|
||||||
func NewVolumeBinder(
|
func NewVolumeBinder(
|
||||||
kubeClient clientset.Interface,
|
kubeClient clientset.Interface,
|
||||||
|
podInformer coreinformers.PodInformer,
|
||||||
nodeInformer coreinformers.NodeInformer,
|
nodeInformer coreinformers.NodeInformer,
|
||||||
csiNodeInformer storageinformers.CSINodeInformer,
|
csiNodeInformer storageinformers.CSINodeInformer,
|
||||||
pvcInformer coreinformers.PersistentVolumeClaimInformer,
|
pvcInformer coreinformers.PersistentVolumeClaimInformer,
|
||||||
pvInformer coreinformers.PersistentVolumeInformer,
|
pvInformer coreinformers.PersistentVolumeInformer,
|
||||||
storageClassInformer storageinformers.StorageClassInformer,
|
storageClassInformer storageinformers.StorageClassInformer,
|
||||||
bindTimeout time.Duration) SchedulerVolumeBinder {
|
bindTimeout time.Duration) SchedulerVolumeBinder {
|
||||||
|
return &volumeBinder{
|
||||||
b := &volumeBinder{
|
|
||||||
kubeClient: kubeClient,
|
kubeClient: kubeClient,
|
||||||
|
podLister: podInformer.Lister(),
|
||||||
classLister: storageClassInformer.Lister(),
|
classLister: storageClassInformer.Lister(),
|
||||||
nodeInformer: nodeInformer,
|
nodeInformer: nodeInformer,
|
||||||
csiNodeInformer: csiNodeInformer,
|
csiNodeInformer: csiNodeInformer,
|
||||||
pvcCache: NewPVCAssumeCache(pvcInformer.Informer()),
|
pvcCache: NewPVCAssumeCache(pvcInformer.Informer()),
|
||||||
pvCache: NewPVAssumeCache(pvInformer.Informer()),
|
pvCache: NewPVAssumeCache(pvInformer.Informer()),
|
||||||
podBindingCache: NewPodBindingCache(),
|
|
||||||
bindTimeout: bindTimeout,
|
bindTimeout: bindTimeout,
|
||||||
translator: csitrans.New(),
|
translator: csitrans.New(),
|
||||||
}
|
}
|
||||||
|
|
||||||
return b
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *volumeBinder) GetBindingsCache() PodBindingCache {
|
// FindPodVolumes finds the matching PVs for PVCs and nodes to provision PVs
|
||||||
return b.podBindingCache
|
// for the given pod and node. If the node does not fit, confilict reasons are
|
||||||
}
|
// returned.
|
||||||
|
func (b *volumeBinder) FindPodVolumes(pod *v1.Pod, boundClaims, claimsToBind []*v1.PersistentVolumeClaim, node *v1.Node) (podVolumes *PodVolumes, reasons ConflictReasons, err error) {
|
||||||
// DeletePodBindings will delete pod's bindingDecisions in podBindingCache.
|
podVolumes = &PodVolumes{}
|
||||||
func (b *volumeBinder) DeletePodBindings(pod *v1.Pod) {
|
|
||||||
cache := b.podBindingCache
|
|
||||||
if pod != nil {
|
|
||||||
cache.DeleteBindings(pod)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// FindPodVolumes caches the matching PVs and PVCs to provision per node in podBindingCache.
|
|
||||||
// This method intentionally takes in a *v1.Node object instead of using volumebinder.nodeInformer.
|
|
||||||
// That's necessary because some operations will need to pass in to the predicate fake node objects.
|
|
||||||
func (b *volumeBinder) FindPodVolumes(pod *v1.Pod, boundClaims, claimsToBind []*v1.PersistentVolumeClaim, node *v1.Node) (reasons ConflictReasons, err error) {
|
|
||||||
podName := getPodName(pod)
|
podName := getPodName(pod)
|
||||||
|
|
||||||
// Warning: Below log needs high verbosity as it can be printed several times (#60933).
|
// Warning: Below log needs high verbosity as it can be printed several times (#60933).
|
||||||
@ -235,16 +234,10 @@ func (b *volumeBinder) FindPodVolumes(pod *v1.Pod, boundClaims, claimsToBind []*
|
|||||||
}()
|
}()
|
||||||
|
|
||||||
var (
|
var (
|
||||||
matchedBindings []*bindingInfo
|
matchedBindings []*BindingInfo
|
||||||
provisionedClaims []*v1.PersistentVolumeClaim
|
provisionedClaims []*v1.PersistentVolumeClaim
|
||||||
)
|
)
|
||||||
defer func() {
|
defer func() {
|
||||||
// We recreate bindings for each new schedule loop.
|
|
||||||
if len(matchedBindings) == 0 && len(provisionedClaims) == 0 {
|
|
||||||
// Clear cache if no claims to bind or provision for this node.
|
|
||||||
b.podBindingCache.ClearBindings(pod, node.Name)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
// Although we do not distinguish nil from empty in this function, for
|
// Although we do not distinguish nil from empty in this function, for
|
||||||
// easier testing, we normalize empty to nil.
|
// easier testing, we normalize empty to nil.
|
||||||
if len(matchedBindings) == 0 {
|
if len(matchedBindings) == 0 {
|
||||||
@ -253,15 +246,15 @@ func (b *volumeBinder) FindPodVolumes(pod *v1.Pod, boundClaims, claimsToBind []*
|
|||||||
if len(provisionedClaims) == 0 {
|
if len(provisionedClaims) == 0 {
|
||||||
provisionedClaims = nil
|
provisionedClaims = nil
|
||||||
}
|
}
|
||||||
// Mark cache with all matched and provisioned claims for this node
|
podVolumes.StaticBindings = matchedBindings
|
||||||
b.podBindingCache.UpdateBindings(pod, node.Name, matchedBindings, provisionedClaims)
|
podVolumes.DynamicProvisions = provisionedClaims
|
||||||
}()
|
}()
|
||||||
|
|
||||||
// Check PV node affinity on bound volumes
|
// Check PV node affinity on bound volumes
|
||||||
if len(boundClaims) > 0 {
|
if len(boundClaims) > 0 {
|
||||||
boundVolumesSatisfied, err = b.checkBoundClaims(boundClaims, node, podName)
|
boundVolumesSatisfied, err = b.checkBoundClaims(boundClaims, node, podName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -291,7 +284,7 @@ func (b *volumeBinder) FindPodVolumes(pod *v1.Pod, boundClaims, claimsToBind []*
|
|||||||
var unboundClaims []*v1.PersistentVolumeClaim
|
var unboundClaims []*v1.PersistentVolumeClaim
|
||||||
unboundVolumesSatisfied, matchedBindings, unboundClaims, err = b.findMatchingVolumes(pod, claimsToFindMatching, node)
|
unboundVolumesSatisfied, matchedBindings, unboundClaims, err = b.findMatchingVolumes(pod, claimsToFindMatching, node)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return
|
||||||
}
|
}
|
||||||
claimsToProvision = append(claimsToProvision, unboundClaims...)
|
claimsToProvision = append(claimsToProvision, unboundClaims...)
|
||||||
}
|
}
|
||||||
@ -300,7 +293,7 @@ func (b *volumeBinder) FindPodVolumes(pod *v1.Pod, boundClaims, claimsToBind []*
|
|||||||
if len(claimsToProvision) > 0 {
|
if len(claimsToProvision) > 0 {
|
||||||
unboundVolumesSatisfied, provisionedClaims, err = b.checkVolumeProvisions(pod, claimsToProvision, node)
|
unboundVolumesSatisfied, provisionedClaims, err = b.checkVolumeProvisions(pod, claimsToProvision, node)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -308,12 +301,12 @@ func (b *volumeBinder) FindPodVolumes(pod *v1.Pod, boundClaims, claimsToBind []*
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// AssumePodVolumes will take the cached matching PVs and PVCs to provision
|
// AssumePodVolumes will take the matching PVs and PVCs to provision in pod's
|
||||||
// in podBindingCache for the chosen node, and:
|
// volume information for the chosen node, and:
|
||||||
// 1. Update the pvCache with the new prebound PV.
|
// 1. Update the pvCache with the new prebound PV.
|
||||||
// 2. Update the pvcCache with the new PVCs with annotations set
|
// 2. Update the pvcCache with the new PVCs with annotations set
|
||||||
// 3. Update podBindingCache again with cached API updates for PVs and PVCs.
|
// 3. Update PodVolumes again with cached API updates for PVs and PVCs.
|
||||||
func (b *volumeBinder) AssumePodVolumes(assumedPod *v1.Pod, nodeName string) (allFullyBound bool, err error) {
|
func (b *volumeBinder) AssumePodVolumes(assumedPod *v1.Pod, nodeName string, podVolumes *PodVolumes) (allFullyBound bool, err error) {
|
||||||
podName := getPodName(assumedPod)
|
podName := getPodName(assumedPod)
|
||||||
|
|
||||||
klog.V(4).Infof("AssumePodVolumes for pod %q, node %q", podName, nodeName)
|
klog.V(4).Infof("AssumePodVolumes for pod %q, node %q", podName, nodeName)
|
||||||
@ -330,12 +323,9 @@ func (b *volumeBinder) AssumePodVolumes(assumedPod *v1.Pod, nodeName string) (al
|
|||||||
return true, nil
|
return true, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
claimsToBind := b.podBindingCache.GetBindings(assumedPod, nodeName)
|
|
||||||
claimsToProvision := b.podBindingCache.GetProvisionedPVCs(assumedPod, nodeName)
|
|
||||||
|
|
||||||
// Assume PV
|
// Assume PV
|
||||||
newBindings := []*bindingInfo{}
|
newBindings := []*BindingInfo{}
|
||||||
for _, binding := range claimsToBind {
|
for _, binding := range podVolumes.StaticBindings {
|
||||||
newPV, dirty, err := pvutil.GetBindVolumeToClaim(binding.pv, binding.pvc)
|
newPV, dirty, err := pvutil.GetBindVolumeToClaim(binding.pv, binding.pvc)
|
||||||
klog.V(5).Infof("AssumePodVolumes: GetBindVolumeToClaim for pod %q, PV %q, PVC %q. newPV %p, dirty %v, err: %v",
|
klog.V(5).Infof("AssumePodVolumes: GetBindVolumeToClaim for pod %q, PV %q, PVC %q. newPV %p, dirty %v, err: %v",
|
||||||
podName,
|
podName,
|
||||||
@ -356,12 +346,12 @@ func (b *volumeBinder) AssumePodVolumes(assumedPod *v1.Pod, nodeName string) (al
|
|||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
newBindings = append(newBindings, &bindingInfo{pv: newPV, pvc: binding.pvc})
|
newBindings = append(newBindings, &BindingInfo{pv: newPV, pvc: binding.pvc})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Assume PVCs
|
// Assume PVCs
|
||||||
newProvisionedPVCs := []*v1.PersistentVolumeClaim{}
|
newProvisionedPVCs := []*v1.PersistentVolumeClaim{}
|
||||||
for _, claim := range claimsToProvision {
|
for _, claim := range podVolumes.DynamicProvisions {
|
||||||
// The claims from method args can be pointing to watcher cache. We must not
|
// The claims from method args can be pointing to watcher cache. We must not
|
||||||
// modify these, therefore create a copy.
|
// modify these, therefore create a copy.
|
||||||
claimClone := claim.DeepCopy()
|
claimClone := claim.DeepCopy()
|
||||||
@ -376,24 +366,21 @@ func (b *volumeBinder) AssumePodVolumes(assumedPod *v1.Pod, nodeName string) (al
|
|||||||
newProvisionedPVCs = append(newProvisionedPVCs, claimClone)
|
newProvisionedPVCs = append(newProvisionedPVCs, claimClone)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update cache with the assumed pvcs and pvs
|
podVolumes.StaticBindings = newBindings
|
||||||
// Even if length is zero, update the cache with an empty slice to indicate that no
|
podVolumes.DynamicProvisions = newProvisionedPVCs
|
||||||
// operations are needed
|
|
||||||
b.podBindingCache.UpdateBindings(assumedPod, nodeName, newBindings, newProvisionedPVCs)
|
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// RevertAssumedPodVolumes will revert assumed PV and PVC cache.
|
// RevertAssumedPodVolumes will revert assumed PV and PVC cache.
|
||||||
func (b *volumeBinder) RevertAssumedPodVolumes(assumedPod *v1.Pod, nodeName string) {
|
func (b *volumeBinder) RevertAssumedPodVolumes(podVolumes *PodVolumes) {
|
||||||
b.revertAssumedPVs(b.podBindingCache.GetBindings(assumedPod, nodeName))
|
b.revertAssumedPVs(podVolumes.StaticBindings)
|
||||||
b.revertAssumedPVCs(b.podBindingCache.GetProvisionedPVCs(assumedPod, nodeName))
|
b.revertAssumedPVCs(podVolumes.DynamicProvisions)
|
||||||
}
|
}
|
||||||
|
|
||||||
// BindPodVolumes gets the cached bindings and PVCs to provision in podBindingCache,
|
// BindPodVolumes gets the cached bindings and PVCs to provision in pod's volumes information,
|
||||||
// makes the API update for those PVs/PVCs, and waits for the PVCs to be completely bound
|
// makes the API update for those PVs/PVCs, and waits for the PVCs to be completely bound
|
||||||
// by the PV controller.
|
// by the PV controller.
|
||||||
func (b *volumeBinder) BindPodVolumes(assumedPod *v1.Pod) (err error) {
|
func (b *volumeBinder) BindPodVolumes(assumedPod *v1.Pod, podVolumes *PodVolumes) (err error) {
|
||||||
podName := getPodName(assumedPod)
|
podName := getPodName(assumedPod)
|
||||||
klog.V(4).Infof("BindPodVolumes for pod %q, node %q", podName, assumedPod.Spec.NodeName)
|
klog.V(4).Infof("BindPodVolumes for pod %q, node %q", podName, assumedPod.Spec.NodeName)
|
||||||
|
|
||||||
@ -405,8 +392,8 @@ func (b *volumeBinder) BindPodVolumes(assumedPod *v1.Pod) (err error) {
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
bindings := b.podBindingCache.GetBindings(assumedPod, assumedPod.Spec.NodeName)
|
bindings := podVolumes.StaticBindings
|
||||||
claimsToProvision := b.podBindingCache.GetProvisionedPVCs(assumedPod, assumedPod.Spec.NodeName)
|
claimsToProvision := podVolumes.DynamicProvisions
|
||||||
|
|
||||||
// Start API operations
|
// Start API operations
|
||||||
err = b.bindAPIUpdate(podName, bindings, claimsToProvision)
|
err = b.bindAPIUpdate(podName, bindings, claimsToProvision)
|
||||||
@ -432,9 +419,8 @@ func getPVCName(pvc *v1.PersistentVolumeClaim) string {
|
|||||||
return pvc.Namespace + "/" + pvc.Name
|
return pvc.Namespace + "/" + pvc.Name
|
||||||
}
|
}
|
||||||
|
|
||||||
// bindAPIUpdate gets the cached bindings and PVCs to provision in podBindingCache
|
// bindAPIUpdate makes the API update for those PVs/PVCs.
|
||||||
// and makes the API update for those PVs/PVCs.
|
func (b *volumeBinder) bindAPIUpdate(podName string, bindings []*BindingInfo, claimsToProvision []*v1.PersistentVolumeClaim) error {
|
||||||
func (b *volumeBinder) bindAPIUpdate(podName string, bindings []*bindingInfo, claimsToProvision []*v1.PersistentVolumeClaim) error {
|
|
||||||
if bindings == nil {
|
if bindings == nil {
|
||||||
return fmt.Errorf("failed to get cached bindings for pod %q", podName)
|
return fmt.Errorf("failed to get cached bindings for pod %q", podName)
|
||||||
}
|
}
|
||||||
@ -456,7 +442,7 @@ func (b *volumeBinder) bindAPIUpdate(podName string, bindings []*bindingInfo, cl
|
|||||||
}()
|
}()
|
||||||
|
|
||||||
var (
|
var (
|
||||||
binding *bindingInfo
|
binding *BindingInfo
|
||||||
i int
|
i int
|
||||||
claim *v1.PersistentVolumeClaim
|
claim *v1.PersistentVolumeClaim
|
||||||
)
|
)
|
||||||
@ -509,7 +495,7 @@ var (
|
|||||||
// PV/PVC cache can be assumed again in main scheduler loop, we must check
|
// PV/PVC cache can be assumed again in main scheduler loop, we must check
|
||||||
// latest state in API server which are shared with PV controller and
|
// latest state in API server which are shared with PV controller and
|
||||||
// provisioners
|
// provisioners
|
||||||
func (b *volumeBinder) checkBindings(pod *v1.Pod, bindings []*bindingInfo, claimsToProvision []*v1.PersistentVolumeClaim) (bool, error) {
|
func (b *volumeBinder) checkBindings(pod *v1.Pod, bindings []*BindingInfo, claimsToProvision []*v1.PersistentVolumeClaim) (bool, error) {
|
||||||
podName := getPodName(pod)
|
podName := getPodName(pod)
|
||||||
if bindings == nil {
|
if bindings == nil {
|
||||||
return false, fmt.Errorf("failed to get cached bindings for pod %q", podName)
|
return false, fmt.Errorf("failed to get cached bindings for pod %q", podName)
|
||||||
@ -531,13 +517,14 @@ func (b *volumeBinder) checkBindings(pod *v1.Pod, bindings []*bindingInfo, claim
|
|||||||
|
|
||||||
// Check for any conditions that might require scheduling retry
|
// Check for any conditions that might require scheduling retry
|
||||||
|
|
||||||
// When pod is removed from scheduling queue because of deletion or any
|
// When pod is deleted, binding operation should be cancelled. There is no
|
||||||
// other reasons, binding operation should be cancelled. There is no need
|
// need to check PV/PVC bindings any more.
|
||||||
// to check PV/PVC bindings any more.
|
_, err = b.podLister.Pods(pod.Namespace).Get(pod.Name)
|
||||||
// We check pod binding cache here which will be cleared when pod is
|
if err != nil {
|
||||||
// removed from scheduling queue.
|
if apierrors.IsNotFound(err) {
|
||||||
if b.podBindingCache.GetDecisions(pod) == nil {
|
return false, fmt.Errorf("pod %q does not exist any more", podName)
|
||||||
return false, fmt.Errorf("pod %q does not exist any more", podName)
|
}
|
||||||
|
klog.Errorf("failed to get pod %s/%s from the lister: %v", pod.Namespace, pod.Name, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, binding := range bindings {
|
for _, binding := range bindings {
|
||||||
@ -756,7 +743,7 @@ func (b *volumeBinder) checkBoundClaims(claims []*v1.PersistentVolumeClaim, node
|
|||||||
|
|
||||||
// findMatchingVolumes tries to find matching volumes for given claims,
|
// findMatchingVolumes tries to find matching volumes for given claims,
|
||||||
// and return unbound claims for further provision.
|
// and return unbound claims for further provision.
|
||||||
func (b *volumeBinder) findMatchingVolumes(pod *v1.Pod, claimsToBind []*v1.PersistentVolumeClaim, node *v1.Node) (foundMatches bool, bindings []*bindingInfo, unboundClaims []*v1.PersistentVolumeClaim, err error) {
|
func (b *volumeBinder) findMatchingVolumes(pod *v1.Pod, claimsToBind []*v1.PersistentVolumeClaim, node *v1.Node) (foundMatches bool, bindings []*BindingInfo, unboundClaims []*v1.PersistentVolumeClaim, err error) {
|
||||||
podName := getPodName(pod)
|
podName := getPodName(pod)
|
||||||
// Sort all the claims by increasing size request to get the smallest fits
|
// Sort all the claims by increasing size request to get the smallest fits
|
||||||
sort.Sort(byPVCSize(claimsToBind))
|
sort.Sort(byPVCSize(claimsToBind))
|
||||||
@ -785,7 +772,7 @@ func (b *volumeBinder) findMatchingVolumes(pod *v1.Pod, claimsToBind []*v1.Persi
|
|||||||
|
|
||||||
// matching PV needs to be excluded so we don't select it again
|
// matching PV needs to be excluded so we don't select it again
|
||||||
chosenPVs[pv.Name] = pv
|
chosenPVs[pv.Name] = pv
|
||||||
bindings = append(bindings, &bindingInfo{pv: pv, pvc: pvc})
|
bindings = append(bindings, &BindingInfo{pv: pv, pvc: pvc})
|
||||||
klog.V(5).Infof("Found matching PV %q for PVC %q on node %q for pod %q", pv.Name, pvcName, node.Name, podName)
|
klog.V(5).Infof("Found matching PV %q for PVC %q on node %q for pod %q", pv.Name, pvcName, node.Name, podName)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -837,9 +824,9 @@ func (b *volumeBinder) checkVolumeProvisions(pod *v1.Pod, claimsToProvision []*v
|
|||||||
return true, provisionedClaims, nil
|
return true, provisionedClaims, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *volumeBinder) revertAssumedPVs(bindings []*bindingInfo) {
|
func (b *volumeBinder) revertAssumedPVs(bindings []*BindingInfo) {
|
||||||
for _, bindingInfo := range bindings {
|
for _, BindingInfo := range bindings {
|
||||||
b.pvCache.Restore(bindingInfo.pv.Name)
|
b.pvCache.Restore(BindingInfo.pv.Name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -849,14 +836,6 @@ func (b *volumeBinder) revertAssumedPVCs(claims []*v1.PersistentVolumeClaim) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type bindingInfo struct {
|
|
||||||
// Claim that needs to be bound
|
|
||||||
pvc *v1.PersistentVolumeClaim
|
|
||||||
|
|
||||||
// Proposed PV to bind to this claim
|
|
||||||
pv *v1.PersistentVolume
|
|
||||||
}
|
|
||||||
|
|
||||||
type byPVCSize []*v1.PersistentVolumeClaim
|
type byPVCSize []*v1.PersistentVolumeClaim
|
||||||
|
|
||||||
func (a byPVCSize) Len() int {
|
func (a byPVCSize) Len() int {
|
||||||
|
@ -1,167 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright 2017 The Kubernetes Authors.
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package scheduling
|
|
||||||
|
|
||||||
import (
|
|
||||||
"sync"
|
|
||||||
|
|
||||||
v1 "k8s.io/api/core/v1"
|
|
||||||
"k8s.io/kubernetes/pkg/controller/volume/scheduling/metrics"
|
|
||||||
)
|
|
||||||
|
|
||||||
// PodBindingCache stores PV binding decisions per pod per node.
|
|
||||||
// Pod entries are removed when the Pod is deleted or updated to
|
|
||||||
// no longer be schedulable.
|
|
||||||
type PodBindingCache interface {
|
|
||||||
// UpdateBindings will update the cache with the given bindings for the
|
|
||||||
// pod and node.
|
|
||||||
UpdateBindings(pod *v1.Pod, node string, bindings []*bindingInfo, provisionings []*v1.PersistentVolumeClaim)
|
|
||||||
|
|
||||||
// ClearBindings will clear the cached bindings for the given pod and node.
|
|
||||||
ClearBindings(pod *v1.Pod, node string)
|
|
||||||
|
|
||||||
// GetBindings will return the cached bindings for the given pod and node.
|
|
||||||
// A nil return value means that the entry was not found. An empty slice
|
|
||||||
// means that no binding operations are needed.
|
|
||||||
GetBindings(pod *v1.Pod, node string) []*bindingInfo
|
|
||||||
|
|
||||||
// A nil return value means that the entry was not found. An empty slice
|
|
||||||
// means that no provisioning operations are needed.
|
|
||||||
GetProvisionedPVCs(pod *v1.Pod, node string) []*v1.PersistentVolumeClaim
|
|
||||||
|
|
||||||
// GetDecisions will return all cached decisions for the given pod.
|
|
||||||
GetDecisions(pod *v1.Pod) nodeDecisions
|
|
||||||
|
|
||||||
// DeleteBindings will remove all cached bindings and provisionings for the given pod.
|
|
||||||
// TODO: separate the func if it is needed to delete bindings/provisionings individually
|
|
||||||
DeleteBindings(pod *v1.Pod)
|
|
||||||
}
|
|
||||||
|
|
||||||
type podBindingCache struct {
|
|
||||||
// synchronizes bindingDecisions
|
|
||||||
rwMutex sync.RWMutex
|
|
||||||
|
|
||||||
// Key = pod name
|
|
||||||
// Value = nodeDecisions
|
|
||||||
bindingDecisions map[string]nodeDecisions
|
|
||||||
}
|
|
||||||
|
|
||||||
// Key = nodeName
|
|
||||||
// Value = bindings & provisioned PVCs of the node
|
|
||||||
type nodeDecisions map[string]nodeDecision
|
|
||||||
|
|
||||||
// A decision includes bindingInfo and provisioned PVCs of the node
|
|
||||||
type nodeDecision struct {
|
|
||||||
bindings []*bindingInfo
|
|
||||||
provisionings []*v1.PersistentVolumeClaim
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewPodBindingCache creates a pod binding cache.
|
|
||||||
func NewPodBindingCache() PodBindingCache {
|
|
||||||
return &podBindingCache{bindingDecisions: map[string]nodeDecisions{}}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *podBindingCache) GetDecisions(pod *v1.Pod) nodeDecisions {
|
|
||||||
c.rwMutex.RLock()
|
|
||||||
defer c.rwMutex.RUnlock()
|
|
||||||
podName := getPodName(pod)
|
|
||||||
decisions, ok := c.bindingDecisions[podName]
|
|
||||||
if !ok {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return decisions
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *podBindingCache) DeleteBindings(pod *v1.Pod) {
|
|
||||||
c.rwMutex.Lock()
|
|
||||||
defer c.rwMutex.Unlock()
|
|
||||||
|
|
||||||
podName := getPodName(pod)
|
|
||||||
|
|
||||||
if _, ok := c.bindingDecisions[podName]; ok {
|
|
||||||
delete(c.bindingDecisions, podName)
|
|
||||||
metrics.VolumeBindingRequestSchedulerBinderCache.WithLabelValues("delete").Inc()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *podBindingCache) UpdateBindings(pod *v1.Pod, node string, bindings []*bindingInfo, pvcs []*v1.PersistentVolumeClaim) {
|
|
||||||
c.rwMutex.Lock()
|
|
||||||
defer c.rwMutex.Unlock()
|
|
||||||
|
|
||||||
podName := getPodName(pod)
|
|
||||||
decisions, ok := c.bindingDecisions[podName]
|
|
||||||
if !ok {
|
|
||||||
decisions = nodeDecisions{}
|
|
||||||
c.bindingDecisions[podName] = decisions
|
|
||||||
}
|
|
||||||
decision, ok := decisions[node]
|
|
||||||
if !ok {
|
|
||||||
decision = nodeDecision{
|
|
||||||
bindings: bindings,
|
|
||||||
provisionings: pvcs,
|
|
||||||
}
|
|
||||||
metrics.VolumeBindingRequestSchedulerBinderCache.WithLabelValues("add").Inc()
|
|
||||||
} else {
|
|
||||||
decision.bindings = bindings
|
|
||||||
decision.provisionings = pvcs
|
|
||||||
}
|
|
||||||
decisions[node] = decision
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *podBindingCache) GetBindings(pod *v1.Pod, node string) []*bindingInfo {
|
|
||||||
c.rwMutex.RLock()
|
|
||||||
defer c.rwMutex.RUnlock()
|
|
||||||
|
|
||||||
podName := getPodName(pod)
|
|
||||||
decisions, ok := c.bindingDecisions[podName]
|
|
||||||
if !ok {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
decision, ok := decisions[node]
|
|
||||||
if !ok {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return decision.bindings
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *podBindingCache) GetProvisionedPVCs(pod *v1.Pod, node string) []*v1.PersistentVolumeClaim {
|
|
||||||
c.rwMutex.RLock()
|
|
||||||
defer c.rwMutex.RUnlock()
|
|
||||||
|
|
||||||
podName := getPodName(pod)
|
|
||||||
decisions, ok := c.bindingDecisions[podName]
|
|
||||||
if !ok {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
decision, ok := decisions[node]
|
|
||||||
if !ok {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return decision.provisionings
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *podBindingCache) ClearBindings(pod *v1.Pod, node string) {
|
|
||||||
c.rwMutex.Lock()
|
|
||||||
defer c.rwMutex.Unlock()
|
|
||||||
|
|
||||||
podName := getPodName(pod)
|
|
||||||
decisions, ok := c.bindingDecisions[podName]
|
|
||||||
if !ok {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
delete(decisions, node)
|
|
||||||
}
|
|
@ -1,150 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright 2017 The Kubernetes Authors.
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package scheduling
|
|
||||||
|
|
||||||
import (
|
|
||||||
"reflect"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"k8s.io/api/core/v1"
|
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestUpdateGetBindings(t *testing.T) {
|
|
||||||
scenarios := map[string]struct {
|
|
||||||
updateBindings []*bindingInfo
|
|
||||||
updateProvisionings []*v1.PersistentVolumeClaim
|
|
||||||
updatePod string
|
|
||||||
updateNode string
|
|
||||||
|
|
||||||
getBindings []*bindingInfo
|
|
||||||
getProvisionings []*v1.PersistentVolumeClaim
|
|
||||||
getPod string
|
|
||||||
getNode string
|
|
||||||
}{
|
|
||||||
"no-pod": {
|
|
||||||
getPod: "pod1",
|
|
||||||
getNode: "node1",
|
|
||||||
},
|
|
||||||
"no-node": {
|
|
||||||
updatePod: "pod1",
|
|
||||||
updateNode: "node1",
|
|
||||||
updateBindings: []*bindingInfo{},
|
|
||||||
updateProvisionings: []*v1.PersistentVolumeClaim{},
|
|
||||||
getPod: "pod1",
|
|
||||||
getNode: "node2",
|
|
||||||
},
|
|
||||||
"binding-nil": {
|
|
||||||
updatePod: "pod1",
|
|
||||||
updateNode: "node1",
|
|
||||||
updateBindings: nil,
|
|
||||||
updateProvisionings: nil,
|
|
||||||
getPod: "pod1",
|
|
||||||
getNode: "node1",
|
|
||||||
},
|
|
||||||
"binding-exists": {
|
|
||||||
updatePod: "pod1",
|
|
||||||
updateNode: "node1",
|
|
||||||
updateBindings: []*bindingInfo{{pvc: &v1.PersistentVolumeClaim{ObjectMeta: metav1.ObjectMeta{Name: "pvc1"}}}},
|
|
||||||
updateProvisionings: []*v1.PersistentVolumeClaim{{ObjectMeta: metav1.ObjectMeta{Name: "pvc2"}}},
|
|
||||||
getPod: "pod1",
|
|
||||||
getNode: "node1",
|
|
||||||
getBindings: []*bindingInfo{{pvc: &v1.PersistentVolumeClaim{ObjectMeta: metav1.ObjectMeta{Name: "pvc1"}}}},
|
|
||||||
getProvisionings: []*v1.PersistentVolumeClaim{{ObjectMeta: metav1.ObjectMeta{Name: "pvc2"}}},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for name, scenario := range scenarios {
|
|
||||||
cache := NewPodBindingCache()
|
|
||||||
|
|
||||||
// Perform updates
|
|
||||||
updatePod := &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: scenario.updatePod, Namespace: "ns"}}
|
|
||||||
cache.UpdateBindings(updatePod, scenario.updateNode, scenario.updateBindings, scenario.updateProvisionings)
|
|
||||||
|
|
||||||
// Verify updated bindings
|
|
||||||
bindings := cache.GetBindings(updatePod, scenario.updateNode)
|
|
||||||
if !reflect.DeepEqual(bindings, scenario.updateBindings) {
|
|
||||||
t.Errorf("Test %v failed: returned bindings after update different. Got %+v, expected %+v", name, bindings, scenario.updateBindings)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Verify updated provisionings
|
|
||||||
provisionings := cache.GetProvisionedPVCs(updatePod, scenario.updateNode)
|
|
||||||
if !reflect.DeepEqual(provisionings, scenario.updateProvisionings) {
|
|
||||||
t.Errorf("Test %v failed: returned provisionings after update different. Got %+v, expected %+v", name, provisionings, scenario.updateProvisionings)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get bindings
|
|
||||||
getPod := &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: scenario.getPod, Namespace: "ns"}}
|
|
||||||
bindings = cache.GetBindings(getPod, scenario.getNode)
|
|
||||||
if !reflect.DeepEqual(bindings, scenario.getBindings) {
|
|
||||||
t.Errorf("Test %v failed: unexpected bindings returned. Got %+v, expected %+v", name, bindings, scenario.updateBindings)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get provisionings
|
|
||||||
provisionings = cache.GetProvisionedPVCs(getPod, scenario.getNode)
|
|
||||||
if !reflect.DeepEqual(provisionings, scenario.getProvisionings) {
|
|
||||||
t.Errorf("Test %v failed: unexpected bindings returned. Got %+v, expected %+v", name, provisionings, scenario.getProvisionings)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestDeleteBindings(t *testing.T) {
|
|
||||||
initialBindings := []*bindingInfo{{pvc: &v1.PersistentVolumeClaim{ObjectMeta: metav1.ObjectMeta{Name: "pvc1"}}}}
|
|
||||||
initialProvisionings := []*v1.PersistentVolumeClaim{{ObjectMeta: metav1.ObjectMeta{Name: "pvc2"}}}
|
|
||||||
cache := NewPodBindingCache()
|
|
||||||
|
|
||||||
pod := &v1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "pod1", Namespace: "ns"}}
|
|
||||||
|
|
||||||
// Get nil bindings and provisionings
|
|
||||||
bindings := cache.GetBindings(pod, "node1")
|
|
||||||
if bindings != nil {
|
|
||||||
t.Errorf("Test failed: expected initial nil bindings, got %+v", bindings)
|
|
||||||
}
|
|
||||||
provisionings := cache.GetProvisionedPVCs(pod, "node1")
|
|
||||||
if provisionings != nil {
|
|
||||||
t.Errorf("Test failed: expected initial nil provisionings, got %+v", provisionings)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Delete nothing
|
|
||||||
cache.DeleteBindings(pod)
|
|
||||||
|
|
||||||
// Perform updates
|
|
||||||
cache.UpdateBindings(pod, "node1", initialBindings, initialProvisionings)
|
|
||||||
|
|
||||||
// Get bindings and provisionings
|
|
||||||
bindings = cache.GetBindings(pod, "node1")
|
|
||||||
if !reflect.DeepEqual(bindings, initialBindings) {
|
|
||||||
t.Errorf("Test failed: expected bindings %+v, got %+v", initialBindings, bindings)
|
|
||||||
}
|
|
||||||
provisionings = cache.GetProvisionedPVCs(pod, "node1")
|
|
||||||
if !reflect.DeepEqual(provisionings, initialProvisionings) {
|
|
||||||
t.Errorf("Test failed: expected provisionings %+v, got %+v", initialProvisionings, provisionings)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Delete
|
|
||||||
cache.DeleteBindings(pod)
|
|
||||||
|
|
||||||
// Get bindings and provisionings
|
|
||||||
bindings = cache.GetBindings(pod, "node1")
|
|
||||||
if bindings != nil {
|
|
||||||
t.Errorf("Test failed: expected nil bindings, got %+v", bindings)
|
|
||||||
}
|
|
||||||
provisionings = cache.GetProvisionedPVCs(pod, "node1")
|
|
||||||
if provisionings != nil {
|
|
||||||
t.Errorf("Test failed: expected nil provisionings, got %+v", provisionings)
|
|
||||||
}
|
|
||||||
}
|
|
@ -16,7 +16,7 @@ limitations under the License.
|
|||||||
|
|
||||||
package scheduling
|
package scheduling
|
||||||
|
|
||||||
import "k8s.io/api/core/v1"
|
import v1 "k8s.io/api/core/v1"
|
||||||
|
|
||||||
// FakeVolumeBinderConfig holds configurations for fake volume binder.
|
// FakeVolumeBinderConfig holds configurations for fake volume binder.
|
||||||
type FakeVolumeBinderConfig struct {
|
type FakeVolumeBinderConfig struct {
|
||||||
@ -48,29 +48,21 @@ func (b *FakeVolumeBinder) GetPodVolumes(pod *v1.Pod) (boundClaims, unboundClaim
|
|||||||
}
|
}
|
||||||
|
|
||||||
// FindPodVolumes implements SchedulerVolumeBinder.FindPodVolumes.
|
// FindPodVolumes implements SchedulerVolumeBinder.FindPodVolumes.
|
||||||
func (b *FakeVolumeBinder) FindPodVolumes(pod *v1.Pod, _, _ []*v1.PersistentVolumeClaim, node *v1.Node) (reasons ConflictReasons, err error) {
|
func (b *FakeVolumeBinder) FindPodVolumes(pod *v1.Pod, _, _ []*v1.PersistentVolumeClaim, node *v1.Node) (podVolumes *PodVolumes, reasons ConflictReasons, err error) {
|
||||||
return b.config.FindReasons, b.config.FindErr
|
return nil, b.config.FindReasons, b.config.FindErr
|
||||||
}
|
}
|
||||||
|
|
||||||
// AssumePodVolumes implements SchedulerVolumeBinder.AssumePodVolumes.
|
// AssumePodVolumes implements SchedulerVolumeBinder.AssumePodVolumes.
|
||||||
func (b *FakeVolumeBinder) AssumePodVolumes(assumedPod *v1.Pod, nodeName string) (bool, error) {
|
func (b *FakeVolumeBinder) AssumePodVolumes(assumedPod *v1.Pod, nodeName string, podVolumes *PodVolumes) (bool, error) {
|
||||||
b.AssumeCalled = true
|
b.AssumeCalled = true
|
||||||
return b.config.AllBound, b.config.AssumeErr
|
return b.config.AllBound, b.config.AssumeErr
|
||||||
}
|
}
|
||||||
|
|
||||||
// RevertAssumedPodVolumes implements SchedulerVolumeBinder.RevertAssumedPodVolumes
|
// RevertAssumedPodVolumes implements SchedulerVolumeBinder.RevertAssumedPodVolumes
|
||||||
func (b *FakeVolumeBinder) RevertAssumedPodVolumes(assumedPod *v1.Pod, nodeName string) {}
|
func (b *FakeVolumeBinder) RevertAssumedPodVolumes(_ *PodVolumes) {}
|
||||||
|
|
||||||
// BindPodVolumes implements SchedulerVolumeBinder.BindPodVolumes.
|
// BindPodVolumes implements SchedulerVolumeBinder.BindPodVolumes.
|
||||||
func (b *FakeVolumeBinder) BindPodVolumes(assumedPod *v1.Pod) error {
|
func (b *FakeVolumeBinder) BindPodVolumes(assumedPod *v1.Pod, podVolumes *PodVolumes) error {
|
||||||
b.BindCalled = true
|
b.BindCalled = true
|
||||||
return b.config.BindErr
|
return b.config.BindErr
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetBindingsCache implements SchedulerVolumeBinder.GetBindingsCache.
|
|
||||||
func (b *FakeVolumeBinder) GetBindingsCache() PodBindingCache {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// DeletePodBindings implements SchedulerVolumeBinder.DeletePodBindings.
|
|
||||||
func (b *FakeVolumeBinder) DeletePodBindings(pod *v1.Pod) {}
|
|
||||||
|
@ -123,6 +123,7 @@ type testEnv struct {
|
|||||||
reactor *pvtesting.VolumeReactor
|
reactor *pvtesting.VolumeReactor
|
||||||
binder SchedulerVolumeBinder
|
binder SchedulerVolumeBinder
|
||||||
internalBinder *volumeBinder
|
internalBinder *volumeBinder
|
||||||
|
internalPodInformer coreinformers.PodInformer
|
||||||
internalNodeInformer coreinformers.NodeInformer
|
internalNodeInformer coreinformers.NodeInformer
|
||||||
internalCSINodeInformer storageinformers.CSINodeInformer
|
internalCSINodeInformer storageinformers.CSINodeInformer
|
||||||
internalPVCache *assumeCache
|
internalPVCache *assumeCache
|
||||||
@ -144,12 +145,14 @@ func newTestBinder(t *testing.T, stopCh <-chan struct{}) *testEnv {
|
|||||||
})
|
})
|
||||||
informerFactory := informers.NewSharedInformerFactory(client, controller.NoResyncPeriodFunc())
|
informerFactory := informers.NewSharedInformerFactory(client, controller.NoResyncPeriodFunc())
|
||||||
|
|
||||||
|
podInformer := informerFactory.Core().V1().Pods()
|
||||||
nodeInformer := informerFactory.Core().V1().Nodes()
|
nodeInformer := informerFactory.Core().V1().Nodes()
|
||||||
csiNodeInformer := informerFactory.Storage().V1().CSINodes()
|
csiNodeInformer := informerFactory.Storage().V1().CSINodes()
|
||||||
pvcInformer := informerFactory.Core().V1().PersistentVolumeClaims()
|
pvcInformer := informerFactory.Core().V1().PersistentVolumeClaims()
|
||||||
classInformer := informerFactory.Storage().V1().StorageClasses()
|
classInformer := informerFactory.Storage().V1().StorageClasses()
|
||||||
binder := NewVolumeBinder(
|
binder := NewVolumeBinder(
|
||||||
client,
|
client,
|
||||||
|
podInformer,
|
||||||
nodeInformer,
|
nodeInformer,
|
||||||
csiNodeInformer,
|
csiNodeInformer,
|
||||||
pvcInformer,
|
pvcInformer,
|
||||||
@ -246,6 +249,7 @@ func newTestBinder(t *testing.T, stopCh <-chan struct{}) *testEnv {
|
|||||||
reactor: reactor,
|
reactor: reactor,
|
||||||
binder: binder,
|
binder: binder,
|
||||||
internalBinder: internalBinder,
|
internalBinder: internalBinder,
|
||||||
|
internalPodInformer: podInformer,
|
||||||
internalNodeInformer: nodeInformer,
|
internalNodeInformer: nodeInformer,
|
||||||
internalCSINodeInformer: csiNodeInformer,
|
internalCSINodeInformer: csiNodeInformer,
|
||||||
internalPVCache: internalPVCache,
|
internalPVCache: internalPVCache,
|
||||||
@ -358,7 +362,7 @@ func (env *testEnv) deleteClaims(pvcs []*v1.PersistentVolumeClaim) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (env *testEnv) assumeVolumes(t *testing.T, node string, pod *v1.Pod, bindings []*bindingInfo, provisionings []*v1.PersistentVolumeClaim) {
|
func (env *testEnv) assumeVolumes(t *testing.T, node string, pod *v1.Pod, bindings []*BindingInfo, provisionings []*v1.PersistentVolumeClaim) {
|
||||||
pvCache := env.internalBinder.pvCache
|
pvCache := env.internalBinder.pvCache
|
||||||
for _, binding := range bindings {
|
for _, binding := range bindings {
|
||||||
if err := pvCache.Assume(binding.pv); err != nil {
|
if err := pvCache.Assume(binding.pv); err != nil {
|
||||||
@ -372,18 +376,17 @@ func (env *testEnv) assumeVolumes(t *testing.T, node string, pod *v1.Pod, bindin
|
|||||||
t.Fatalf("error: %v", err)
|
t.Fatalf("error: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
env.internalBinder.podBindingCache.UpdateBindings(pod, node, bindings, provisionings)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (env *testEnv) initPodCache(pod *v1.Pod, node string, bindings []*bindingInfo, provisionings []*v1.PersistentVolumeClaim) {
|
func (env *testEnv) validatePodCache(t *testing.T, node string, pod *v1.Pod, podVolumes *PodVolumes, expectedBindings []*BindingInfo, expectedProvisionings []*v1.PersistentVolumeClaim) {
|
||||||
cache := env.internalBinder.podBindingCache
|
var (
|
||||||
cache.UpdateBindings(pod, node, bindings, provisionings)
|
bindings []*BindingInfo
|
||||||
}
|
provisionedClaims []*v1.PersistentVolumeClaim
|
||||||
|
)
|
||||||
func (env *testEnv) validatePodCache(t *testing.T, node string, pod *v1.Pod, expectedBindings []*bindingInfo, expectedProvisionings []*v1.PersistentVolumeClaim) {
|
if podVolumes != nil {
|
||||||
cache := env.internalBinder.podBindingCache
|
bindings = podVolumes.StaticBindings
|
||||||
bindings := cache.GetBindings(pod, node)
|
provisionedClaims = podVolumes.DynamicProvisions
|
||||||
|
}
|
||||||
if aLen, eLen := len(bindings), len(expectedBindings); aLen != eLen {
|
if aLen, eLen := len(bindings), len(expectedBindings); aLen != eLen {
|
||||||
t.Errorf("expected %v bindings, got %v", eLen, aLen)
|
t.Errorf("expected %v bindings, got %v", eLen, aLen)
|
||||||
} else if expectedBindings == nil && bindings != nil {
|
} else if expectedBindings == nil && bindings != nil {
|
||||||
@ -406,7 +409,6 @@ func (env *testEnv) validatePodCache(t *testing.T, node string, pod *v1.Pod, exp
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
provisionedClaims := cache.GetProvisionedPVCs(pod, node)
|
|
||||||
if aLen, eLen := len(provisionedClaims), len(expectedProvisionings); aLen != eLen {
|
if aLen, eLen := len(provisionedClaims), len(expectedProvisionings); aLen != eLen {
|
||||||
t.Errorf("expected %v provisioned claims, got %v", eLen, aLen)
|
t.Errorf("expected %v provisioned claims, got %v", eLen, aLen)
|
||||||
} else if expectedProvisionings == nil && provisionedClaims != nil {
|
} else if expectedProvisionings == nil && provisionedClaims != nil {
|
||||||
@ -424,12 +426,7 @@ func (env *testEnv) validatePodCache(t *testing.T, node string, pod *v1.Pod, exp
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (env *testEnv) getPodBindings(t *testing.T, node string, pod *v1.Pod) []*bindingInfo {
|
func (env *testEnv) validateAssume(t *testing.T, pod *v1.Pod, bindings []*BindingInfo, provisionings []*v1.PersistentVolumeClaim) {
|
||||||
cache := env.internalBinder.podBindingCache
|
|
||||||
return cache.GetBindings(pod, node)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (env *testEnv) validateAssume(t *testing.T, pod *v1.Pod, bindings []*bindingInfo, provisionings []*v1.PersistentVolumeClaim) {
|
|
||||||
// Check pv cache
|
// Check pv cache
|
||||||
pvCache := env.internalBinder.pvCache
|
pvCache := env.internalBinder.pvCache
|
||||||
for _, b := range bindings {
|
for _, b := range bindings {
|
||||||
@ -465,7 +462,7 @@ func (env *testEnv) validateAssume(t *testing.T, pod *v1.Pod, bindings []*bindin
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (env *testEnv) validateCacheRestored(t *testing.T, pod *v1.Pod, bindings []*bindingInfo, provisionings []*v1.PersistentVolumeClaim) {
|
func (env *testEnv) validateCacheRestored(t *testing.T, pod *v1.Pod, bindings []*BindingInfo, provisionings []*v1.PersistentVolumeClaim) {
|
||||||
// All PVs have been unmodified in cache
|
// All PVs have been unmodified in cache
|
||||||
pvCache := env.internalBinder.pvCache
|
pvCache := env.internalBinder.pvCache
|
||||||
for _, b := range bindings {
|
for _, b := range bindings {
|
||||||
@ -725,8 +722,8 @@ func makePodWithoutPVC() *v1.Pod {
|
|||||||
return pod
|
return pod
|
||||||
}
|
}
|
||||||
|
|
||||||
func makeBinding(pvc *v1.PersistentVolumeClaim, pv *v1.PersistentVolume) *bindingInfo {
|
func makeBinding(pvc *v1.PersistentVolumeClaim, pv *v1.PersistentVolume) *BindingInfo {
|
||||||
return &bindingInfo{pvc: pvc, pv: pv}
|
return &BindingInfo{pvc: pvc, pv: pv}
|
||||||
}
|
}
|
||||||
|
|
||||||
func addProvisionAnn(pvc *v1.PersistentVolumeClaim) *v1.PersistentVolumeClaim {
|
func addProvisionAnn(pvc *v1.PersistentVolumeClaim) *v1.PersistentVolumeClaim {
|
||||||
@ -773,13 +770,13 @@ func checkReasons(t *testing.T, actual, expected ConflictReasons) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// findPodVolumes gets and finds volumes for given pod and node
|
// findPodVolumes gets and finds volumes for given pod and node
|
||||||
func findPodVolumes(binder SchedulerVolumeBinder, pod *v1.Pod, node *v1.Node) (ConflictReasons, error) {
|
func findPodVolumes(binder SchedulerVolumeBinder, pod *v1.Pod, node *v1.Node) (*PodVolumes, ConflictReasons, error) {
|
||||||
boundClaims, claimsToBind, unboundClaimsImmediate, err := binder.GetPodVolumes(pod)
|
boundClaims, claimsToBind, unboundClaimsImmediate, err := binder.GetPodVolumes(pod)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
if len(unboundClaimsImmediate) > 0 {
|
if len(unboundClaimsImmediate) > 0 {
|
||||||
return nil, fmt.Errorf("pod has unbound immediate PersistentVolumeClaims")
|
return nil, nil, fmt.Errorf("pod has unbound immediate PersistentVolumeClaims")
|
||||||
}
|
}
|
||||||
return binder.FindPodVolumes(pod, boundClaims, claimsToBind, node)
|
return binder.FindPodVolumes(pod, boundClaims, claimsToBind, node)
|
||||||
}
|
}
|
||||||
@ -795,7 +792,7 @@ func TestFindPodVolumesWithoutProvisioning(t *testing.T) {
|
|||||||
pod *v1.Pod
|
pod *v1.Pod
|
||||||
|
|
||||||
// Expected podBindingCache fields
|
// Expected podBindingCache fields
|
||||||
expectedBindings []*bindingInfo
|
expectedBindings []*BindingInfo
|
||||||
|
|
||||||
// Expected return values
|
// Expected return values
|
||||||
reasons ConflictReasons
|
reasons ConflictReasons
|
||||||
@ -829,7 +826,7 @@ func TestFindPodVolumesWithoutProvisioning(t *testing.T) {
|
|||||||
"unbound-pvc,pv-same-node": {
|
"unbound-pvc,pv-same-node": {
|
||||||
podPVCs: []*v1.PersistentVolumeClaim{unboundPVC},
|
podPVCs: []*v1.PersistentVolumeClaim{unboundPVC},
|
||||||
pvs: []*v1.PersistentVolume{pvNode2, pvNode1a, pvNode1b},
|
pvs: []*v1.PersistentVolume{pvNode2, pvNode1a, pvNode1b},
|
||||||
expectedBindings: []*bindingInfo{makeBinding(unboundPVC, pvNode1a)},
|
expectedBindings: []*BindingInfo{makeBinding(unboundPVC, pvNode1a)},
|
||||||
},
|
},
|
||||||
"unbound-pvc,pv-different-node": {
|
"unbound-pvc,pv-different-node": {
|
||||||
podPVCs: []*v1.PersistentVolumeClaim{unboundPVC},
|
podPVCs: []*v1.PersistentVolumeClaim{unboundPVC},
|
||||||
@ -839,23 +836,23 @@ func TestFindPodVolumesWithoutProvisioning(t *testing.T) {
|
|||||||
"two-unbound-pvcs": {
|
"two-unbound-pvcs": {
|
||||||
podPVCs: []*v1.PersistentVolumeClaim{unboundPVC, unboundPVC2},
|
podPVCs: []*v1.PersistentVolumeClaim{unboundPVC, unboundPVC2},
|
||||||
pvs: []*v1.PersistentVolume{pvNode1a, pvNode1b},
|
pvs: []*v1.PersistentVolume{pvNode1a, pvNode1b},
|
||||||
expectedBindings: []*bindingInfo{makeBinding(unboundPVC, pvNode1a), makeBinding(unboundPVC2, pvNode1b)},
|
expectedBindings: []*BindingInfo{makeBinding(unboundPVC, pvNode1a), makeBinding(unboundPVC2, pvNode1b)},
|
||||||
},
|
},
|
||||||
"two-unbound-pvcs,order-by-size": {
|
"two-unbound-pvcs,order-by-size": {
|
||||||
podPVCs: []*v1.PersistentVolumeClaim{unboundPVC2, unboundPVC},
|
podPVCs: []*v1.PersistentVolumeClaim{unboundPVC2, unboundPVC},
|
||||||
pvs: []*v1.PersistentVolume{pvNode1a, pvNode1b},
|
pvs: []*v1.PersistentVolume{pvNode1a, pvNode1b},
|
||||||
expectedBindings: []*bindingInfo{makeBinding(unboundPVC, pvNode1a), makeBinding(unboundPVC2, pvNode1b)},
|
expectedBindings: []*BindingInfo{makeBinding(unboundPVC, pvNode1a), makeBinding(unboundPVC2, pvNode1b)},
|
||||||
},
|
},
|
||||||
"two-unbound-pvcs,partial-match": {
|
"two-unbound-pvcs,partial-match": {
|
||||||
podPVCs: []*v1.PersistentVolumeClaim{unboundPVC, unboundPVC2},
|
podPVCs: []*v1.PersistentVolumeClaim{unboundPVC, unboundPVC2},
|
||||||
pvs: []*v1.PersistentVolume{pvNode1a},
|
pvs: []*v1.PersistentVolume{pvNode1a},
|
||||||
expectedBindings: []*bindingInfo{makeBinding(unboundPVC, pvNode1a)},
|
expectedBindings: []*BindingInfo{makeBinding(unboundPVC, pvNode1a)},
|
||||||
reasons: ConflictReasons{ErrReasonBindConflict},
|
reasons: ConflictReasons{ErrReasonBindConflict},
|
||||||
},
|
},
|
||||||
"one-bound,one-unbound": {
|
"one-bound,one-unbound": {
|
||||||
podPVCs: []*v1.PersistentVolumeClaim{unboundPVC, boundPVC},
|
podPVCs: []*v1.PersistentVolumeClaim{unboundPVC, boundPVC},
|
||||||
pvs: []*v1.PersistentVolume{pvBound, pvNode1a},
|
pvs: []*v1.PersistentVolume{pvBound, pvNode1a},
|
||||||
expectedBindings: []*bindingInfo{makeBinding(unboundPVC, pvNode1a)},
|
expectedBindings: []*BindingInfo{makeBinding(unboundPVC, pvNode1a)},
|
||||||
},
|
},
|
||||||
"one-bound,one-unbound,no-match": {
|
"one-bound,one-unbound,no-match": {
|
||||||
podPVCs: []*v1.PersistentVolumeClaim{unboundPVC, boundPVC},
|
podPVCs: []*v1.PersistentVolumeClaim{unboundPVC, boundPVC},
|
||||||
@ -920,7 +917,7 @@ func TestFindPodVolumesWithoutProvisioning(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Execute
|
// Execute
|
||||||
reasons, err := findPodVolumes(testEnv.binder, scenario.pod, testNode)
|
podVolumes, reasons, err := findPodVolumes(testEnv.binder, scenario.pod, testNode)
|
||||||
|
|
||||||
// Validate
|
// Validate
|
||||||
if !scenario.shouldFail && err != nil {
|
if !scenario.shouldFail && err != nil {
|
||||||
@ -930,7 +927,7 @@ func TestFindPodVolumesWithoutProvisioning(t *testing.T) {
|
|||||||
t.Error("returned success but expected error")
|
t.Error("returned success but expected error")
|
||||||
}
|
}
|
||||||
checkReasons(t, reasons, scenario.reasons)
|
checkReasons(t, reasons, scenario.reasons)
|
||||||
testEnv.validatePodCache(t, testNode.Name, scenario.pod, scenario.expectedBindings, nil)
|
testEnv.validatePodCache(t, testNode.Name, scenario.pod, podVolumes, scenario.expectedBindings, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
for name, scenario := range scenarios {
|
for name, scenario := range scenarios {
|
||||||
@ -949,7 +946,7 @@ func TestFindPodVolumesWithProvisioning(t *testing.T) {
|
|||||||
pod *v1.Pod
|
pod *v1.Pod
|
||||||
|
|
||||||
// Expected podBindingCache fields
|
// Expected podBindingCache fields
|
||||||
expectedBindings []*bindingInfo
|
expectedBindings []*BindingInfo
|
||||||
expectedProvisions []*v1.PersistentVolumeClaim
|
expectedProvisions []*v1.PersistentVolumeClaim
|
||||||
|
|
||||||
// Expected return values
|
// Expected return values
|
||||||
@ -964,7 +961,7 @@ func TestFindPodVolumesWithProvisioning(t *testing.T) {
|
|||||||
"two-unbound-pvcs,one-matched,one-provisioned": {
|
"two-unbound-pvcs,one-matched,one-provisioned": {
|
||||||
podPVCs: []*v1.PersistentVolumeClaim{unboundPVC, provisionedPVC},
|
podPVCs: []*v1.PersistentVolumeClaim{unboundPVC, provisionedPVC},
|
||||||
pvs: []*v1.PersistentVolume{pvNode1a},
|
pvs: []*v1.PersistentVolume{pvNode1a},
|
||||||
expectedBindings: []*bindingInfo{makeBinding(unboundPVC, pvNode1a)},
|
expectedBindings: []*BindingInfo{makeBinding(unboundPVC, pvNode1a)},
|
||||||
expectedProvisions: []*v1.PersistentVolumeClaim{provisionedPVC},
|
expectedProvisions: []*v1.PersistentVolumeClaim{provisionedPVC},
|
||||||
},
|
},
|
||||||
"one-bound,one-provisioned": {
|
"one-bound,one-provisioned": {
|
||||||
@ -1025,7 +1022,7 @@ func TestFindPodVolumesWithProvisioning(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Execute
|
// Execute
|
||||||
reasons, err := findPodVolumes(testEnv.binder, scenario.pod, testNode)
|
podVolumes, reasons, err := findPodVolumes(testEnv.binder, scenario.pod, testNode)
|
||||||
|
|
||||||
// Validate
|
// Validate
|
||||||
if !scenario.shouldFail && err != nil {
|
if !scenario.shouldFail && err != nil {
|
||||||
@ -1035,7 +1032,7 @@ func TestFindPodVolumesWithProvisioning(t *testing.T) {
|
|||||||
t.Error("returned success but expected error")
|
t.Error("returned success but expected error")
|
||||||
}
|
}
|
||||||
checkReasons(t, reasons, scenario.reasons)
|
checkReasons(t, reasons, scenario.reasons)
|
||||||
testEnv.validatePodCache(t, testNode.Name, scenario.pod, scenario.expectedBindings, scenario.expectedProvisions)
|
testEnv.validatePodCache(t, testNode.Name, scenario.pod, podVolumes, scenario.expectedBindings, scenario.expectedProvisions)
|
||||||
}
|
}
|
||||||
|
|
||||||
for name, scenario := range scenarios {
|
for name, scenario := range scenarios {
|
||||||
@ -1125,7 +1122,7 @@ func TestFindPodVolumesWithCSIMigration(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Execute
|
// Execute
|
||||||
reasons, err := findPodVolumes(testEnv.binder, scenario.pod, node)
|
_, reasons, err := findPodVolumes(testEnv.binder, scenario.pod, node)
|
||||||
|
|
||||||
// Validate
|
// Validate
|
||||||
if !scenario.shouldFail && err != nil {
|
if !scenario.shouldFail && err != nil {
|
||||||
@ -1147,14 +1144,14 @@ func TestAssumePodVolumes(t *testing.T) {
|
|||||||
// Inputs
|
// Inputs
|
||||||
podPVCs []*v1.PersistentVolumeClaim
|
podPVCs []*v1.PersistentVolumeClaim
|
||||||
pvs []*v1.PersistentVolume
|
pvs []*v1.PersistentVolume
|
||||||
bindings []*bindingInfo
|
bindings []*BindingInfo
|
||||||
provisionedPVCs []*v1.PersistentVolumeClaim
|
provisionedPVCs []*v1.PersistentVolumeClaim
|
||||||
|
|
||||||
// Expected return values
|
// Expected return values
|
||||||
shouldFail bool
|
shouldFail bool
|
||||||
expectedAllBound bool
|
expectedAllBound bool
|
||||||
|
|
||||||
expectedBindings []*bindingInfo
|
expectedBindings []*BindingInfo
|
||||||
expectedProvisionings []*v1.PersistentVolumeClaim
|
expectedProvisionings []*v1.PersistentVolumeClaim
|
||||||
}
|
}
|
||||||
scenarios := map[string]scenarioType{
|
scenarios := map[string]scenarioType{
|
||||||
@ -1165,42 +1162,42 @@ func TestAssumePodVolumes(t *testing.T) {
|
|||||||
},
|
},
|
||||||
"one-binding": {
|
"one-binding": {
|
||||||
podPVCs: []*v1.PersistentVolumeClaim{unboundPVC},
|
podPVCs: []*v1.PersistentVolumeClaim{unboundPVC},
|
||||||
bindings: []*bindingInfo{makeBinding(unboundPVC, pvNode1a)},
|
bindings: []*BindingInfo{makeBinding(unboundPVC, pvNode1a)},
|
||||||
pvs: []*v1.PersistentVolume{pvNode1a},
|
pvs: []*v1.PersistentVolume{pvNode1a},
|
||||||
expectedBindings: []*bindingInfo{makeBinding(unboundPVC, pvNode1aBound)},
|
expectedBindings: []*BindingInfo{makeBinding(unboundPVC, pvNode1aBound)},
|
||||||
expectedProvisionings: []*v1.PersistentVolumeClaim{},
|
expectedProvisionings: []*v1.PersistentVolumeClaim{},
|
||||||
},
|
},
|
||||||
"two-bindings": {
|
"two-bindings": {
|
||||||
podPVCs: []*v1.PersistentVolumeClaim{unboundPVC, unboundPVC2},
|
podPVCs: []*v1.PersistentVolumeClaim{unboundPVC, unboundPVC2},
|
||||||
bindings: []*bindingInfo{makeBinding(unboundPVC, pvNode1a), makeBinding(unboundPVC2, pvNode1b)},
|
bindings: []*BindingInfo{makeBinding(unboundPVC, pvNode1a), makeBinding(unboundPVC2, pvNode1b)},
|
||||||
pvs: []*v1.PersistentVolume{pvNode1a, pvNode1b},
|
pvs: []*v1.PersistentVolume{pvNode1a, pvNode1b},
|
||||||
expectedBindings: []*bindingInfo{makeBinding(unboundPVC, pvNode1aBound), makeBinding(unboundPVC2, pvNode1bBound)},
|
expectedBindings: []*BindingInfo{makeBinding(unboundPVC, pvNode1aBound), makeBinding(unboundPVC2, pvNode1bBound)},
|
||||||
expectedProvisionings: []*v1.PersistentVolumeClaim{},
|
expectedProvisionings: []*v1.PersistentVolumeClaim{},
|
||||||
},
|
},
|
||||||
"pv-already-bound": {
|
"pv-already-bound": {
|
||||||
podPVCs: []*v1.PersistentVolumeClaim{unboundPVC},
|
podPVCs: []*v1.PersistentVolumeClaim{unboundPVC},
|
||||||
bindings: []*bindingInfo{makeBinding(unboundPVC, pvNode1aBound)},
|
bindings: []*BindingInfo{makeBinding(unboundPVC, pvNode1aBound)},
|
||||||
pvs: []*v1.PersistentVolume{pvNode1aBound},
|
pvs: []*v1.PersistentVolume{pvNode1aBound},
|
||||||
expectedBindings: []*bindingInfo{makeBinding(unboundPVC, pvNode1aBound)},
|
expectedBindings: []*BindingInfo{makeBinding(unboundPVC, pvNode1aBound)},
|
||||||
expectedProvisionings: []*v1.PersistentVolumeClaim{},
|
expectedProvisionings: []*v1.PersistentVolumeClaim{},
|
||||||
},
|
},
|
||||||
"tmpupdate-failed": {
|
"tmpupdate-failed": {
|
||||||
podPVCs: []*v1.PersistentVolumeClaim{unboundPVC},
|
podPVCs: []*v1.PersistentVolumeClaim{unboundPVC},
|
||||||
bindings: []*bindingInfo{makeBinding(unboundPVC, pvNode1a), makeBinding(unboundPVC2, pvNode1b)},
|
bindings: []*BindingInfo{makeBinding(unboundPVC, pvNode1a), makeBinding(unboundPVC2, pvNode1b)},
|
||||||
pvs: []*v1.PersistentVolume{pvNode1a},
|
pvs: []*v1.PersistentVolume{pvNode1a},
|
||||||
shouldFail: true,
|
shouldFail: true,
|
||||||
},
|
},
|
||||||
"one-binding, one-pvc-provisioned": {
|
"one-binding, one-pvc-provisioned": {
|
||||||
podPVCs: []*v1.PersistentVolumeClaim{unboundPVC, provisionedPVC},
|
podPVCs: []*v1.PersistentVolumeClaim{unboundPVC, provisionedPVC},
|
||||||
bindings: []*bindingInfo{makeBinding(unboundPVC, pvNode1a)},
|
bindings: []*BindingInfo{makeBinding(unboundPVC, pvNode1a)},
|
||||||
pvs: []*v1.PersistentVolume{pvNode1a},
|
pvs: []*v1.PersistentVolume{pvNode1a},
|
||||||
provisionedPVCs: []*v1.PersistentVolumeClaim{provisionedPVC},
|
provisionedPVCs: []*v1.PersistentVolumeClaim{provisionedPVC},
|
||||||
expectedBindings: []*bindingInfo{makeBinding(unboundPVC, pvNode1aBound)},
|
expectedBindings: []*BindingInfo{makeBinding(unboundPVC, pvNode1aBound)},
|
||||||
expectedProvisionings: []*v1.PersistentVolumeClaim{selectedNodePVC},
|
expectedProvisionings: []*v1.PersistentVolumeClaim{selectedNodePVC},
|
||||||
},
|
},
|
||||||
"one-binding, one-provision-tmpupdate-failed": {
|
"one-binding, one-provision-tmpupdate-failed": {
|
||||||
podPVCs: []*v1.PersistentVolumeClaim{unboundPVC, provisionedPVCHigherVersion},
|
podPVCs: []*v1.PersistentVolumeClaim{unboundPVC, provisionedPVCHigherVersion},
|
||||||
bindings: []*bindingInfo{makeBinding(unboundPVC, pvNode1a)},
|
bindings: []*BindingInfo{makeBinding(unboundPVC, pvNode1a)},
|
||||||
pvs: []*v1.PersistentVolume{pvNode1a},
|
pvs: []*v1.PersistentVolume{pvNode1a},
|
||||||
provisionedPVCs: []*v1.PersistentVolumeClaim{provisionedPVC2},
|
provisionedPVCs: []*v1.PersistentVolumeClaim{provisionedPVC2},
|
||||||
shouldFail: true,
|
shouldFail: true,
|
||||||
@ -1215,11 +1212,14 @@ func TestAssumePodVolumes(t *testing.T) {
|
|||||||
testEnv := newTestBinder(t, ctx.Done())
|
testEnv := newTestBinder(t, ctx.Done())
|
||||||
testEnv.initClaims(scenario.podPVCs, scenario.podPVCs)
|
testEnv.initClaims(scenario.podPVCs, scenario.podPVCs)
|
||||||
pod := makePod(scenario.podPVCs)
|
pod := makePod(scenario.podPVCs)
|
||||||
testEnv.initPodCache(pod, "node1", scenario.bindings, scenario.provisionedPVCs)
|
podVolumes := &PodVolumes{
|
||||||
|
StaticBindings: scenario.bindings,
|
||||||
|
DynamicProvisions: scenario.provisionedPVCs,
|
||||||
|
}
|
||||||
testEnv.initVolumes(scenario.pvs, scenario.pvs)
|
testEnv.initVolumes(scenario.pvs, scenario.pvs)
|
||||||
|
|
||||||
// Execute
|
// Execute
|
||||||
allBound, err := testEnv.binder.AssumePodVolumes(pod, "node1")
|
allBound, err := testEnv.binder.AssumePodVolumes(pod, "node1", podVolumes)
|
||||||
|
|
||||||
// Validate
|
// Validate
|
||||||
if !scenario.shouldFail && err != nil {
|
if !scenario.shouldFail && err != nil {
|
||||||
@ -1242,7 +1242,7 @@ func TestAssumePodVolumes(t *testing.T) {
|
|||||||
} else {
|
} else {
|
||||||
testEnv.validateAssume(t, pod, scenario.expectedBindings, scenario.expectedProvisionings)
|
testEnv.validateAssume(t, pod, scenario.expectedBindings, scenario.expectedProvisionings)
|
||||||
}
|
}
|
||||||
testEnv.validatePodCache(t, pod.Spec.NodeName, pod, scenario.expectedBindings, scenario.expectedProvisionings)
|
testEnv.validatePodCache(t, pod.Spec.NodeName, pod, podVolumes, scenario.expectedBindings, scenario.expectedProvisionings)
|
||||||
}
|
}
|
||||||
|
|
||||||
for name, scenario := range scenarios {
|
for name, scenario := range scenarios {
|
||||||
@ -1255,33 +1255,36 @@ func TestRevertAssumedPodVolumes(t *testing.T) {
|
|||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
podPVCs := []*v1.PersistentVolumeClaim{unboundPVC, provisionedPVC}
|
podPVCs := []*v1.PersistentVolumeClaim{unboundPVC, provisionedPVC}
|
||||||
bindings := []*bindingInfo{makeBinding(unboundPVC, pvNode1a)}
|
bindings := []*BindingInfo{makeBinding(unboundPVC, pvNode1a)}
|
||||||
pvs := []*v1.PersistentVolume{pvNode1a}
|
pvs := []*v1.PersistentVolume{pvNode1a}
|
||||||
provisionedPVCs := []*v1.PersistentVolumeClaim{provisionedPVC}
|
provisionedPVCs := []*v1.PersistentVolumeClaim{provisionedPVC}
|
||||||
expectedBindings := []*bindingInfo{makeBinding(unboundPVC, pvNode1aBound)}
|
expectedBindings := []*BindingInfo{makeBinding(unboundPVC, pvNode1aBound)}
|
||||||
expectedProvisionings := []*v1.PersistentVolumeClaim{selectedNodePVC}
|
expectedProvisionings := []*v1.PersistentVolumeClaim{selectedNodePVC}
|
||||||
|
|
||||||
// Setup
|
// Setup
|
||||||
testEnv := newTestBinder(t, ctx.Done())
|
testEnv := newTestBinder(t, ctx.Done())
|
||||||
testEnv.initClaims(podPVCs, podPVCs)
|
testEnv.initClaims(podPVCs, podPVCs)
|
||||||
pod := makePod(podPVCs)
|
pod := makePod(podPVCs)
|
||||||
testEnv.initPodCache(pod, "node1", bindings, provisionedPVCs)
|
podVolumes := &PodVolumes{
|
||||||
|
StaticBindings: bindings,
|
||||||
|
DynamicProvisions: provisionedPVCs,
|
||||||
|
}
|
||||||
testEnv.initVolumes(pvs, pvs)
|
testEnv.initVolumes(pvs, pvs)
|
||||||
|
|
||||||
allbound, err := testEnv.binder.AssumePodVolumes(pod, "node1")
|
allbound, err := testEnv.binder.AssumePodVolumes(pod, "node1", podVolumes)
|
||||||
if allbound || err != nil {
|
if allbound || err != nil {
|
||||||
t.Errorf("No volumes are assumed")
|
t.Errorf("No volumes are assumed")
|
||||||
}
|
}
|
||||||
testEnv.validateAssume(t, pod, expectedBindings, expectedProvisionings)
|
testEnv.validateAssume(t, pod, expectedBindings, expectedProvisionings)
|
||||||
|
|
||||||
testEnv.binder.RevertAssumedPodVolumes(pod, "node1")
|
testEnv.binder.RevertAssumedPodVolumes(podVolumes)
|
||||||
testEnv.validateCacheRestored(t, pod, bindings, provisionedPVCs)
|
testEnv.validateCacheRestored(t, pod, bindings, provisionedPVCs)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestBindAPIUpdate(t *testing.T) {
|
func TestBindAPIUpdate(t *testing.T) {
|
||||||
type scenarioType struct {
|
type scenarioType struct {
|
||||||
// Inputs
|
// Inputs
|
||||||
bindings []*bindingInfo
|
bindings []*BindingInfo
|
||||||
cachedPVs []*v1.PersistentVolume
|
cachedPVs []*v1.PersistentVolume
|
||||||
// if nil, use cachedPVs
|
// if nil, use cachedPVs
|
||||||
apiPVs []*v1.PersistentVolume
|
apiPVs []*v1.PersistentVolume
|
||||||
@ -1310,33 +1313,33 @@ func TestBindAPIUpdate(t *testing.T) {
|
|||||||
shouldFail: true,
|
shouldFail: true,
|
||||||
},
|
},
|
||||||
"nothing-to-bind-provisionings-nil": {
|
"nothing-to-bind-provisionings-nil": {
|
||||||
bindings: []*bindingInfo{},
|
bindings: []*BindingInfo{},
|
||||||
shouldFail: true,
|
shouldFail: true,
|
||||||
},
|
},
|
||||||
"nothing-to-bind-empty": {
|
"nothing-to-bind-empty": {
|
||||||
bindings: []*bindingInfo{},
|
bindings: []*BindingInfo{},
|
||||||
provisionedPVCs: []*v1.PersistentVolumeClaim{},
|
provisionedPVCs: []*v1.PersistentVolumeClaim{},
|
||||||
},
|
},
|
||||||
"one-binding": {
|
"one-binding": {
|
||||||
bindings: []*bindingInfo{makeBinding(unboundPVC, pvNode1aBound)},
|
bindings: []*BindingInfo{makeBinding(unboundPVC, pvNode1aBound)},
|
||||||
cachedPVs: []*v1.PersistentVolume{pvNode1a},
|
cachedPVs: []*v1.PersistentVolume{pvNode1a},
|
||||||
expectedPVs: []*v1.PersistentVolume{pvNode1aBound},
|
expectedPVs: []*v1.PersistentVolume{pvNode1aBound},
|
||||||
provisionedPVCs: []*v1.PersistentVolumeClaim{},
|
provisionedPVCs: []*v1.PersistentVolumeClaim{},
|
||||||
},
|
},
|
||||||
"two-bindings": {
|
"two-bindings": {
|
||||||
bindings: []*bindingInfo{makeBinding(unboundPVC, pvNode1aBound), makeBinding(unboundPVC2, pvNode1bBound)},
|
bindings: []*BindingInfo{makeBinding(unboundPVC, pvNode1aBound), makeBinding(unboundPVC2, pvNode1bBound)},
|
||||||
cachedPVs: []*v1.PersistentVolume{pvNode1a, pvNode1b},
|
cachedPVs: []*v1.PersistentVolume{pvNode1a, pvNode1b},
|
||||||
expectedPVs: []*v1.PersistentVolume{pvNode1aBound, pvNode1bBound},
|
expectedPVs: []*v1.PersistentVolume{pvNode1aBound, pvNode1bBound},
|
||||||
provisionedPVCs: []*v1.PersistentVolumeClaim{},
|
provisionedPVCs: []*v1.PersistentVolumeClaim{},
|
||||||
},
|
},
|
||||||
"api-already-updated": {
|
"api-already-updated": {
|
||||||
bindings: []*bindingInfo{makeBinding(unboundPVC, pvNode1aBound)},
|
bindings: []*BindingInfo{makeBinding(unboundPVC, pvNode1aBound)},
|
||||||
cachedPVs: []*v1.PersistentVolume{pvNode1aBound},
|
cachedPVs: []*v1.PersistentVolume{pvNode1aBound},
|
||||||
expectedPVs: []*v1.PersistentVolume{pvNode1aBound},
|
expectedPVs: []*v1.PersistentVolume{pvNode1aBound},
|
||||||
provisionedPVCs: []*v1.PersistentVolumeClaim{},
|
provisionedPVCs: []*v1.PersistentVolumeClaim{},
|
||||||
},
|
},
|
||||||
"api-update-failed": {
|
"api-update-failed": {
|
||||||
bindings: []*bindingInfo{makeBinding(unboundPVC, pvNode1aBound), makeBinding(unboundPVC2, pvNode1bBound)},
|
bindings: []*BindingInfo{makeBinding(unboundPVC, pvNode1aBound), makeBinding(unboundPVC2, pvNode1bBound)},
|
||||||
cachedPVs: []*v1.PersistentVolume{pvNode1a, pvNode1b},
|
cachedPVs: []*v1.PersistentVolume{pvNode1a, pvNode1b},
|
||||||
apiPVs: []*v1.PersistentVolume{pvNode1a, pvNode1bBoundHigherVersion},
|
apiPVs: []*v1.PersistentVolume{pvNode1a, pvNode1bBoundHigherVersion},
|
||||||
expectedPVs: []*v1.PersistentVolume{pvNode1aBound, pvNode1b},
|
expectedPVs: []*v1.PersistentVolume{pvNode1aBound, pvNode1b},
|
||||||
@ -1345,13 +1348,13 @@ func TestBindAPIUpdate(t *testing.T) {
|
|||||||
shouldFail: true,
|
shouldFail: true,
|
||||||
},
|
},
|
||||||
"one-provisioned-pvc": {
|
"one-provisioned-pvc": {
|
||||||
bindings: []*bindingInfo{},
|
bindings: []*BindingInfo{},
|
||||||
provisionedPVCs: []*v1.PersistentVolumeClaim{addProvisionAnn(provisionedPVC)},
|
provisionedPVCs: []*v1.PersistentVolumeClaim{addProvisionAnn(provisionedPVC)},
|
||||||
cachedPVCs: []*v1.PersistentVolumeClaim{provisionedPVC},
|
cachedPVCs: []*v1.PersistentVolumeClaim{provisionedPVC},
|
||||||
expectedPVCs: []*v1.PersistentVolumeClaim{addProvisionAnn(provisionedPVC)},
|
expectedPVCs: []*v1.PersistentVolumeClaim{addProvisionAnn(provisionedPVC)},
|
||||||
},
|
},
|
||||||
"provision-api-update-failed": {
|
"provision-api-update-failed": {
|
||||||
bindings: []*bindingInfo{},
|
bindings: []*BindingInfo{},
|
||||||
provisionedPVCs: []*v1.PersistentVolumeClaim{addProvisionAnn(provisionedPVC), addProvisionAnn(provisionedPVC2)},
|
provisionedPVCs: []*v1.PersistentVolumeClaim{addProvisionAnn(provisionedPVC), addProvisionAnn(provisionedPVC2)},
|
||||||
cachedPVCs: []*v1.PersistentVolumeClaim{provisionedPVC, provisionedPVC2},
|
cachedPVCs: []*v1.PersistentVolumeClaim{provisionedPVC, provisionedPVC2},
|
||||||
apiPVCs: []*v1.PersistentVolumeClaim{provisionedPVC, provisionedPVCHigherVersion},
|
apiPVCs: []*v1.PersistentVolumeClaim{provisionedPVC, provisionedPVCHigherVersion},
|
||||||
@ -1360,7 +1363,7 @@ func TestBindAPIUpdate(t *testing.T) {
|
|||||||
shouldFail: true,
|
shouldFail: true,
|
||||||
},
|
},
|
||||||
"binding-succeed, provision-api-update-failed": {
|
"binding-succeed, provision-api-update-failed": {
|
||||||
bindings: []*bindingInfo{makeBinding(unboundPVC, pvNode1aBound)},
|
bindings: []*BindingInfo{makeBinding(unboundPVC, pvNode1aBound)},
|
||||||
cachedPVs: []*v1.PersistentVolume{pvNode1a},
|
cachedPVs: []*v1.PersistentVolume{pvNode1a},
|
||||||
expectedPVs: []*v1.PersistentVolume{pvNode1aBound},
|
expectedPVs: []*v1.PersistentVolume{pvNode1aBound},
|
||||||
provisionedPVCs: []*v1.PersistentVolumeClaim{addProvisionAnn(provisionedPVC), addProvisionAnn(provisionedPVC2)},
|
provisionedPVCs: []*v1.PersistentVolumeClaim{addProvisionAnn(provisionedPVC), addProvisionAnn(provisionedPVC2)},
|
||||||
@ -1420,7 +1423,7 @@ func TestCheckBindings(t *testing.T) {
|
|||||||
initPVs []*v1.PersistentVolume
|
initPVs []*v1.PersistentVolume
|
||||||
initPVCs []*v1.PersistentVolumeClaim
|
initPVCs []*v1.PersistentVolumeClaim
|
||||||
|
|
||||||
bindings []*bindingInfo
|
bindings []*BindingInfo
|
||||||
provisionedPVCs []*v1.PersistentVolumeClaim
|
provisionedPVCs []*v1.PersistentVolumeClaim
|
||||||
|
|
||||||
// api updates before checking
|
// api updates before checking
|
||||||
@ -1444,41 +1447,41 @@ func TestCheckBindings(t *testing.T) {
|
|||||||
shouldFail: true,
|
shouldFail: true,
|
||||||
},
|
},
|
||||||
"nothing-to-bind-provisionings-nil": {
|
"nothing-to-bind-provisionings-nil": {
|
||||||
bindings: []*bindingInfo{},
|
bindings: []*BindingInfo{},
|
||||||
shouldFail: true,
|
shouldFail: true,
|
||||||
},
|
},
|
||||||
"nothing-to-bind": {
|
"nothing-to-bind": {
|
||||||
bindings: []*bindingInfo{},
|
bindings: []*BindingInfo{},
|
||||||
provisionedPVCs: []*v1.PersistentVolumeClaim{},
|
provisionedPVCs: []*v1.PersistentVolumeClaim{},
|
||||||
expectedBound: true,
|
expectedBound: true,
|
||||||
},
|
},
|
||||||
"binding-bound": {
|
"binding-bound": {
|
||||||
bindings: []*bindingInfo{makeBinding(unboundPVC, pvNode1aBound)},
|
bindings: []*BindingInfo{makeBinding(unboundPVC, pvNode1aBound)},
|
||||||
provisionedPVCs: []*v1.PersistentVolumeClaim{},
|
provisionedPVCs: []*v1.PersistentVolumeClaim{},
|
||||||
initPVs: []*v1.PersistentVolume{pvNode1aBound},
|
initPVs: []*v1.PersistentVolume{pvNode1aBound},
|
||||||
initPVCs: []*v1.PersistentVolumeClaim{boundPVCNode1a},
|
initPVCs: []*v1.PersistentVolumeClaim{boundPVCNode1a},
|
||||||
expectedBound: true,
|
expectedBound: true,
|
||||||
},
|
},
|
||||||
"binding-prebound": {
|
"binding-prebound": {
|
||||||
bindings: []*bindingInfo{makeBinding(unboundPVC, pvNode1aBound)},
|
bindings: []*BindingInfo{makeBinding(unboundPVC, pvNode1aBound)},
|
||||||
provisionedPVCs: []*v1.PersistentVolumeClaim{},
|
provisionedPVCs: []*v1.PersistentVolumeClaim{},
|
||||||
initPVs: []*v1.PersistentVolume{pvNode1aBound},
|
initPVs: []*v1.PersistentVolume{pvNode1aBound},
|
||||||
initPVCs: []*v1.PersistentVolumeClaim{preboundPVCNode1a},
|
initPVCs: []*v1.PersistentVolumeClaim{preboundPVCNode1a},
|
||||||
},
|
},
|
||||||
"binding-unbound": {
|
"binding-unbound": {
|
||||||
bindings: []*bindingInfo{makeBinding(unboundPVC, pvNode1aBound)},
|
bindings: []*BindingInfo{makeBinding(unboundPVC, pvNode1aBound)},
|
||||||
provisionedPVCs: []*v1.PersistentVolumeClaim{},
|
provisionedPVCs: []*v1.PersistentVolumeClaim{},
|
||||||
initPVs: []*v1.PersistentVolume{pvNode1aBound},
|
initPVs: []*v1.PersistentVolume{pvNode1aBound},
|
||||||
initPVCs: []*v1.PersistentVolumeClaim{unboundPVC},
|
initPVCs: []*v1.PersistentVolumeClaim{unboundPVC},
|
||||||
},
|
},
|
||||||
"binding-pvc-not-exists": {
|
"binding-pvc-not-exists": {
|
||||||
bindings: []*bindingInfo{makeBinding(unboundPVC, pvNode1aBound)},
|
bindings: []*BindingInfo{makeBinding(unboundPVC, pvNode1aBound)},
|
||||||
provisionedPVCs: []*v1.PersistentVolumeClaim{},
|
provisionedPVCs: []*v1.PersistentVolumeClaim{},
|
||||||
initPVs: []*v1.PersistentVolume{pvNode1aBound},
|
initPVs: []*v1.PersistentVolume{pvNode1aBound},
|
||||||
shouldFail: true,
|
shouldFail: true,
|
||||||
},
|
},
|
||||||
"binding-pv-not-exists": {
|
"binding-pv-not-exists": {
|
||||||
bindings: []*bindingInfo{makeBinding(unboundPVC, pvNode1aBound)},
|
bindings: []*BindingInfo{makeBinding(unboundPVC, pvNode1aBound)},
|
||||||
provisionedPVCs: []*v1.PersistentVolumeClaim{},
|
provisionedPVCs: []*v1.PersistentVolumeClaim{},
|
||||||
initPVs: []*v1.PersistentVolume{pvNode1aBound},
|
initPVs: []*v1.PersistentVolume{pvNode1aBound},
|
||||||
initPVCs: []*v1.PersistentVolumeClaim{boundPVCNode1a},
|
initPVCs: []*v1.PersistentVolumeClaim{boundPVCNode1a},
|
||||||
@ -1486,7 +1489,7 @@ func TestCheckBindings(t *testing.T) {
|
|||||||
shouldFail: true,
|
shouldFail: true,
|
||||||
},
|
},
|
||||||
"binding-claimref-nil": {
|
"binding-claimref-nil": {
|
||||||
bindings: []*bindingInfo{makeBinding(unboundPVC, pvNode1aBound)},
|
bindings: []*BindingInfo{makeBinding(unboundPVC, pvNode1aBound)},
|
||||||
provisionedPVCs: []*v1.PersistentVolumeClaim{},
|
provisionedPVCs: []*v1.PersistentVolumeClaim{},
|
||||||
initPVs: []*v1.PersistentVolume{pvNode1a},
|
initPVs: []*v1.PersistentVolume{pvNode1a},
|
||||||
initPVCs: []*v1.PersistentVolumeClaim{boundPVCNode1a},
|
initPVCs: []*v1.PersistentVolumeClaim{boundPVCNode1a},
|
||||||
@ -1495,7 +1498,7 @@ func TestCheckBindings(t *testing.T) {
|
|||||||
shouldFail: true,
|
shouldFail: true,
|
||||||
},
|
},
|
||||||
"binding-claimref-uid-empty": {
|
"binding-claimref-uid-empty": {
|
||||||
bindings: []*bindingInfo{makeBinding(unboundPVC, pvNode1aBound)},
|
bindings: []*BindingInfo{makeBinding(unboundPVC, pvNode1aBound)},
|
||||||
provisionedPVCs: []*v1.PersistentVolumeClaim{},
|
provisionedPVCs: []*v1.PersistentVolumeClaim{},
|
||||||
initPVs: []*v1.PersistentVolume{pvNode1aBound},
|
initPVs: []*v1.PersistentVolume{pvNode1aBound},
|
||||||
initPVCs: []*v1.PersistentVolumeClaim{boundPVCNode1a},
|
initPVCs: []*v1.PersistentVolumeClaim{boundPVCNode1a},
|
||||||
@ -1504,13 +1507,13 @@ func TestCheckBindings(t *testing.T) {
|
|||||||
shouldFail: true,
|
shouldFail: true,
|
||||||
},
|
},
|
||||||
"binding-one-bound,one-unbound": {
|
"binding-one-bound,one-unbound": {
|
||||||
bindings: []*bindingInfo{makeBinding(unboundPVC, pvNode1aBound), makeBinding(unboundPVC2, pvNode1bBound)},
|
bindings: []*BindingInfo{makeBinding(unboundPVC, pvNode1aBound), makeBinding(unboundPVC2, pvNode1bBound)},
|
||||||
provisionedPVCs: []*v1.PersistentVolumeClaim{},
|
provisionedPVCs: []*v1.PersistentVolumeClaim{},
|
||||||
initPVs: []*v1.PersistentVolume{pvNode1aBound, pvNode1bBound},
|
initPVs: []*v1.PersistentVolume{pvNode1aBound, pvNode1bBound},
|
||||||
initPVCs: []*v1.PersistentVolumeClaim{boundPVCNode1a, unboundPVC2},
|
initPVCs: []*v1.PersistentVolumeClaim{boundPVCNode1a, unboundPVC2},
|
||||||
},
|
},
|
||||||
"provisioning-pvc-bound": {
|
"provisioning-pvc-bound": {
|
||||||
bindings: []*bindingInfo{},
|
bindings: []*BindingInfo{},
|
||||||
provisionedPVCs: []*v1.PersistentVolumeClaim{addProvisionAnn(provisionedPVC)},
|
provisionedPVCs: []*v1.PersistentVolumeClaim{addProvisionAnn(provisionedPVC)},
|
||||||
initPVs: []*v1.PersistentVolume{pvBound},
|
initPVs: []*v1.PersistentVolume{pvBound},
|
||||||
initPVCs: []*v1.PersistentVolumeClaim{provisionedPVCBound},
|
initPVCs: []*v1.PersistentVolumeClaim{provisionedPVCBound},
|
||||||
@ -1518,26 +1521,26 @@ func TestCheckBindings(t *testing.T) {
|
|||||||
expectedBound: true,
|
expectedBound: true,
|
||||||
},
|
},
|
||||||
"provisioning-pvc-unbound": {
|
"provisioning-pvc-unbound": {
|
||||||
bindings: []*bindingInfo{},
|
bindings: []*BindingInfo{},
|
||||||
provisionedPVCs: []*v1.PersistentVolumeClaim{addProvisionAnn(provisionedPVC)},
|
provisionedPVCs: []*v1.PersistentVolumeClaim{addProvisionAnn(provisionedPVC)},
|
||||||
initPVCs: []*v1.PersistentVolumeClaim{addProvisionAnn(provisionedPVC)},
|
initPVCs: []*v1.PersistentVolumeClaim{addProvisionAnn(provisionedPVC)},
|
||||||
},
|
},
|
||||||
"provisioning-pvc-not-exists": {
|
"provisioning-pvc-not-exists": {
|
||||||
bindings: []*bindingInfo{},
|
bindings: []*BindingInfo{},
|
||||||
provisionedPVCs: []*v1.PersistentVolumeClaim{addProvisionAnn(provisionedPVC)},
|
provisionedPVCs: []*v1.PersistentVolumeClaim{addProvisionAnn(provisionedPVC)},
|
||||||
initPVCs: []*v1.PersistentVolumeClaim{provisionedPVC},
|
initPVCs: []*v1.PersistentVolumeClaim{provisionedPVC},
|
||||||
deletePVCs: true,
|
deletePVCs: true,
|
||||||
shouldFail: true,
|
shouldFail: true,
|
||||||
},
|
},
|
||||||
"provisioning-pvc-annotations-nil": {
|
"provisioning-pvc-annotations-nil": {
|
||||||
bindings: []*bindingInfo{},
|
bindings: []*BindingInfo{},
|
||||||
provisionedPVCs: []*v1.PersistentVolumeClaim{addProvisionAnn(provisionedPVC)},
|
provisionedPVCs: []*v1.PersistentVolumeClaim{addProvisionAnn(provisionedPVC)},
|
||||||
initPVCs: []*v1.PersistentVolumeClaim{provisionedPVC},
|
initPVCs: []*v1.PersistentVolumeClaim{provisionedPVC},
|
||||||
apiPVCs: []*v1.PersistentVolumeClaim{provisionedPVC},
|
apiPVCs: []*v1.PersistentVolumeClaim{provisionedPVC},
|
||||||
shouldFail: true,
|
shouldFail: true,
|
||||||
},
|
},
|
||||||
"provisioning-pvc-selected-node-dropped": {
|
"provisioning-pvc-selected-node-dropped": {
|
||||||
bindings: []*bindingInfo{},
|
bindings: []*BindingInfo{},
|
||||||
provisionedPVCs: []*v1.PersistentVolumeClaim{addProvisionAnn(provisionedPVC)},
|
provisionedPVCs: []*v1.PersistentVolumeClaim{addProvisionAnn(provisionedPVC)},
|
||||||
initPVCs: []*v1.PersistentVolumeClaim{provisionedPVC},
|
initPVCs: []*v1.PersistentVolumeClaim{provisionedPVC},
|
||||||
apiPVCs: []*v1.PersistentVolumeClaim{pvcSetEmptyAnnotations(provisionedPVC)},
|
apiPVCs: []*v1.PersistentVolumeClaim{pvcSetEmptyAnnotations(provisionedPVC)},
|
||||||
@ -1545,13 +1548,13 @@ func TestCheckBindings(t *testing.T) {
|
|||||||
},
|
},
|
||||||
"provisioning-pvc-selected-node-wrong-node": {
|
"provisioning-pvc-selected-node-wrong-node": {
|
||||||
initPVCs: []*v1.PersistentVolumeClaim{provisionedPVC},
|
initPVCs: []*v1.PersistentVolumeClaim{provisionedPVC},
|
||||||
bindings: []*bindingInfo{},
|
bindings: []*BindingInfo{},
|
||||||
provisionedPVCs: []*v1.PersistentVolumeClaim{addProvisionAnn(provisionedPVC)},
|
provisionedPVCs: []*v1.PersistentVolumeClaim{addProvisionAnn(provisionedPVC)},
|
||||||
apiPVCs: []*v1.PersistentVolumeClaim{pvcSetSelectedNode(provisionedPVC, "wrong-node")},
|
apiPVCs: []*v1.PersistentVolumeClaim{pvcSetSelectedNode(provisionedPVC, "wrong-node")},
|
||||||
shouldFail: true,
|
shouldFail: true,
|
||||||
},
|
},
|
||||||
"binding-bound-provisioning-unbound": {
|
"binding-bound-provisioning-unbound": {
|
||||||
bindings: []*bindingInfo{makeBinding(unboundPVC, pvNode1aBound)},
|
bindings: []*BindingInfo{makeBinding(unboundPVC, pvNode1aBound)},
|
||||||
provisionedPVCs: []*v1.PersistentVolumeClaim{addProvisionAnn(provisionedPVC)},
|
provisionedPVCs: []*v1.PersistentVolumeClaim{addProvisionAnn(provisionedPVC)},
|
||||||
initPVs: []*v1.PersistentVolume{pvNode1aBound},
|
initPVs: []*v1.PersistentVolume{pvNode1aBound},
|
||||||
initPVCs: []*v1.PersistentVolumeClaim{boundPVCNode1a, addProvisionAnn(provisionedPVC)},
|
initPVCs: []*v1.PersistentVolumeClaim{boundPVCNode1a, addProvisionAnn(provisionedPVC)},
|
||||||
@ -1559,7 +1562,7 @@ func TestCheckBindings(t *testing.T) {
|
|||||||
"tolerate-provisioning-pvc-bound-pv-not-found": {
|
"tolerate-provisioning-pvc-bound-pv-not-found": {
|
||||||
initPVs: []*v1.PersistentVolume{pvNode1a},
|
initPVs: []*v1.PersistentVolume{pvNode1a},
|
||||||
initPVCs: []*v1.PersistentVolumeClaim{provisionedPVC},
|
initPVCs: []*v1.PersistentVolumeClaim{provisionedPVC},
|
||||||
bindings: []*bindingInfo{},
|
bindings: []*BindingInfo{},
|
||||||
provisionedPVCs: []*v1.PersistentVolumeClaim{addProvisionAnn(provisionedPVC)},
|
provisionedPVCs: []*v1.PersistentVolumeClaim{addProvisionAnn(provisionedPVC)},
|
||||||
apiPVCs: []*v1.PersistentVolumeClaim{addProvisionAnn(provisionedPVCBound)},
|
apiPVCs: []*v1.PersistentVolumeClaim{addProvisionAnn(provisionedPVCBound)},
|
||||||
deletePVs: true,
|
deletePVs: true,
|
||||||
@ -1573,6 +1576,7 @@ func TestCheckBindings(t *testing.T) {
|
|||||||
// Setup
|
// Setup
|
||||||
pod := makePod(nil)
|
pod := makePod(nil)
|
||||||
testEnv := newTestBinder(t, ctx.Done())
|
testEnv := newTestBinder(t, ctx.Done())
|
||||||
|
testEnv.internalPodInformer.Informer().GetIndexer().Add(pod)
|
||||||
testEnv.initNodes([]*v1.Node{node1})
|
testEnv.initNodes([]*v1.Node{node1})
|
||||||
testEnv.initVolumes(scenario.initPVs, nil)
|
testEnv.initVolumes(scenario.initPVs, nil)
|
||||||
testEnv.initClaims(scenario.initPVCs, nil)
|
testEnv.initClaims(scenario.initPVCs, nil)
|
||||||
@ -1618,7 +1622,7 @@ func TestCheckBindingsWithCSIMigration(t *testing.T) {
|
|||||||
initNodes []*v1.Node
|
initNodes []*v1.Node
|
||||||
initCSINodes []*storagev1.CSINode
|
initCSINodes []*storagev1.CSINode
|
||||||
|
|
||||||
bindings []*bindingInfo
|
bindings []*BindingInfo
|
||||||
provisionedPVCs []*v1.PersistentVolumeClaim
|
provisionedPVCs []*v1.PersistentVolumeClaim
|
||||||
|
|
||||||
// API updates before checking
|
// API updates before checking
|
||||||
@ -1632,7 +1636,7 @@ func TestCheckBindingsWithCSIMigration(t *testing.T) {
|
|||||||
}
|
}
|
||||||
scenarios := map[string]scenarioType{
|
scenarios := map[string]scenarioType{
|
||||||
"provisioning-pvc-bound": {
|
"provisioning-pvc-bound": {
|
||||||
bindings: []*bindingInfo{},
|
bindings: []*BindingInfo{},
|
||||||
provisionedPVCs: []*v1.PersistentVolumeClaim{addProvisionAnn(provMigrationPVCBound)},
|
provisionedPVCs: []*v1.PersistentVolumeClaim{addProvisionAnn(provMigrationPVCBound)},
|
||||||
initPVs: []*v1.PersistentVolume{migrationPVBound},
|
initPVs: []*v1.PersistentVolume{migrationPVBound},
|
||||||
initPVCs: []*v1.PersistentVolumeClaim{provMigrationPVCBound},
|
initPVCs: []*v1.PersistentVolumeClaim{provMigrationPVCBound},
|
||||||
@ -1642,7 +1646,7 @@ func TestCheckBindingsWithCSIMigration(t *testing.T) {
|
|||||||
expectedBound: true,
|
expectedBound: true,
|
||||||
},
|
},
|
||||||
"binding-node-pv-same-zone": {
|
"binding-node-pv-same-zone": {
|
||||||
bindings: []*bindingInfo{makeBinding(unboundPVC, migrationPVBoundToUnbound)},
|
bindings: []*BindingInfo{makeBinding(unboundPVC, migrationPVBoundToUnbound)},
|
||||||
provisionedPVCs: []*v1.PersistentVolumeClaim{},
|
provisionedPVCs: []*v1.PersistentVolumeClaim{},
|
||||||
initPVs: []*v1.PersistentVolume{migrationPVBoundToUnbound},
|
initPVs: []*v1.PersistentVolume{migrationPVBoundToUnbound},
|
||||||
initPVCs: []*v1.PersistentVolumeClaim{unboundPVC},
|
initPVCs: []*v1.PersistentVolumeClaim{unboundPVC},
|
||||||
@ -1651,7 +1655,7 @@ func TestCheckBindingsWithCSIMigration(t *testing.T) {
|
|||||||
migrationEnabled: true,
|
migrationEnabled: true,
|
||||||
},
|
},
|
||||||
"binding-without-csinode": {
|
"binding-without-csinode": {
|
||||||
bindings: []*bindingInfo{makeBinding(unboundPVC, migrationPVBoundToUnbound)},
|
bindings: []*BindingInfo{makeBinding(unboundPVC, migrationPVBoundToUnbound)},
|
||||||
provisionedPVCs: []*v1.PersistentVolumeClaim{},
|
provisionedPVCs: []*v1.PersistentVolumeClaim{},
|
||||||
initPVs: []*v1.PersistentVolume{migrationPVBoundToUnbound},
|
initPVs: []*v1.PersistentVolume{migrationPVBoundToUnbound},
|
||||||
initPVCs: []*v1.PersistentVolumeClaim{unboundPVC},
|
initPVCs: []*v1.PersistentVolumeClaim{unboundPVC},
|
||||||
@ -1660,7 +1664,7 @@ func TestCheckBindingsWithCSIMigration(t *testing.T) {
|
|||||||
migrationEnabled: true,
|
migrationEnabled: true,
|
||||||
},
|
},
|
||||||
"binding-non-migrated-plugin": {
|
"binding-non-migrated-plugin": {
|
||||||
bindings: []*bindingInfo{makeBinding(unboundPVC, migrationPVBoundToUnbound)},
|
bindings: []*BindingInfo{makeBinding(unboundPVC, migrationPVBoundToUnbound)},
|
||||||
provisionedPVCs: []*v1.PersistentVolumeClaim{},
|
provisionedPVCs: []*v1.PersistentVolumeClaim{},
|
||||||
initPVs: []*v1.PersistentVolume{migrationPVBoundToUnbound},
|
initPVs: []*v1.PersistentVolume{migrationPVBoundToUnbound},
|
||||||
initPVCs: []*v1.PersistentVolumeClaim{unboundPVC},
|
initPVCs: []*v1.PersistentVolumeClaim{unboundPVC},
|
||||||
@ -1669,7 +1673,7 @@ func TestCheckBindingsWithCSIMigration(t *testing.T) {
|
|||||||
migrationEnabled: true,
|
migrationEnabled: true,
|
||||||
},
|
},
|
||||||
"binding-node-pv-in-different-zones": {
|
"binding-node-pv-in-different-zones": {
|
||||||
bindings: []*bindingInfo{makeBinding(unboundPVC, migrationPVBoundToUnbound)},
|
bindings: []*BindingInfo{makeBinding(unboundPVC, migrationPVBoundToUnbound)},
|
||||||
provisionedPVCs: []*v1.PersistentVolumeClaim{},
|
provisionedPVCs: []*v1.PersistentVolumeClaim{},
|
||||||
initPVs: []*v1.PersistentVolume{migrationPVBoundToUnbound},
|
initPVs: []*v1.PersistentVolume{migrationPVBoundToUnbound},
|
||||||
initPVCs: []*v1.PersistentVolumeClaim{unboundPVC},
|
initPVCs: []*v1.PersistentVolumeClaim{unboundPVC},
|
||||||
@ -1679,7 +1683,7 @@ func TestCheckBindingsWithCSIMigration(t *testing.T) {
|
|||||||
shouldFail: true,
|
shouldFail: true,
|
||||||
},
|
},
|
||||||
"binding-node-pv-different-zones-migration-off": {
|
"binding-node-pv-different-zones-migration-off": {
|
||||||
bindings: []*bindingInfo{makeBinding(unboundPVC, migrationPVBoundToUnbound)},
|
bindings: []*BindingInfo{makeBinding(unboundPVC, migrationPVBoundToUnbound)},
|
||||||
provisionedPVCs: []*v1.PersistentVolumeClaim{},
|
provisionedPVCs: []*v1.PersistentVolumeClaim{},
|
||||||
initPVs: []*v1.PersistentVolume{migrationPVBoundToUnbound},
|
initPVs: []*v1.PersistentVolume{migrationPVBoundToUnbound},
|
||||||
initPVCs: []*v1.PersistentVolumeClaim{unboundPVC},
|
initPVCs: []*v1.PersistentVolumeClaim{unboundPVC},
|
||||||
@ -1699,6 +1703,7 @@ func TestCheckBindingsWithCSIMigration(t *testing.T) {
|
|||||||
// Setup
|
// Setup
|
||||||
pod := makePod(nil)
|
pod := makePod(nil)
|
||||||
testEnv := newTestBinder(t, ctx.Done())
|
testEnv := newTestBinder(t, ctx.Done())
|
||||||
|
testEnv.internalPodInformer.Informer().GetIndexer().Add(pod)
|
||||||
testEnv.initNodes(scenario.initNodes)
|
testEnv.initNodes(scenario.initNodes)
|
||||||
testEnv.initCSINodes(scenario.initCSINodes)
|
testEnv.initCSINodes(scenario.initCSINodes)
|
||||||
testEnv.initVolumes(scenario.initPVs, nil)
|
testEnv.initVolumes(scenario.initPVs, nil)
|
||||||
@ -1741,7 +1746,7 @@ func TestBindPodVolumes(t *testing.T) {
|
|||||||
initPVCs []*v1.PersistentVolumeClaim
|
initPVCs []*v1.PersistentVolumeClaim
|
||||||
|
|
||||||
// assume PV & PVC with these binding results
|
// assume PV & PVC with these binding results
|
||||||
binding *bindingInfo
|
binding *BindingInfo
|
||||||
claimToProvision *v1.PersistentVolumeClaim
|
claimToProvision *v1.PersistentVolumeClaim
|
||||||
|
|
||||||
// API updates after assume before bind
|
// API updates after assume before bind
|
||||||
@ -1819,19 +1824,7 @@ func TestBindPodVolumes(t *testing.T) {
|
|||||||
initPVs: []*v1.PersistentVolume{pvNode1a},
|
initPVs: []*v1.PersistentVolume{pvNode1a},
|
||||||
initPVCs: []*v1.PersistentVolumeClaim{unboundPVC},
|
initPVCs: []*v1.PersistentVolumeClaim{unboundPVC},
|
||||||
delayFunc: func(t *testing.T, testEnv *testEnv, pod *v1.Pod, pvs []*v1.PersistentVolume, pvcs []*v1.PersistentVolumeClaim) {
|
delayFunc: func(t *testing.T, testEnv *testEnv, pod *v1.Pod, pvs []*v1.PersistentVolume, pvcs []*v1.PersistentVolumeClaim) {
|
||||||
bindingsCache := testEnv.binder.GetBindingsCache()
|
testEnv.client.CoreV1().Pods(pod.Namespace).Delete(context.Background(), pod.Name, metav1.DeleteOptions{})
|
||||||
if bindingsCache == nil {
|
|
||||||
t.Fatalf("Failed to get bindings cache")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Delete the pod from the cache
|
|
||||||
bindingsCache.DeleteBindings(pod)
|
|
||||||
|
|
||||||
// Check that it's deleted
|
|
||||||
bindings := bindingsCache.GetBindings(pod, "node1")
|
|
||||||
if bindings != nil {
|
|
||||||
t.Fatalf("Failed to delete bindings")
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
shouldFail: true,
|
shouldFail: true,
|
||||||
},
|
},
|
||||||
@ -1892,15 +1885,16 @@ func TestBindPodVolumes(t *testing.T) {
|
|||||||
// Setup
|
// Setup
|
||||||
pod := makePod(nil)
|
pod := makePod(nil)
|
||||||
testEnv := newTestBinder(t, ctx.Done())
|
testEnv := newTestBinder(t, ctx.Done())
|
||||||
|
testEnv.internalPodInformer.Informer().GetIndexer().Add(pod)
|
||||||
if scenario.nodes == nil {
|
if scenario.nodes == nil {
|
||||||
scenario.nodes = []*v1.Node{node1}
|
scenario.nodes = []*v1.Node{node1}
|
||||||
}
|
}
|
||||||
|
bindings := []*BindingInfo{}
|
||||||
|
claimsToProvision := []*v1.PersistentVolumeClaim{}
|
||||||
if !scenario.bindingsNil {
|
if !scenario.bindingsNil {
|
||||||
bindings := []*bindingInfo{}
|
|
||||||
if scenario.binding != nil {
|
if scenario.binding != nil {
|
||||||
bindings = []*bindingInfo{scenario.binding}
|
bindings = []*BindingInfo{scenario.binding}
|
||||||
}
|
}
|
||||||
claimsToProvision := []*v1.PersistentVolumeClaim{}
|
|
||||||
if scenario.claimToProvision != nil {
|
if scenario.claimToProvision != nil {
|
||||||
claimsToProvision = []*v1.PersistentVolumeClaim{scenario.claimToProvision}
|
claimsToProvision = []*v1.PersistentVolumeClaim{scenario.claimToProvision}
|
||||||
}
|
}
|
||||||
@ -1934,7 +1928,11 @@ func TestBindPodVolumes(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Execute
|
// Execute
|
||||||
err := testEnv.binder.BindPodVolumes(pod)
|
podVolumes := &PodVolumes{
|
||||||
|
StaticBindings: bindings,
|
||||||
|
DynamicProvisions: claimsToProvision,
|
||||||
|
}
|
||||||
|
err := testEnv.binder.BindPodVolumes(pod, podVolumes)
|
||||||
|
|
||||||
// Validate
|
// Validate
|
||||||
if !scenario.shouldFail && err != nil {
|
if !scenario.shouldFail && err != nil {
|
||||||
@ -1974,17 +1972,17 @@ func TestFindAssumeVolumes(t *testing.T) {
|
|||||||
|
|
||||||
// Execute
|
// Execute
|
||||||
// 1. Find matching PVs
|
// 1. Find matching PVs
|
||||||
reasons, err := findPodVolumes(testEnv.binder, pod, testNode)
|
podVolumes, reasons, err := findPodVolumes(testEnv.binder, pod, testNode)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Test failed: FindPodVolumes returned error: %v", err)
|
t.Errorf("Test failed: FindPodVolumes returned error: %v", err)
|
||||||
}
|
}
|
||||||
if len(reasons) > 0 {
|
if len(reasons) > 0 {
|
||||||
t.Errorf("Test failed: couldn't find PVs for all PVCs: %v", reasons)
|
t.Errorf("Test failed: couldn't find PVs for all PVCs: %v", reasons)
|
||||||
}
|
}
|
||||||
expectedBindings := testEnv.getPodBindings(t, testNode.Name, pod)
|
expectedBindings := podVolumes.StaticBindings
|
||||||
|
|
||||||
// 2. Assume matches
|
// 2. Assume matches
|
||||||
allBound, err := testEnv.binder.AssumePodVolumes(pod, testNode.Name)
|
allBound, err := testEnv.binder.AssumePodVolumes(pod, testNode.Name, podVolumes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Test failed: AssumePodVolumes returned error: %v", err)
|
t.Errorf("Test failed: AssumePodVolumes returned error: %v", err)
|
||||||
}
|
}
|
||||||
@ -1994,19 +1992,19 @@ func TestFindAssumeVolumes(t *testing.T) {
|
|||||||
testEnv.validateAssume(t, pod, expectedBindings, nil)
|
testEnv.validateAssume(t, pod, expectedBindings, nil)
|
||||||
|
|
||||||
// After assume, claimref should be set on pv
|
// After assume, claimref should be set on pv
|
||||||
expectedBindings = testEnv.getPodBindings(t, testNode.Name, pod)
|
expectedBindings = podVolumes.StaticBindings
|
||||||
|
|
||||||
// 3. Find matching PVs again
|
// 3. Find matching PVs again
|
||||||
// This should always return the original chosen pv
|
// This should always return the original chosen pv
|
||||||
// Run this many times in case sorting returns different orders for the two PVs.
|
// Run this many times in case sorting returns different orders for the two PVs.
|
||||||
for i := 0; i < 50; i++ {
|
for i := 0; i < 50; i++ {
|
||||||
reasons, err := findPodVolumes(testEnv.binder, pod, testNode)
|
podVolumes, reasons, err := findPodVolumes(testEnv.binder, pod, testNode)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Test failed: FindPodVolumes returned error: %v", err)
|
t.Errorf("Test failed: FindPodVolumes returned error: %v", err)
|
||||||
}
|
}
|
||||||
if len(reasons) > 0 {
|
if len(reasons) > 0 {
|
||||||
t.Errorf("Test failed: couldn't find PVs for all PVCs: %v", reasons)
|
t.Errorf("Test failed: couldn't find PVs for all PVCs: %v", reasons)
|
||||||
}
|
}
|
||||||
testEnv.validatePodCache(t, testNode.Name, pod, expectedBindings, nil)
|
testEnv.validatePodCache(t, testNode.Name, pod, podVolumes, expectedBindings, nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -157,11 +157,6 @@ func getDefaultConfig() *schedulerapi.Plugins {
|
|||||||
{Name: defaultbinder.Name},
|
{Name: defaultbinder.Name},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
PostBind: &schedulerapi.PluginSet{
|
|
||||||
Enabled: []schedulerapi.Plugin{
|
|
||||||
{Name: volumebinding.Name},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -127,11 +127,6 @@ func TestClusterAutoscalerProvider(t *testing.T) {
|
|||||||
{Name: defaultbinder.Name},
|
{Name: defaultbinder.Name},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
PostBind: &schedulerapi.PluginSet{
|
|
||||||
Enabled: []schedulerapi.Plugin{
|
|
||||||
{Name: volumebinding.Name},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
r := NewRegistry()
|
r := NewRegistry()
|
||||||
@ -229,11 +224,6 @@ func TestApplyFeatureGates(t *testing.T) {
|
|||||||
{Name: defaultbinder.Name},
|
{Name: defaultbinder.Name},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
PostBind: &schedulerapi.PluginSet{
|
|
||||||
Enabled: []schedulerapi.Plugin{
|
|
||||||
{Name: volumebinding.Name},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -317,11 +307,6 @@ func TestApplyFeatureGates(t *testing.T) {
|
|||||||
{Name: defaultbinder.Name},
|
{Name: defaultbinder.Name},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
PostBind: &schedulerapi.PluginSet{
|
|
||||||
Enabled: []schedulerapi.Plugin{
|
|
||||||
{Name: volumebinding.Name},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -706,7 +706,6 @@ func TestCompatibility_v1_Scheduler(t *testing.T) {
|
|||||||
"ReservePlugin": {{Name: "VolumeBinding"}},
|
"ReservePlugin": {{Name: "VolumeBinding"}},
|
||||||
"UnreservePlugin": {{Name: "VolumeBinding"}},
|
"UnreservePlugin": {{Name: "VolumeBinding"}},
|
||||||
"PreBindPlugin": {{Name: "VolumeBinding"}},
|
"PreBindPlugin": {{Name: "VolumeBinding"}},
|
||||||
"PostBindPlugin": {{Name: "VolumeBinding"}},
|
|
||||||
},
|
},
|
||||||
wantExtenders: []config.Extender{{
|
wantExtenders: []config.Extender{{
|
||||||
URLPrefix: "/prefix",
|
URLPrefix: "/prefix",
|
||||||
@ -814,7 +813,6 @@ func TestCompatibility_v1_Scheduler(t *testing.T) {
|
|||||||
"ReservePlugin": {{Name: "VolumeBinding"}},
|
"ReservePlugin": {{Name: "VolumeBinding"}},
|
||||||
"UnreservePlugin": {{Name: "VolumeBinding"}},
|
"UnreservePlugin": {{Name: "VolumeBinding"}},
|
||||||
"PreBindPlugin": {{Name: "VolumeBinding"}},
|
"PreBindPlugin": {{Name: "VolumeBinding"}},
|
||||||
"PostBindPlugin": {{Name: "VolumeBinding"}},
|
|
||||||
},
|
},
|
||||||
wantExtenders: []config.Extender{{
|
wantExtenders: []config.Extender{{
|
||||||
URLPrefix: "/prefix",
|
URLPrefix: "/prefix",
|
||||||
@ -935,7 +933,6 @@ func TestCompatibility_v1_Scheduler(t *testing.T) {
|
|||||||
"ReservePlugin": {{Name: "VolumeBinding"}},
|
"ReservePlugin": {{Name: "VolumeBinding"}},
|
||||||
"UnreservePlugin": {{Name: "VolumeBinding"}},
|
"UnreservePlugin": {{Name: "VolumeBinding"}},
|
||||||
"PreBindPlugin": {{Name: "VolumeBinding"}},
|
"PreBindPlugin": {{Name: "VolumeBinding"}},
|
||||||
"PostBindPlugin": {{Name: "VolumeBinding"}},
|
|
||||||
},
|
},
|
||||||
wantExtenders: []config.Extender{{
|
wantExtenders: []config.Extender{{
|
||||||
URLPrefix: "/prefix",
|
URLPrefix: "/prefix",
|
||||||
@ -1058,7 +1055,6 @@ func TestCompatibility_v1_Scheduler(t *testing.T) {
|
|||||||
"ReservePlugin": {{Name: "VolumeBinding"}},
|
"ReservePlugin": {{Name: "VolumeBinding"}},
|
||||||
"UnreservePlugin": {{Name: "VolumeBinding"}},
|
"UnreservePlugin": {{Name: "VolumeBinding"}},
|
||||||
"PreBindPlugin": {{Name: "VolumeBinding"}},
|
"PreBindPlugin": {{Name: "VolumeBinding"}},
|
||||||
"PostBindPlugin": {{Name: "VolumeBinding"}},
|
|
||||||
},
|
},
|
||||||
wantExtenders: []config.Extender{{
|
wantExtenders: []config.Extender{{
|
||||||
URLPrefix: "/prefix",
|
URLPrefix: "/prefix",
|
||||||
@ -1181,7 +1177,6 @@ func TestCompatibility_v1_Scheduler(t *testing.T) {
|
|||||||
"ReservePlugin": {{Name: "VolumeBinding"}},
|
"ReservePlugin": {{Name: "VolumeBinding"}},
|
||||||
"UnreservePlugin": {{Name: "VolumeBinding"}},
|
"UnreservePlugin": {{Name: "VolumeBinding"}},
|
||||||
"PreBindPlugin": {{Name: "VolumeBinding"}},
|
"PreBindPlugin": {{Name: "VolumeBinding"}},
|
||||||
"PostBindPlugin": {{Name: "VolumeBinding"}},
|
|
||||||
},
|
},
|
||||||
wantExtenders: []config.Extender{{
|
wantExtenders: []config.Extender{{
|
||||||
URLPrefix: "/prefix",
|
URLPrefix: "/prefix",
|
||||||
@ -1308,7 +1303,6 @@ func TestCompatibility_v1_Scheduler(t *testing.T) {
|
|||||||
"ReservePlugin": {{Name: "VolumeBinding"}},
|
"ReservePlugin": {{Name: "VolumeBinding"}},
|
||||||
"UnreservePlugin": {{Name: "VolumeBinding"}},
|
"UnreservePlugin": {{Name: "VolumeBinding"}},
|
||||||
"PreBindPlugin": {{Name: "VolumeBinding"}},
|
"PreBindPlugin": {{Name: "VolumeBinding"}},
|
||||||
"PostBindPlugin": {{Name: "VolumeBinding"}},
|
|
||||||
},
|
},
|
||||||
wantExtenders: []config.Extender{{
|
wantExtenders: []config.Extender{{
|
||||||
URLPrefix: "/prefix",
|
URLPrefix: "/prefix",
|
||||||
@ -1438,7 +1432,6 @@ func TestAlgorithmProviderCompatibility(t *testing.T) {
|
|||||||
"ReservePlugin": {{Name: "VolumeBinding"}},
|
"ReservePlugin": {{Name: "VolumeBinding"}},
|
||||||
"UnreservePlugin": {{Name: "VolumeBinding"}},
|
"UnreservePlugin": {{Name: "VolumeBinding"}},
|
||||||
"PreBindPlugin": {{Name: "VolumeBinding"}},
|
"PreBindPlugin": {{Name: "VolumeBinding"}},
|
||||||
"PostBindPlugin": {{Name: "VolumeBinding"}},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
testcases := []struct {
|
testcases := []struct {
|
||||||
@ -1510,7 +1503,6 @@ func TestAlgorithmProviderCompatibility(t *testing.T) {
|
|||||||
"UnreservePlugin": {{Name: "VolumeBinding"}},
|
"UnreservePlugin": {{Name: "VolumeBinding"}},
|
||||||
"PreBindPlugin": {{Name: "VolumeBinding"}},
|
"PreBindPlugin": {{Name: "VolumeBinding"}},
|
||||||
"BindPlugin": {{Name: "DefaultBinder"}},
|
"BindPlugin": {{Name: "DefaultBinder"}},
|
||||||
"PostBindPlugin": {{Name: "VolumeBinding"}},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@ -1602,7 +1594,6 @@ func TestPluginsConfigurationCompatibility(t *testing.T) {
|
|||||||
"UnreservePlugin": {{Name: "VolumeBinding"}},
|
"UnreservePlugin": {{Name: "VolumeBinding"}},
|
||||||
"PreBindPlugin": {{Name: "VolumeBinding"}},
|
"PreBindPlugin": {{Name: "VolumeBinding"}},
|
||||||
"BindPlugin": {{Name: "DefaultBinder"}},
|
"BindPlugin": {{Name: "DefaultBinder"}},
|
||||||
"PostBindPlugin": {{Name: "VolumeBinding"}},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
testcases := []struct {
|
testcases := []struct {
|
||||||
@ -1953,7 +1944,6 @@ func TestPluginsConfigurationCompatibility(t *testing.T) {
|
|||||||
"UnreservePlugin": {{Name: "VolumeBinding"}},
|
"UnreservePlugin": {{Name: "VolumeBinding"}},
|
||||||
"PreBindPlugin": {{Name: "VolumeBinding"}},
|
"PreBindPlugin": {{Name: "VolumeBinding"}},
|
||||||
"BindPlugin": {{Name: "DefaultBinder"}},
|
"BindPlugin": {{Name: "DefaultBinder"}},
|
||||||
"PostBindPlugin": {{Name: "VolumeBinding"}},
|
|
||||||
},
|
},
|
||||||
wantPluginConfig: nil,
|
wantPluginConfig: nil,
|
||||||
},
|
},
|
||||||
|
@ -274,7 +274,6 @@ func NewLegacyRegistry() *LegacyRegistry {
|
|||||||
plugins.Reserve = appendToPluginSet(plugins.Reserve, volumebinding.Name, nil)
|
plugins.Reserve = appendToPluginSet(plugins.Reserve, volumebinding.Name, nil)
|
||||||
plugins.PreBind = appendToPluginSet(plugins.PreBind, volumebinding.Name, nil)
|
plugins.PreBind = appendToPluginSet(plugins.PreBind, volumebinding.Name, nil)
|
||||||
plugins.Unreserve = appendToPluginSet(plugins.Unreserve, volumebinding.Name, nil)
|
plugins.Unreserve = appendToPluginSet(plugins.Unreserve, volumebinding.Name, nil)
|
||||||
plugins.PostBind = appendToPluginSet(plugins.PostBind, volumebinding.Name, nil)
|
|
||||||
return
|
return
|
||||||
})
|
})
|
||||||
registry.registerPredicateConfigProducer(NoDiskConflictPred,
|
registry.registerPredicateConfigProducer(NoDiskConflictPred,
|
||||||
|
@ -11,8 +11,6 @@ go_library(
|
|||||||
"//pkg/scheduler/framework/v1alpha1:go_default_library",
|
"//pkg/scheduler/framework/v1alpha1:go_default_library",
|
||||||
"//staging/src/k8s.io/api/core/v1:go_default_library",
|
"//staging/src/k8s.io/api/core/v1:go_default_library",
|
||||||
"//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
"//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
||||||
"//staging/src/k8s.io/apimachinery/pkg/util/runtime:go_default_library",
|
|
||||||
"//staging/src/k8s.io/client-go/tools/cache:go_default_library",
|
|
||||||
"//vendor/k8s.io/klog/v2:go_default_library",
|
"//vendor/k8s.io/klog/v2:go_default_library",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
@ -24,8 +24,6 @@ import (
|
|||||||
|
|
||||||
v1 "k8s.io/api/core/v1"
|
v1 "k8s.io/api/core/v1"
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
|
|
||||||
"k8s.io/client-go/tools/cache"
|
|
||||||
"k8s.io/klog/v2"
|
"k8s.io/klog/v2"
|
||||||
"k8s.io/kubernetes/pkg/controller/volume/scheduling"
|
"k8s.io/kubernetes/pkg/controller/volume/scheduling"
|
||||||
"k8s.io/kubernetes/pkg/scheduler/apis/config"
|
"k8s.io/kubernetes/pkg/scheduler/apis/config"
|
||||||
@ -39,11 +37,18 @@ const (
|
|||||||
stateKey framework.StateKey = Name
|
stateKey framework.StateKey = Name
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// the state is initialized in PreFilter phase. because we save the pointer in
|
||||||
|
// framework.CycleState, in the later phases we don't need to call Write method
|
||||||
|
// to update the value
|
||||||
type stateData struct {
|
type stateData struct {
|
||||||
skip bool // set true if pod does not have PVCs
|
skip bool // set true if pod does not have PVCs
|
||||||
boundClaims []*v1.PersistentVolumeClaim
|
boundClaims []*v1.PersistentVolumeClaim
|
||||||
claimsToBind []*v1.PersistentVolumeClaim
|
claimsToBind []*v1.PersistentVolumeClaim
|
||||||
allBound bool
|
allBound bool
|
||||||
|
// podVolumesByNode holds the pod's volume information found in the Filter
|
||||||
|
// phase for each node
|
||||||
|
// it's initialized in the PreFilter phase
|
||||||
|
podVolumesByNode map[string]*scheduling.PodVolumes
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *stateData) Clone() framework.StateData {
|
func (d *stateData) Clone() framework.StateData {
|
||||||
@ -52,12 +57,7 @@ func (d *stateData) Clone() framework.StateData {
|
|||||||
|
|
||||||
// VolumeBinding is a plugin that binds pod volumes in scheduling.
|
// VolumeBinding is a plugin that binds pod volumes in scheduling.
|
||||||
// In the Filter phase, pod binding cache is created for the pod and used in
|
// In the Filter phase, pod binding cache is created for the pod and used in
|
||||||
// Reserve and PreBind phases. Pod binding cache will be cleared at
|
// Reserve and PreBind phases.
|
||||||
// Unreserve and PostBind extension points. However, if pod fails before
|
|
||||||
// the Reserve phase and is deleted from the apiserver later, its pod binding
|
|
||||||
// cache cannot be cleared at plugin extension points. We register an
|
|
||||||
// event handler to clear pod binding cache when the pod is deleted to
|
|
||||||
// prevent memory leaking.
|
|
||||||
type VolumeBinding struct {
|
type VolumeBinding struct {
|
||||||
Binder scheduling.SchedulerVolumeBinder
|
Binder scheduling.SchedulerVolumeBinder
|
||||||
}
|
}
|
||||||
@ -67,7 +67,6 @@ var _ framework.FilterPlugin = &VolumeBinding{}
|
|||||||
var _ framework.ReservePlugin = &VolumeBinding{}
|
var _ framework.ReservePlugin = &VolumeBinding{}
|
||||||
var _ framework.PreBindPlugin = &VolumeBinding{}
|
var _ framework.PreBindPlugin = &VolumeBinding{}
|
||||||
var _ framework.UnreservePlugin = &VolumeBinding{}
|
var _ framework.UnreservePlugin = &VolumeBinding{}
|
||||||
var _ framework.PostBindPlugin = &VolumeBinding{}
|
|
||||||
|
|
||||||
// Name is the name of the plugin used in Registry and configurations.
|
// Name is the name of the plugin used in Registry and configurations.
|
||||||
const Name = "VolumeBinding"
|
const Name = "VolumeBinding"
|
||||||
@ -90,7 +89,7 @@ func podHasPVCs(pod *v1.Pod) bool {
|
|||||||
// immediate PVCs bound. If not all immediate PVCs are bound, an
|
// immediate PVCs bound. If not all immediate PVCs are bound, an
|
||||||
// UnschedulableAndUnresolvable is returned.
|
// UnschedulableAndUnresolvable is returned.
|
||||||
func (pl *VolumeBinding) PreFilter(ctx context.Context, state *framework.CycleState, pod *v1.Pod) *framework.Status {
|
func (pl *VolumeBinding) PreFilter(ctx context.Context, state *framework.CycleState, pod *v1.Pod) *framework.Status {
|
||||||
// If pod does not request any PVC, we don't need to do anything.
|
// If pod does not reference any PVC, we don't need to do anything.
|
||||||
if !podHasPVCs(pod) {
|
if !podHasPVCs(pod) {
|
||||||
state.Write(stateKey, &stateData{skip: true})
|
state.Write(stateKey, &stateData{skip: true})
|
||||||
return nil
|
return nil
|
||||||
@ -107,7 +106,7 @@ func (pl *VolumeBinding) PreFilter(ctx context.Context, state *framework.CycleSt
|
|||||||
status.AppendReason("pod has unbound immediate PersistentVolumeClaims")
|
status.AppendReason("pod has unbound immediate PersistentVolumeClaims")
|
||||||
return status
|
return status
|
||||||
}
|
}
|
||||||
state.Write(stateKey, &stateData{boundClaims: boundClaims, claimsToBind: claimsToBind})
|
state.Write(stateKey, &stateData{boundClaims: boundClaims, claimsToBind: claimsToBind, podVolumesByNode: make(map[string]*scheduling.PodVolumes)})
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -155,7 +154,7 @@ func (pl *VolumeBinding) Filter(ctx context.Context, cs *framework.CycleState, p
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
reasons, err := pl.Binder.FindPodVolumes(pod, state.boundClaims, state.claimsToBind, node)
|
podVolumes, reasons, err := pl.Binder.FindPodVolumes(pod, state.boundClaims, state.claimsToBind, node)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return framework.NewStatus(framework.Error, err.Error())
|
return framework.NewStatus(framework.Error, err.Error())
|
||||||
@ -168,16 +167,31 @@ func (pl *VolumeBinding) Filter(ctx context.Context, cs *framework.CycleState, p
|
|||||||
}
|
}
|
||||||
return status
|
return status
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cs.Lock()
|
||||||
|
state.podVolumesByNode[node.Name] = podVolumes
|
||||||
|
cs.Unlock()
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reserve reserves volumes of pod and saves binding status in cycle state.
|
// Reserve reserves volumes of pod and saves binding status in cycle state.
|
||||||
func (pl *VolumeBinding) Reserve(ctx context.Context, cs *framework.CycleState, pod *v1.Pod, nodeName string) *framework.Status {
|
func (pl *VolumeBinding) Reserve(ctx context.Context, cs *framework.CycleState, pod *v1.Pod, nodeName string) *framework.Status {
|
||||||
allBound, err := pl.Binder.AssumePodVolumes(pod, nodeName)
|
state, err := getStateData(cs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return framework.NewStatus(framework.Error, err.Error())
|
return framework.NewStatus(framework.Error, err.Error())
|
||||||
}
|
}
|
||||||
cs.Write(stateKey, &stateData{allBound: allBound})
|
// we don't need to hold the lock as only one node will be reserved for the given pod
|
||||||
|
podVolumes, ok := state.podVolumesByNode[nodeName]
|
||||||
|
if ok {
|
||||||
|
allBound, err := pl.Binder.AssumePodVolumes(pod, nodeName, podVolumes)
|
||||||
|
if err != nil {
|
||||||
|
return framework.NewStatus(framework.Error, err.Error())
|
||||||
|
}
|
||||||
|
state.allBound = allBound
|
||||||
|
} else {
|
||||||
|
// may not exist if the pod does not reference any PVC
|
||||||
|
state.allBound = true
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -195,8 +209,13 @@ func (pl *VolumeBinding) PreBind(ctx context.Context, cs *framework.CycleState,
|
|||||||
// no need to bind volumes
|
// no need to bind volumes
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
// we don't need to hold the lock as only one node will be pre-bound for the given pod
|
||||||
|
podVolumes, ok := s.podVolumesByNode[nodeName]
|
||||||
|
if !ok {
|
||||||
|
return framework.NewStatus(framework.Error, fmt.Sprintf("no pod volumes found for node %q", nodeName))
|
||||||
|
}
|
||||||
klog.V(5).Infof("Trying to bind volumes for pod \"%v/%v\"", pod.Namespace, pod.Name)
|
klog.V(5).Infof("Trying to bind volumes for pod \"%v/%v\"", pod.Namespace, pod.Name)
|
||||||
err = pl.Binder.BindPodVolumes(pod)
|
err = pl.Binder.BindPodVolumes(pod, podVolumes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
klog.V(1).Infof("Failed to bind volumes for pod \"%v/%v\": %v", pod.Namespace, pod.Name, err)
|
klog.V(1).Infof("Failed to bind volumes for pod \"%v/%v\": %v", pod.Namespace, pod.Name, err)
|
||||||
return framework.NewStatus(framework.Error, err.Error())
|
return framework.NewStatus(framework.Error, err.Error())
|
||||||
@ -205,17 +224,19 @@ func (pl *VolumeBinding) PreBind(ctx context.Context, cs *framework.CycleState,
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unreserve clears assumed PV and PVC cache and pod binding state.
|
// Unreserve clears assumed PV and PVC cache.
|
||||||
// It's idempotent, and does nothing if no cache or binding state found for the given pod.
|
// It's idempotent, and does nothing if no cache found for the given pod.
|
||||||
func (pl *VolumeBinding) Unreserve(ctx context.Context, cs *framework.CycleState, pod *v1.Pod, nodeName string) {
|
func (pl *VolumeBinding) Unreserve(ctx context.Context, cs *framework.CycleState, pod *v1.Pod, nodeName string) {
|
||||||
pl.Binder.RevertAssumedPodVolumes(pod, nodeName)
|
s, err := getStateData(cs)
|
||||||
pl.Binder.DeletePodBindings(pod)
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
// we don't need to hold the lock as only one node may be unreserved
|
||||||
// PostBind is called after a pod is successfully bound.
|
podVolumes, ok := s.podVolumesByNode[nodeName]
|
||||||
func (pl *VolumeBinding) PostBind(ctx context.Context, cs *framework.CycleState, pod *v1.Pod, nodeName string) {
|
if !ok {
|
||||||
pl.Binder.DeletePodBindings(pod)
|
return
|
||||||
|
}
|
||||||
|
pl.Binder.RevertAssumedPodVolumes(podVolumes)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -228,37 +249,13 @@ func New(plArgs runtime.Object, fh framework.FrameworkHandle) (framework.Plugin,
|
|||||||
if err := validateArgs(args); err != nil {
|
if err := validateArgs(args); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
podInformer := fh.SharedInformerFactory().Core().V1().Pods()
|
||||||
nodeInformer := fh.SharedInformerFactory().Core().V1().Nodes()
|
nodeInformer := fh.SharedInformerFactory().Core().V1().Nodes()
|
||||||
pvcInformer := fh.SharedInformerFactory().Core().V1().PersistentVolumeClaims()
|
pvcInformer := fh.SharedInformerFactory().Core().V1().PersistentVolumeClaims()
|
||||||
pvInformer := fh.SharedInformerFactory().Core().V1().PersistentVolumes()
|
pvInformer := fh.SharedInformerFactory().Core().V1().PersistentVolumes()
|
||||||
storageClassInformer := fh.SharedInformerFactory().Storage().V1().StorageClasses()
|
storageClassInformer := fh.SharedInformerFactory().Storage().V1().StorageClasses()
|
||||||
csiNodeInformer := fh.SharedInformerFactory().Storage().V1().CSINodes()
|
csiNodeInformer := fh.SharedInformerFactory().Storage().V1().CSINodes()
|
||||||
binder := scheduling.NewVolumeBinder(fh.ClientSet(), nodeInformer, csiNodeInformer, pvcInformer, pvInformer, storageClassInformer, time.Duration(args.BindTimeoutSeconds)*time.Second)
|
binder := scheduling.NewVolumeBinder(fh.ClientSet(), podInformer, nodeInformer, csiNodeInformer, pvcInformer, pvInformer, storageClassInformer, time.Duration(args.BindTimeoutSeconds)*time.Second)
|
||||||
// TODO(#90962) Because pod volume binding cache in SchedulerVolumeBinder is
|
|
||||||
// used only in current scheduling cycle, we can share it via
|
|
||||||
// framework.CycleState, then we don't need to register this event handler
|
|
||||||
// and Unreserve/PostBind extension points to clear pod volume binding
|
|
||||||
// cache.
|
|
||||||
fh.SharedInformerFactory().Core().V1().Pods().Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{
|
|
||||||
DeleteFunc: func(obj interface{}) {
|
|
||||||
var pod *v1.Pod
|
|
||||||
switch t := obj.(type) {
|
|
||||||
case *v1.Pod:
|
|
||||||
pod = obj.(*v1.Pod)
|
|
||||||
case cache.DeletedFinalStateUnknown:
|
|
||||||
var ok bool
|
|
||||||
pod, ok = t.Obj.(*v1.Pod)
|
|
||||||
if !ok {
|
|
||||||
utilruntime.HandleError(fmt.Errorf("unable to convert object %T to *v1.Pod", obj))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
utilruntime.HandleError(fmt.Errorf("unable to handle object %T", obj))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
binder.DeletePodBindings(pod)
|
|
||||||
},
|
|
||||||
})
|
|
||||||
return &VolumeBinding{
|
return &VolumeBinding{
|
||||||
Binder: binder,
|
Binder: binder,
|
||||||
}, nil
|
}, nil
|
||||||
|
@ -134,7 +134,8 @@ func TestVolumeBinding(t *testing.T) {
|
|||||||
boundClaims: []*v1.PersistentVolumeClaim{
|
boundClaims: []*v1.PersistentVolumeClaim{
|
||||||
makePVC("pvc-a", "pv-a", waitSC.Name),
|
makePVC("pvc-a", "pv-a", waitSC.Name),
|
||||||
},
|
},
|
||||||
claimsToBind: []*v1.PersistentVolumeClaim{},
|
claimsToBind: []*v1.PersistentVolumeClaim{},
|
||||||
|
podVolumesByNode: map[string]*scheduling.PodVolumes{},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -158,6 +159,7 @@ func TestVolumeBinding(t *testing.T) {
|
|||||||
claimsToBind: []*v1.PersistentVolumeClaim{
|
claimsToBind: []*v1.PersistentVolumeClaim{
|
||||||
makePVC("pvc-a", "", waitSC.Name),
|
makePVC("pvc-a", "", waitSC.Name),
|
||||||
},
|
},
|
||||||
|
podVolumesByNode: map[string]*scheduling.PodVolumes{},
|
||||||
},
|
},
|
||||||
wantFilterStatus: framework.NewStatus(framework.UnschedulableAndUnresolvable, string(scheduling.ErrReasonBindConflict)),
|
wantFilterStatus: framework.NewStatus(framework.UnschedulableAndUnresolvable, string(scheduling.ErrReasonBindConflict)),
|
||||||
},
|
},
|
||||||
@ -199,6 +201,7 @@ func TestVolumeBinding(t *testing.T) {
|
|||||||
claimsToBind: []*v1.PersistentVolumeClaim{
|
claimsToBind: []*v1.PersistentVolumeClaim{
|
||||||
makePVC("pvc-b", "", waitSC.Name),
|
makePVC("pvc-b", "", waitSC.Name),
|
||||||
},
|
},
|
||||||
|
podVolumesByNode: map[string]*scheduling.PodVolumes{},
|
||||||
},
|
},
|
||||||
wantFilterStatus: framework.NewStatus(framework.UnschedulableAndUnresolvable, string(scheduling.ErrReasonNodeConflict), string(scheduling.ErrReasonBindConflict)),
|
wantFilterStatus: framework.NewStatus(framework.UnschedulableAndUnresolvable, string(scheduling.ErrReasonNodeConflict), string(scheduling.ErrReasonBindConflict)),
|
||||||
},
|
},
|
||||||
@ -221,7 +224,8 @@ func TestVolumeBinding(t *testing.T) {
|
|||||||
boundClaims: []*v1.PersistentVolumeClaim{
|
boundClaims: []*v1.PersistentVolumeClaim{
|
||||||
makePVC("pvc-a", "pv-a", waitSC.Name),
|
makePVC("pvc-a", "pv-a", waitSC.Name),
|
||||||
},
|
},
|
||||||
claimsToBind: []*v1.PersistentVolumeClaim{},
|
claimsToBind: []*v1.PersistentVolumeClaim{},
|
||||||
|
podVolumesByNode: map[string]*scheduling.PodVolumes{},
|
||||||
},
|
},
|
||||||
wantFilterStatus: framework.NewStatus(framework.Error, `could not find v1.PersistentVolume "pv-a"`),
|
wantFilterStatus: framework.NewStatus(framework.Error, `could not find v1.PersistentVolume "pv-a"`),
|
||||||
},
|
},
|
||||||
@ -229,7 +233,8 @@ func TestVolumeBinding(t *testing.T) {
|
|||||||
|
|
||||||
for _, item := range table {
|
for _, item := range table {
|
||||||
t.Run(item.name, func(t *testing.T) {
|
t.Run(item.name, func(t *testing.T) {
|
||||||
ctx := context.Background()
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
|
defer cancel()
|
||||||
client := fake.NewSimpleClientset()
|
client := fake.NewSimpleClientset()
|
||||||
informerFactory := informers.NewSharedInformerFactory(client, 0)
|
informerFactory := informers.NewSharedInformerFactory(client, 0)
|
||||||
opts := []runtime.Option{
|
opts := []runtime.Option{
|
||||||
@ -256,15 +261,11 @@ func TestVolumeBinding(t *testing.T) {
|
|||||||
if item.node != nil {
|
if item.node != nil {
|
||||||
client.CoreV1().Nodes().Create(ctx, item.node, metav1.CreateOptions{})
|
client.CoreV1().Nodes().Create(ctx, item.node, metav1.CreateOptions{})
|
||||||
}
|
}
|
||||||
if len(item.pvcs) > 0 {
|
for _, pvc := range item.pvcs {
|
||||||
for _, pvc := range item.pvcs {
|
client.CoreV1().PersistentVolumeClaims(pvc.Namespace).Create(ctx, pvc, metav1.CreateOptions{})
|
||||||
client.CoreV1().PersistentVolumeClaims(pvc.Namespace).Create(ctx, pvc, metav1.CreateOptions{})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if len(item.pvs) > 0 {
|
for _, pv := range item.pvs {
|
||||||
for _, pv := range item.pvs {
|
client.CoreV1().PersistentVolumes().Create(ctx, pv, metav1.CreateOptions{})
|
||||||
client.CoreV1().PersistentVolumes().Create(ctx, pv, metav1.CreateOptions{})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
caches := informerFactory.WaitForCacheSync(ctx.Done())
|
caches := informerFactory.WaitForCacheSync(ctx.Done())
|
||||||
for _, synced := range caches {
|
for _, synced := range caches {
|
||||||
|
@ -826,7 +826,7 @@ func setupTestSchedulerWithVolumeBinding(volumeBinder scheduling.SchedulerVolume
|
|||||||
st.RegisterBindPlugin(defaultbinder.Name, defaultbinder.New),
|
st.RegisterBindPlugin(defaultbinder.Name, defaultbinder.New),
|
||||||
st.RegisterPluginAsExtensions(volumebinding.Name, func(plArgs runtime.Object, handle framework.FrameworkHandle) (framework.Plugin, error) {
|
st.RegisterPluginAsExtensions(volumebinding.Name, func(plArgs runtime.Object, handle framework.FrameworkHandle) (framework.Plugin, error) {
|
||||||
return &volumebinding.VolumeBinding{Binder: volumeBinder}, nil
|
return &volumebinding.VolumeBinding{Binder: volumeBinder}, nil
|
||||||
}, "PreFilter", "Filter", "Reserve", "Unreserve", "PreBind", "PostBind"),
|
}, "PreFilter", "Filter", "Reserve", "Unreserve", "PreBind"),
|
||||||
}
|
}
|
||||||
s, bindingChan, errChan := setupTestScheduler(queuedPodStore, scache, informerFactory, broadcaster, fns...)
|
s, bindingChan, errChan := setupTestScheduler(queuedPodStore, scache, informerFactory, broadcaster, fns...)
|
||||||
informerFactory.Start(stop)
|
informerFactory.Start(stop)
|
||||||
|
@ -148,7 +148,6 @@ func TestSchedulerCreationFromConfigMap(t *testing.T) {
|
|||||||
"UnreservePlugin": {{Name: "VolumeBinding"}},
|
"UnreservePlugin": {{Name: "VolumeBinding"}},
|
||||||
"PreBindPlugin": {{Name: "VolumeBinding"}},
|
"PreBindPlugin": {{Name: "VolumeBinding"}},
|
||||||
"BindPlugin": {{Name: "DefaultBinder"}},
|
"BindPlugin": {{Name: "DefaultBinder"}},
|
||||||
"PostBindPlugin": {{Name: "VolumeBinding"}},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -243,7 +242,6 @@ kind: Policy
|
|||||||
"UnreservePlugin": {{Name: "VolumeBinding"}},
|
"UnreservePlugin": {{Name: "VolumeBinding"}},
|
||||||
"PreBindPlugin": {{Name: "VolumeBinding"}},
|
"PreBindPlugin": {{Name: "VolumeBinding"}},
|
||||||
"BindPlugin": {{Name: "DefaultBinder"}},
|
"BindPlugin": {{Name: "DefaultBinder"}},
|
||||||
"PostBindPlugin": {{Name: "VolumeBinding"}},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user