Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
K
k3s
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Jacklull
k3s
Commits
094841c6
Commit
094841c6
authored
Nov 08, 2017
by
Michelle Au
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add predicate to find volume matches
parent
01a87721
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
298 additions
and
77 deletions
+298
-77
error.go
plugin/pkg/scheduler/algorithm/predicates/error.go
+2
-1
predicates.go
plugin/pkg/scheduler/algorithm/predicates/predicates.go
+75
-63
predicates_test.go
plugin/pkg/scheduler/algorithm/predicates/predicates_test.go
+139
-2
compatibility_test.go
...cheduler/algorithmprovider/defaults/compatibility_test.go
+76
-6
defaults.go
plugin/pkg/scheduler/algorithmprovider/defaults/defaults.go
+4
-4
defaults_test.go
...pkg/scheduler/algorithmprovider/defaults/defaults_test.go
+2
-1
No files found.
plugin/pkg/scheduler/algorithm/predicates/error.go
View file @
094841c6
...
@@ -50,7 +50,8 @@ var (
...
@@ -50,7 +50,8 @@ var (
ErrNodeNetworkUnavailable
=
newPredicateFailureError
(
"NodeNetworkUnavailable"
)
ErrNodeNetworkUnavailable
=
newPredicateFailureError
(
"NodeNetworkUnavailable"
)
ErrNodeUnschedulable
=
newPredicateFailureError
(
"NodeUnschedulable"
)
ErrNodeUnschedulable
=
newPredicateFailureError
(
"NodeUnschedulable"
)
ErrNodeUnknownCondition
=
newPredicateFailureError
(
"NodeUnknownCondition"
)
ErrNodeUnknownCondition
=
newPredicateFailureError
(
"NodeUnknownCondition"
)
ErrVolumeNodeConflict
=
newPredicateFailureError
(
"NoVolumeNodeConflict"
)
ErrVolumeNodeConflict
=
newPredicateFailureError
(
"VolumeNodeAffinityConflict"
)
ErrVolumeBindConflict
=
newPredicateFailureError
(
"VolumeBindingNoMatch"
)
// ErrFakePredicate is used for test only. The fake predicates returning false also returns error
// ErrFakePredicate is used for test only. The fake predicates returning false also returns error
// as ErrFakePredicate.
// as ErrFakePredicate.
ErrFakePredicate
=
newPredicateFailureError
(
"FakePredicateError"
)
ErrFakePredicate
=
newPredicateFailureError
(
"FakePredicateError"
)
...
...
plugin/pkg/scheduler/algorithm/predicates/predicates.go
View file @
094841c6
...
@@ -24,12 +24,14 @@ import (
...
@@ -24,12 +24,14 @@ import (
"sync"
"sync"
"k8s.io/api/core/v1"
"k8s.io/api/core/v1"
storagev1
"k8s.io/api/storage/v1"
apierrors
"k8s.io/apimachinery/pkg/api/errors"
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/rand"
"k8s.io/apimachinery/pkg/util/rand"
utilfeature
"k8s.io/apiserver/pkg/util/feature"
utilfeature
"k8s.io/apiserver/pkg/util/feature"
corelisters
"k8s.io/client-go/listers/core/v1"
corelisters
"k8s.io/client-go/listers/core/v1"
storagelisters
"k8s.io/client-go/listers/storage/v1"
"k8s.io/client-go/util/workqueue"
"k8s.io/client-go/util/workqueue"
v1helper
"k8s.io/kubernetes/pkg/apis/core/v1/helper"
v1helper
"k8s.io/kubernetes/pkg/apis/core/v1/helper"
v1qos
"k8s.io/kubernetes/pkg/apis/core/v1/helper/qos"
v1qos
"k8s.io/kubernetes/pkg/apis/core/v1/helper/qos"
...
@@ -41,13 +43,14 @@ import (
...
@@ -41,13 +43,14 @@ import (
priorityutil
"k8s.io/kubernetes/plugin/pkg/scheduler/algorithm/priorities/util"
priorityutil
"k8s.io/kubernetes/plugin/pkg/scheduler/algorithm/priorities/util"
"k8s.io/kubernetes/plugin/pkg/scheduler/schedulercache"
"k8s.io/kubernetes/plugin/pkg/scheduler/schedulercache"
schedutil
"k8s.io/kubernetes/plugin/pkg/scheduler/util"
schedutil
"k8s.io/kubernetes/plugin/pkg/scheduler/util"
"k8s.io/metrics/pkg/client/clientset_generated/clientset"
"github.com/golang/glog"
"github.com/golang/glog"
"k8s.io/kubernetes/plugin/pkg/scheduler/volumebinder"
)
)
const
(
const
(
MatchInterPodAffinity
=
"MatchInterPodAffinity"
MatchInterPodAffinity
=
"MatchInterPodAffinity"
CheckVolumeBinding
=
"CheckVolumeBinding"
// DefaultMaxGCEPDVolumes defines the maximum number of PD Volumes for GCE
// DefaultMaxGCEPDVolumes defines the maximum number of PD Volumes for GCE
// GCE instances can have up to 16 PD volumes attached.
// GCE instances can have up to 16 PD volumes attached.
...
@@ -127,6 +130,19 @@ func (c *CachedNodeInfo) GetNodeInfo(id string) (*v1.Node, error) {
...
@@ -127,6 +130,19 @@ func (c *CachedNodeInfo) GetNodeInfo(id string) (*v1.Node, error) {
return
node
,
nil
return
node
,
nil
}
}
type
StorageClassInfo
interface
{
GetStorageClassInfo
(
className
string
)
(
*
storagev1
.
StorageClass
,
error
)
}
// CachedStorageClassInfo implements StorageClassInfo
type
CachedStorageClassInfo
struct
{
storagelisters
.
StorageClassLister
}
func
(
c
*
CachedStorageClassInfo
)
GetStorageClassInfo
(
className
string
)
(
*
storagev1
.
StorageClass
,
error
)
{
return
c
.
Get
(
className
)
}
func
isVolumeConflict
(
volume
v1
.
Volume
,
pod
*
v1
.
Pod
)
bool
{
func
isVolumeConflict
(
volume
v1
.
Volume
,
pod
*
v1
.
Pod
)
bool
{
// fast path if there is no conflict checking targets.
// fast path if there is no conflict checking targets.
if
volume
.
GCEPersistentDisk
==
nil
&&
volume
.
AWSElasticBlockStore
==
nil
&&
volume
.
RBD
==
nil
&&
volume
.
ISCSI
==
nil
{
if
volume
.
GCEPersistentDisk
==
nil
&&
volume
.
AWSElasticBlockStore
==
nil
&&
volume
.
RBD
==
nil
&&
volume
.
ISCSI
==
nil
{
...
@@ -416,8 +432,9 @@ var AzureDiskVolumeFilter VolumeFilter = VolumeFilter{
...
@@ -416,8 +432,9 @@ var AzureDiskVolumeFilter VolumeFilter = VolumeFilter{
}
}
type
VolumeZoneChecker
struct
{
type
VolumeZoneChecker
struct
{
pvInfo
PersistentVolumeInfo
pvInfo
PersistentVolumeInfo
pvcInfo
PersistentVolumeClaimInfo
pvcInfo
PersistentVolumeClaimInfo
classInfo
StorageClassInfo
}
}
// NewVolumeZonePredicate evaluates if a pod can fit due to the volumes it requests, given
// NewVolumeZonePredicate evaluates if a pod can fit due to the volumes it requests, given
...
@@ -434,10 +451,11 @@ type VolumeZoneChecker struct {
...
@@ -434,10 +451,11 @@ type VolumeZoneChecker struct {
// determining the zone of a volume during scheduling, and that is likely to
// determining the zone of a volume during scheduling, and that is likely to
// require calling out to the cloud provider. It seems that we are moving away
// require calling out to the cloud provider. It seems that we are moving away
// from inline volume declarations anyway.
// from inline volume declarations anyway.
func
NewVolumeZonePredicate
(
pvInfo
PersistentVolumeInfo
,
pvcInfo
PersistentVolumeClaimInfo
)
algorithm
.
FitPredicate
{
func
NewVolumeZonePredicate
(
pvInfo
PersistentVolumeInfo
,
pvcInfo
PersistentVolumeClaimInfo
,
classInfo
StorageClassInfo
)
algorithm
.
FitPredicate
{
c
:=
&
VolumeZoneChecker
{
c
:=
&
VolumeZoneChecker
{
pvInfo
:
pvInfo
,
pvInfo
:
pvInfo
,
pvcInfo
:
pvcInfo
,
pvcInfo
:
pvcInfo
,
classInfo
:
classInfo
,
}
}
return
c
.
predicate
return
c
.
predicate
}
}
...
@@ -489,6 +507,21 @@ func (c *VolumeZoneChecker) predicate(pod *v1.Pod, meta algorithm.PredicateMetad
...
@@ -489,6 +507,21 @@ func (c *VolumeZoneChecker) predicate(pod *v1.Pod, meta algorithm.PredicateMetad
pvName
:=
pvc
.
Spec
.
VolumeName
pvName
:=
pvc
.
Spec
.
VolumeName
if
pvName
==
""
{
if
pvName
==
""
{
if
utilfeature
.
DefaultFeatureGate
.
Enabled
(
features
.
VolumeScheduling
)
{
scName
:=
pvc
.
Spec
.
StorageClassName
if
scName
!=
nil
&&
len
(
*
scName
)
>
0
{
class
,
_
:=
c
.
classInfo
.
GetStorageClassInfo
(
*
scName
)
if
class
!=
nil
{
if
class
.
VolumeBindingMode
==
nil
{
return
false
,
nil
,
fmt
.
Errorf
(
"VolumeBindingMode not set for StorageClass %q"
,
scName
)
}
if
*
class
.
VolumeBindingMode
==
storagev1
.
VolumeBindingWaitForFirstConsumer
{
// Skip unbound volumes
continue
}
}
}
}
return
false
,
nil
,
fmt
.
Errorf
(
"PersistentVolumeClaim is not bound: %q"
,
pvcName
)
return
false
,
nil
,
fmt
.
Errorf
(
"PersistentVolumeClaim is not bound: %q"
,
pvcName
)
}
}
...
@@ -1403,33 +1436,30 @@ func CheckNodeConditionPredicate(pod *v1.Pod, meta algorithm.PredicateMetadata,
...
@@ -1403,33 +1436,30 @@ func CheckNodeConditionPredicate(pod *v1.Pod, meta algorithm.PredicateMetadata,
return
len
(
reasons
)
==
0
,
reasons
,
nil
return
len
(
reasons
)
==
0
,
reasons
,
nil
}
}
type
VolumeNodeChecker
struct
{
type
VolumeBindingChecker
struct
{
pvInfo
PersistentVolumeInfo
binder
*
volumebinder
.
VolumeBinder
pvcInfo
PersistentVolumeClaimInfo
client
clientset
.
Interface
}
}
// NewVolumeNodePredicate evaluates if a pod can fit due to the volumes it requests, given
// NewVolumeBindingPredicate evaluates if a pod can fit due to the volumes it requests,
// that some volumes have node topology constraints, particularly when using Local PVs.
// for both bound and unbound PVCs.
// The requirement is that any pod that uses a PVC that is bound to a PV with topology constraints
//
// must be scheduled to a node that satisfies the PV's topology labels.
// For PVCs that are bound, then it checks that the corresponding PV's node affinity is
func
NewVolumeNodePredicate
(
pvInfo
PersistentVolumeInfo
,
pvcInfo
PersistentVolumeClaimInfo
,
client
clientset
.
Interface
)
algorithm
.
FitPredicate
{
// satisfied by the given node.
c
:=
&
VolumeNodeChecker
{
//
pvInfo
:
pvInfo
,
// For PVCs that are unbound, it tries to find available PVs that can satisfy the PVC requirements
pvcInfo
:
pvcInfo
,
// and that the PV node affinity is satisfied by the given node.
client
:
client
,
//
// The predicate returns true if all bound PVCs have compatible PVs with the node, and if all unbound
// PVCs can be matched with an available and node-compatible PV.
func
NewVolumeBindingPredicate
(
binder
*
volumebinder
.
VolumeBinder
)
algorithm
.
FitPredicate
{
c
:=
&
VolumeBindingChecker
{
binder
:
binder
,
}
}
return
c
.
predicate
return
c
.
predicate
}
}
func
(
c
*
VolumeNodeChecker
)
predicate
(
pod
*
v1
.
Pod
,
meta
algorithm
.
PredicateMetadata
,
nodeInfo
*
schedulercache
.
NodeInfo
)
(
bool
,
[]
algorithm
.
PredicateFailureReason
,
error
)
{
func
(
c
*
VolumeBindingChecker
)
predicate
(
pod
*
v1
.
Pod
,
meta
algorithm
.
PredicateMetadata
,
nodeInfo
*
schedulercache
.
NodeInfo
)
(
bool
,
[]
algorithm
.
PredicateFailureReason
,
error
)
{
if
!
utilfeature
.
DefaultFeatureGate
.
Enabled
(
features
.
PersistentLocalVolumes
)
{
if
!
utilfeature
.
DefaultFeatureGate
.
Enabled
(
features
.
VolumeScheduling
)
{
return
true
,
nil
,
nil
}
// If a pod doesn't have any volume attached to it, the predicate will always be true.
// Thus we make a fast path for it, to avoid unnecessary computations in this case.
if
len
(
pod
.
Spec
.
Volumes
)
==
0
{
return
true
,
nil
,
nil
return
true
,
nil
,
nil
}
}
...
@@ -1438,45 +1468,27 @@ func (c *VolumeNodeChecker) predicate(pod *v1.Pod, meta algorithm.PredicateMetad
...
@@ -1438,45 +1468,27 @@ func (c *VolumeNodeChecker) predicate(pod *v1.Pod, meta algorithm.PredicateMetad
return
false
,
nil
,
fmt
.
Errorf
(
"node not found"
)
return
false
,
nil
,
fmt
.
Errorf
(
"node not found"
)
}
}
glog
.
V
(
2
)
.
Infof
(
"Checking for prebound volumes with node affinity"
)
unboundSatisfied
,
boundSatisfied
,
err
:=
c
.
binder
.
Binder
.
FindPodVolumes
(
pod
,
node
.
Name
)
namespace
:=
pod
.
Namespace
if
err
!=
nil
{
manifest
:=
&
(
pod
.
Spec
)
return
false
,
nil
,
err
for
i
:=
range
manifest
.
Volumes
{
}
volume
:=
&
manifest
.
Volumes
[
i
]
if
volume
.
PersistentVolumeClaim
==
nil
{
continue
}
pvcName
:=
volume
.
PersistentVolumeClaim
.
ClaimName
if
pvcName
==
""
{
return
false
,
nil
,
fmt
.
Errorf
(
"PersistentVolumeClaim had no name"
)
}
pvc
,
err
:=
c
.
pvcInfo
.
GetPersistentVolumeClaimInfo
(
namespace
,
pvcName
)
if
err
!=
nil
{
return
false
,
nil
,
err
}
if
pvc
==
nil
{
failReasons
:=
[]
algorithm
.
PredicateFailureReason
{}
return
false
,
nil
,
fmt
.
Errorf
(
"PersistentVolumeClaim was not found: %q"
,
pvcName
)
if
!
boundSatisfied
{
}
glog
.
V
(
5
)
.
Info
(
"Bound PVs not satisfied for pod %v/%v, node %q"
,
pod
.
Namespace
,
pod
.
Name
,
node
.
Name
)
pvName
:=
pvc
.
Spec
.
VolumeName
failReasons
=
append
(
failReasons
,
ErrVolumeNodeConflict
)
if
pvName
==
""
{
}
return
false
,
nil
,
fmt
.
Errorf
(
"PersistentVolumeClaim is not bound: %q"
,
pvcName
)
}
pv
,
err
:=
c
.
pvInfo
.
GetPersistentVolumeInfo
(
pvName
)
if
!
unboundSatisfied
{
if
err
!=
nil
{
glog
.
V
(
5
)
.
Info
(
"Couldn't find matching PVs for pod %v/%v, node %q"
,
pod
.
Namespace
,
pod
.
Name
,
node
.
Name
)
return
false
,
nil
,
err
failReasons
=
append
(
failReasons
,
ErrVolumeBindConflict
)
}
}
if
pv
==
nil
{
return
false
,
nil
,
fmt
.
Errorf
(
"PersistentVolume not found: %q"
,
pvName
)
}
err
=
volumeutil
.
CheckNodeAffinity
(
pv
,
node
.
Labels
)
if
len
(
failReasons
)
>
0
{
if
err
!=
nil
{
return
false
,
failReasons
,
nil
glog
.
V
(
2
)
.
Infof
(
"Won't schedule pod %q onto node %q due to volume %q node mismatch: %v"
,
pod
.
Name
,
node
.
Name
,
pvName
,
err
.
Error
())
return
false
,
[]
algorithm
.
PredicateFailureReason
{
ErrVolumeNodeConflict
},
nil
}
glog
.
V
(
4
)
.
Infof
(
"VolumeNode predicate allows node %q for pod %q due to volume %q"
,
node
.
Name
,
pod
.
Name
,
pvName
)
}
}
// All volumes bound or matching PVs found for all unbound PVCs
glog
.
V
(
5
)
.
Info
(
"All PVCs found matches for pod %v/%v, node %q"
,
pod
.
Namespace
,
pod
.
Name
,
node
.
Name
)
return
true
,
nil
,
nil
return
true
,
nil
,
nil
}
}
plugin/pkg/scheduler/algorithm/predicates/predicates_test.go
View file @
094841c6
...
@@ -24,8 +24,10 @@ import (
...
@@ -24,8 +24,10 @@ import (
"testing"
"testing"
"k8s.io/api/core/v1"
"k8s.io/api/core/v1"
storagev1
"k8s.io/api/storage/v1"
"k8s.io/apimachinery/pkg/api/resource"
"k8s.io/apimachinery/pkg/api/resource"
metav1
"k8s.io/apimachinery/pkg/apis/meta/v1"
metav1
"k8s.io/apimachinery/pkg/apis/meta/v1"
utilfeature
"k8s.io/apiserver/pkg/util/feature"
v1helper
"k8s.io/kubernetes/pkg/apis/core/v1/helper"
v1helper
"k8s.io/kubernetes/pkg/apis/core/v1/helper"
kubeletapis
"k8s.io/kubernetes/pkg/kubelet/apis"
kubeletapis
"k8s.io/kubernetes/pkg/kubelet/apis"
"k8s.io/kubernetes/plugin/pkg/scheduler/algorithm"
"k8s.io/kubernetes/plugin/pkg/scheduler/algorithm"
...
@@ -74,6 +76,17 @@ func (pvs FakePersistentVolumeInfo) GetPersistentVolumeInfo(pvID string) (*v1.Pe
...
@@ -74,6 +76,17 @@ func (pvs FakePersistentVolumeInfo) GetPersistentVolumeInfo(pvID string) (*v1.Pe
return
nil
,
fmt
.
Errorf
(
"Unable to find persistent volume: %s"
,
pvID
)
return
nil
,
fmt
.
Errorf
(
"Unable to find persistent volume: %s"
,
pvID
)
}
}
type
FakeStorageClassInfo
[]
storagev1
.
StorageClass
func
(
classes
FakeStorageClassInfo
)
GetStorageClassInfo
(
name
string
)
(
*
storagev1
.
StorageClass
,
error
)
{
for
_
,
sc
:=
range
classes
{
if
sc
.
Name
==
name
{
return
&
sc
,
nil
}
}
return
nil
,
fmt
.
Errorf
(
"Unable to find storage class: %s"
,
name
)
}
var
(
var
(
opaqueResourceA
=
v1helper
.
OpaqueIntResourceName
(
"AAA"
)
opaqueResourceA
=
v1helper
.
OpaqueIntResourceName
(
"AAA"
)
opaqueResourceB
=
v1helper
.
OpaqueIntResourceName
(
"BBB"
)
opaqueResourceB
=
v1helper
.
OpaqueIntResourceName
(
"BBB"
)
...
@@ -3834,7 +3847,7 @@ func TestVolumeZonePredicate(t *testing.T) {
...
@@ -3834,7 +3847,7 @@ func TestVolumeZonePredicate(t *testing.T) {
expectedFailureReasons
:=
[]
algorithm
.
PredicateFailureReason
{
ErrVolumeZoneConflict
}
expectedFailureReasons
:=
[]
algorithm
.
PredicateFailureReason
{
ErrVolumeZoneConflict
}
for
_
,
test
:=
range
tests
{
for
_
,
test
:=
range
tests
{
fit
:=
NewVolumeZonePredicate
(
pvInfo
,
pvcInfo
)
fit
:=
NewVolumeZonePredicate
(
pvInfo
,
pvcInfo
,
nil
)
node
:=
&
schedulercache
.
NodeInfo
{}
node
:=
&
schedulercache
.
NodeInfo
{}
node
.
SetNode
(
test
.
Node
)
node
.
SetNode
(
test
.
Node
)
...
@@ -3927,7 +3940,7 @@ func TestVolumeZonePredicateMultiZone(t *testing.T) {
...
@@ -3927,7 +3940,7 @@ func TestVolumeZonePredicateMultiZone(t *testing.T) {
expectedFailureReasons
:=
[]
algorithm
.
PredicateFailureReason
{
ErrVolumeZoneConflict
}
expectedFailureReasons
:=
[]
algorithm
.
PredicateFailureReason
{
ErrVolumeZoneConflict
}
for
_
,
test
:=
range
tests
{
for
_
,
test
:=
range
tests
{
fit
:=
NewVolumeZonePredicate
(
pvInfo
,
pvcInfo
)
fit
:=
NewVolumeZonePredicate
(
pvInfo
,
pvcInfo
,
nil
)
node
:=
&
schedulercache
.
NodeInfo
{}
node
:=
&
schedulercache
.
NodeInfo
{}
node
.
SetNode
(
test
.
Node
)
node
.
SetNode
(
test
.
Node
)
...
@@ -3945,6 +3958,130 @@ func TestVolumeZonePredicateMultiZone(t *testing.T) {
...
@@ -3945,6 +3958,130 @@ func TestVolumeZonePredicateMultiZone(t *testing.T) {
}
}
}
}
func
TestVolumeZonePredicateWithVolumeBinding
(
t
*
testing
.
T
)
{
var
(
modeWait
=
storagev1
.
VolumeBindingWaitForFirstConsumer
class0
=
"Class_0"
classWait
=
"Class_Wait"
classImmediate
=
"Class_Immediate"
)
classInfo
:=
FakeStorageClassInfo
{
{
ObjectMeta
:
metav1
.
ObjectMeta
{
Name
:
classImmediate
},
},
{
ObjectMeta
:
metav1
.
ObjectMeta
{
Name
:
classWait
},
VolumeBindingMode
:
&
modeWait
,
},
}
pvInfo
:=
FakePersistentVolumeInfo
{
{
ObjectMeta
:
metav1
.
ObjectMeta
{
Name
:
"Vol_1"
,
Labels
:
map
[
string
]
string
{
kubeletapis
.
LabelZoneFailureDomain
:
"us-west1-a"
}},
},
}
pvcInfo
:=
FakePersistentVolumeClaimInfo
{
{
ObjectMeta
:
metav1
.
ObjectMeta
{
Name
:
"PVC_1"
,
Namespace
:
"default"
},
Spec
:
v1
.
PersistentVolumeClaimSpec
{
VolumeName
:
"Vol_1"
},
},
{
ObjectMeta
:
metav1
.
ObjectMeta
{
Name
:
"PVC_NoSC"
,
Namespace
:
"default"
},
Spec
:
v1
.
PersistentVolumeClaimSpec
{
StorageClassName
:
&
class0
},
},
{
ObjectMeta
:
metav1
.
ObjectMeta
{
Name
:
"PVC_EmptySC"
,
Namespace
:
"default"
},
},
{
ObjectMeta
:
metav1
.
ObjectMeta
{
Name
:
"PVC_WaitSC"
,
Namespace
:
"default"
},
Spec
:
v1
.
PersistentVolumeClaimSpec
{
StorageClassName
:
&
classWait
},
},
{
ObjectMeta
:
metav1
.
ObjectMeta
{
Name
:
"PVC_ImmediateSC"
,
Namespace
:
"default"
},
Spec
:
v1
.
PersistentVolumeClaimSpec
{
StorageClassName
:
&
classImmediate
},
},
}
testNode
:=
&
v1
.
Node
{
ObjectMeta
:
metav1
.
ObjectMeta
{
Name
:
"host1"
,
Labels
:
map
[
string
]
string
{
kubeletapis
.
LabelZoneFailureDomain
:
"us-west1-a"
,
"uselessLabel"
:
"none"
},
},
}
tests
:=
[]
struct
{
Name
string
Pod
*
v1
.
Pod
Fits
bool
Node
*
v1
.
Node
ExpectFailure
bool
}{
{
Name
:
"label zone failure domain matched"
,
Pod
:
createPodWithVolume
(
"pod_1"
,
"vol_1"
,
"PVC_1"
),
Node
:
testNode
,
Fits
:
true
,
},
{
Name
:
"unbound volume empty storage class"
,
Pod
:
createPodWithVolume
(
"pod_1"
,
"vol_1"
,
"PVC_EmptySC"
),
Node
:
testNode
,
Fits
:
false
,
ExpectFailure
:
true
,
},
{
Name
:
"unbound volume no storage class"
,
Pod
:
createPodWithVolume
(
"pod_1"
,
"vol_1"
,
"PVC_NoSC"
),
Node
:
testNode
,
Fits
:
false
,
ExpectFailure
:
true
,
},
{
Name
:
"unbound volume immediate binding mode"
,
Pod
:
createPodWithVolume
(
"pod_1"
,
"vol_1"
,
"PVC_ImmediateSC"
),
Node
:
testNode
,
Fits
:
false
,
ExpectFailure
:
true
,
},
{
Name
:
"unbound volume wait binding mode"
,
Pod
:
createPodWithVolume
(
"pod_1"
,
"vol_1"
,
"PVC_WaitSC"
),
Node
:
testNode
,
Fits
:
true
,
},
}
err
:=
utilfeature
.
DefaultFeatureGate
.
Set
(
"VolumeScheduling=true"
)
if
err
!=
nil
{
t
.
Fatalf
(
"Failed to enable feature gate for VolumeScheduling: %v"
,
err
)
}
for
_
,
test
:=
range
tests
{
fit
:=
NewVolumeZonePredicate
(
pvInfo
,
pvcInfo
,
classInfo
)
node
:=
&
schedulercache
.
NodeInfo
{}
node
.
SetNode
(
test
.
Node
)
fits
,
_
,
err
:=
fit
(
test
.
Pod
,
nil
,
node
)
if
!
test
.
ExpectFailure
&&
err
!=
nil
{
t
.
Errorf
(
"%s: unexpected error: %v"
,
test
.
Name
,
err
)
}
if
test
.
ExpectFailure
&&
err
==
nil
{
t
.
Errorf
(
"%s: expected error, got success"
,
test
.
Name
)
}
if
fits
!=
test
.
Fits
{
t
.
Errorf
(
"%s: expected %v got %v"
,
test
.
Name
,
test
.
Fits
,
fits
)
}
}
err
=
utilfeature
.
DefaultFeatureGate
.
Set
(
"VolumeScheduling=false"
)
if
err
!=
nil
{
t
.
Fatalf
(
"Failed to disable feature gate for VolumeScheduling: %v"
,
err
)
}
}
func
TestGetMaxVols
(
t
*
testing
.
T
)
{
func
TestGetMaxVols
(
t
*
testing
.
T
)
{
previousValue
:=
os
.
Getenv
(
KubeMaxPDVols
)
previousValue
:=
os
.
Getenv
(
KubeMaxPDVols
)
defaultValue
:=
39
defaultValue
:=
39
...
...
plugin/pkg/scheduler/algorithmprovider/defaults/compatibility_test.go
View file @
094841c6
...
@@ -337,8 +337,7 @@ func TestCompatibility_v1_Scheduler(t *testing.T) {
...
@@ -337,8 +337,7 @@ func TestCompatibility_v1_Scheduler(t *testing.T) {
{"name": "MatchInterPodAffinity"},
{"name": "MatchInterPodAffinity"},
{"name": "GeneralPredicates"},
{"name": "GeneralPredicates"},
{"name": "TestServiceAffinity", "argument": {"serviceAffinity" : {"labels" : ["region"]}}},
{"name": "TestServiceAffinity", "argument": {"serviceAffinity" : {"labels" : ["region"]}}},
{"name": "TestLabelsPresence", "argument": {"labelsPresence" : {"labels" : ["foo"], "presence":true}}},
{"name": "TestLabelsPresence", "argument": {"labelsPresence" : {"labels" : ["foo"], "presence":true}}}
{"name": "NoVolumeNodeConflict"}
],"priorities": [
],"priorities": [
{"name": "EqualPriority", "weight": 2},
{"name": "EqualPriority", "weight": 2},
{"name": "ImageLocalityPriority", "weight": 2},
{"name": "ImageLocalityPriority", "weight": 2},
...
@@ -370,7 +369,6 @@ func TestCompatibility_v1_Scheduler(t *testing.T) {
...
@@ -370,7 +369,6 @@ func TestCompatibility_v1_Scheduler(t *testing.T) {
{
Name
:
"GeneralPredicates"
},
{
Name
:
"GeneralPredicates"
},
{
Name
:
"TestServiceAffinity"
,
Argument
:
&
schedulerapi
.
PredicateArgument
{
ServiceAffinity
:
&
schedulerapi
.
ServiceAffinity
{
Labels
:
[]
string
{
"region"
}}}},
{
Name
:
"TestServiceAffinity"
,
Argument
:
&
schedulerapi
.
PredicateArgument
{
ServiceAffinity
:
&
schedulerapi
.
ServiceAffinity
{
Labels
:
[]
string
{
"region"
}}}},
{
Name
:
"TestLabelsPresence"
,
Argument
:
&
schedulerapi
.
PredicateArgument
{
LabelsPresence
:
&
schedulerapi
.
LabelsPresence
{
Labels
:
[]
string
{
"foo"
},
Presence
:
true
}}},
{
Name
:
"TestLabelsPresence"
,
Argument
:
&
schedulerapi
.
PredicateArgument
{
LabelsPresence
:
&
schedulerapi
.
LabelsPresence
{
Labels
:
[]
string
{
"foo"
},
Presence
:
true
}}},
{
Name
:
"NoVolumeNodeConflict"
},
},
},
Priorities
:
[]
schedulerapi
.
PriorityPolicy
{
Priorities
:
[]
schedulerapi
.
PriorityPolicy
{
{
Name
:
"EqualPriority"
,
Weight
:
2
},
{
Name
:
"EqualPriority"
,
Weight
:
2
},
...
@@ -409,8 +407,80 @@ func TestCompatibility_v1_Scheduler(t *testing.T) {
...
@@ -409,8 +407,80 @@ func TestCompatibility_v1_Scheduler(t *testing.T) {
{"name": "MatchInterPodAffinity"},
{"name": "MatchInterPodAffinity"},
{"name": "GeneralPredicates"},
{"name": "GeneralPredicates"},
{"name": "TestServiceAffinity", "argument": {"serviceAffinity" : {"labels" : ["region"]}}},
{"name": "TestServiceAffinity", "argument": {"serviceAffinity" : {"labels" : ["region"]}}},
{"name": "TestLabelsPresence", "argument": {"labelsPresence" : {"labels" : ["foo"], "presence":true}}},
{"name": "TestLabelsPresence", "argument": {"labelsPresence" : {"labels" : ["foo"], "presence":true}}}
{"name": "NoVolumeNodeConflict"}
],"priorities": [
{"name": "EqualPriority", "weight": 2},
{"name": "ImageLocalityPriority", "weight": 2},
{"name": "LeastRequestedPriority", "weight": 2},
{"name": "BalancedResourceAllocation", "weight": 2},
{"name": "SelectorSpreadPriority", "weight": 2},
{"name": "NodePreferAvoidPodsPriority", "weight": 2},
{"name": "NodeAffinityPriority", "weight": 2},
{"name": "TaintTolerationPriority", "weight": 2},
{"name": "InterPodAffinityPriority", "weight": 2},
{"name": "MostRequestedPriority", "weight": 2}
]
}`
,
ExpectedPolicy
:
schedulerapi
.
Policy
{
Predicates
:
[]
schedulerapi
.
PredicatePolicy
{
{
Name
:
"MatchNodeSelector"
},
{
Name
:
"PodFitsResources"
},
{
Name
:
"PodFitsHostPorts"
},
{
Name
:
"HostName"
},
{
Name
:
"NoDiskConflict"
},
{
Name
:
"NoVolumeZoneConflict"
},
{
Name
:
"PodToleratesNodeTaints"
},
{
Name
:
"CheckNodeMemoryPressure"
},
{
Name
:
"CheckNodeDiskPressure"
},
{
Name
:
"CheckNodeCondition"
},
{
Name
:
"MaxEBSVolumeCount"
},
{
Name
:
"MaxGCEPDVolumeCount"
},
{
Name
:
"MaxAzureDiskVolumeCount"
},
{
Name
:
"MatchInterPodAffinity"
},
{
Name
:
"GeneralPredicates"
},
{
Name
:
"TestServiceAffinity"
,
Argument
:
&
schedulerapi
.
PredicateArgument
{
ServiceAffinity
:
&
schedulerapi
.
ServiceAffinity
{
Labels
:
[]
string
{
"region"
}}}},
{
Name
:
"TestLabelsPresence"
,
Argument
:
&
schedulerapi
.
PredicateArgument
{
LabelsPresence
:
&
schedulerapi
.
LabelsPresence
{
Labels
:
[]
string
{
"foo"
},
Presence
:
true
}}},
},
Priorities
:
[]
schedulerapi
.
PriorityPolicy
{
{
Name
:
"EqualPriority"
,
Weight
:
2
},
{
Name
:
"ImageLocalityPriority"
,
Weight
:
2
},
{
Name
:
"LeastRequestedPriority"
,
Weight
:
2
},
{
Name
:
"BalancedResourceAllocation"
,
Weight
:
2
},
{
Name
:
"SelectorSpreadPriority"
,
Weight
:
2
},
{
Name
:
"NodePreferAvoidPodsPriority"
,
Weight
:
2
},
{
Name
:
"NodeAffinityPriority"
,
Weight
:
2
},
{
Name
:
"TaintTolerationPriority"
,
Weight
:
2
},
{
Name
:
"InterPodAffinityPriority"
,
Weight
:
2
},
{
Name
:
"MostRequestedPriority"
,
Weight
:
2
},
},
},
},
// Do not change this JSON after the corresponding release has been tagged.
// A failure indicates backwards compatibility with the specified release was broken.
"1.9"
:
{
JSON
:
`{
"kind": "Policy",
"apiVersion": "v1",
"predicates": [
{"name": "MatchNodeSelector"},
{"name": "PodFitsResources"},
{"name": "PodFitsHostPorts"},
{"name": "HostName"},
{"name": "NoDiskConflict"},
{"name": "NoVolumeZoneConflict"},
{"name": "PodToleratesNodeTaints"},
{"name": "CheckNodeMemoryPressure"},
{"name": "CheckNodeDiskPressure"},
{"name": "CheckNodeCondition"},
{"name": "MaxEBSVolumeCount"},
{"name": "MaxGCEPDVolumeCount"},
{"name": "MaxAzureDiskVolumeCount"},
{"name": "MatchInterPodAffinity"},
{"name": "GeneralPredicates"},
{"name": "CheckVolumeBinding"},
{"name": "TestServiceAffinity", "argument": {"serviceAffinity" : {"labels" : ["region"]}}},
{"name": "TestLabelsPresence", "argument": {"labelsPresence" : {"labels" : ["foo"], "presence":true}}}
],"priorities": [
],"priorities": [
{"name": "EqualPriority", "weight": 2},
{"name": "EqualPriority", "weight": 2},
{"name": "ImageLocalityPriority", "weight": 2},
{"name": "ImageLocalityPriority", "weight": 2},
...
@@ -441,9 +511,9 @@ func TestCompatibility_v1_Scheduler(t *testing.T) {
...
@@ -441,9 +511,9 @@ func TestCompatibility_v1_Scheduler(t *testing.T) {
{
Name
:
"MaxAzureDiskVolumeCount"
},
{
Name
:
"MaxAzureDiskVolumeCount"
},
{
Name
:
"MatchInterPodAffinity"
},
{
Name
:
"MatchInterPodAffinity"
},
{
Name
:
"GeneralPredicates"
},
{
Name
:
"GeneralPredicates"
},
{
Name
:
"CheckVolumeBinding"
},
{
Name
:
"TestServiceAffinity"
,
Argument
:
&
schedulerapi
.
PredicateArgument
{
ServiceAffinity
:
&
schedulerapi
.
ServiceAffinity
{
Labels
:
[]
string
{
"region"
}}}},
{
Name
:
"TestServiceAffinity"
,
Argument
:
&
schedulerapi
.
PredicateArgument
{
ServiceAffinity
:
&
schedulerapi
.
ServiceAffinity
{
Labels
:
[]
string
{
"region"
}}}},
{
Name
:
"TestLabelsPresence"
,
Argument
:
&
schedulerapi
.
PredicateArgument
{
LabelsPresence
:
&
schedulerapi
.
LabelsPresence
{
Labels
:
[]
string
{
"foo"
},
Presence
:
true
}}},
{
Name
:
"TestLabelsPresence"
,
Argument
:
&
schedulerapi
.
PredicateArgument
{
LabelsPresence
:
&
schedulerapi
.
LabelsPresence
{
Labels
:
[]
string
{
"foo"
},
Presence
:
true
}}},
{
Name
:
"NoVolumeNodeConflict"
},
},
},
Priorities
:
[]
schedulerapi
.
PriorityPolicy
{
Priorities
:
[]
schedulerapi
.
PriorityPolicy
{
{
Name
:
"EqualPriority"
,
Weight
:
2
},
{
Name
:
"EqualPriority"
,
Weight
:
2
},
...
...
plugin/pkg/scheduler/algorithmprovider/defaults/defaults.go
View file @
094841c6
...
@@ -114,7 +114,7 @@ func defaultPredicates() sets.String {
...
@@ -114,7 +114,7 @@ func defaultPredicates() sets.String {
factory
.
RegisterFitPredicateFactory
(
factory
.
RegisterFitPredicateFactory
(
"NoVolumeZoneConflict"
,
"NoVolumeZoneConflict"
,
func
(
args
factory
.
PluginFactoryArgs
)
algorithm
.
FitPredicate
{
func
(
args
factory
.
PluginFactoryArgs
)
algorithm
.
FitPredicate
{
return
predicates
.
NewVolumeZonePredicate
(
args
.
PVInfo
,
args
.
PVCInfo
)
return
predicates
.
NewVolumeZonePredicate
(
args
.
PVInfo
,
args
.
PVCInfo
,
args
.
StorageClassInfo
)
},
},
),
),
// Fit is determined by whether or not there would be too many AWS EBS volumes attached to the node
// Fit is determined by whether or not there would be too many AWS EBS volumes attached to the node
...
@@ -165,11 +165,11 @@ func defaultPredicates() sets.String {
...
@@ -165,11 +165,11 @@ func defaultPredicates() sets.String {
// Fit is determined based on whether a pod can tolerate all of the node's taints
// Fit is determined based on whether a pod can tolerate all of the node's taints
factory
.
RegisterFitPredicate
(
"PodToleratesNodeTaints"
,
predicates
.
PodToleratesNodeTaints
),
factory
.
RegisterFitPredicate
(
"PodToleratesNodeTaints"
,
predicates
.
PodToleratesNodeTaints
),
// Fit is determined by volume
zone
requirements.
// Fit is determined by volume
topology
requirements.
factory
.
RegisterFitPredicateFactory
(
factory
.
RegisterFitPredicateFactory
(
"NoVolumeNodeConflict"
,
predicates
.
CheckVolumeBinding
,
func
(
args
factory
.
PluginFactoryArgs
)
algorithm
.
FitPredicate
{
func
(
args
factory
.
PluginFactoryArgs
)
algorithm
.
FitPredicate
{
return
predicates
.
NewVolume
NodePredicate
(
args
.
PVInfo
,
args
.
PVCInfo
,
nil
)
return
predicates
.
NewVolume
BindingPredicate
(
args
.
VolumeBinder
)
},
},
),
),
)
)
...
...
plugin/pkg/scheduler/algorithmprovider/defaults/defaults_test.go
View file @
094841c6
...
@@ -20,6 +20,7 @@ import (
...
@@ -20,6 +20,7 @@ import (
"testing"
"testing"
"k8s.io/apimachinery/pkg/util/sets"
"k8s.io/apimachinery/pkg/util/sets"
"k8s.io/kubernetes/plugin/pkg/scheduler/algorithm/predicates"
)
)
func
TestCopyAndReplace
(
t
*
testing
.
T
)
{
func
TestCopyAndReplace
(
t
*
testing
.
T
)
{
...
@@ -75,9 +76,9 @@ func TestDefaultPredicates(t *testing.T) {
...
@@ -75,9 +76,9 @@ func TestDefaultPredicates(t *testing.T) {
"GeneralPredicates"
,
"GeneralPredicates"
,
"CheckNodeMemoryPressure"
,
"CheckNodeMemoryPressure"
,
"CheckNodeDiskPressure"
,
"CheckNodeDiskPressure"
,
"NoVolumeNodeConflict"
,
"CheckNodeCondition"
,
"CheckNodeCondition"
,
"PodToleratesNodeTaints"
,
"PodToleratesNodeTaints"
,
predicates
.
CheckVolumeBinding
,
)
)
if
expected
:=
defaultPredicates
();
!
result
.
Equal
(
expected
)
{
if
expected
:=
defaultPredicates
();
!
result
.
Equal
(
expected
)
{
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment