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
d36fc302
Commit
d36fc302
authored
Apr 14, 2018
by
Harry Zhang
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add integration test for disable preemption
parent
4f0bd412
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
140 additions
and
11 deletions
+140
-11
preemption_test.go
test/integration/scheduler/preemption_test.go
+88
-2
util.go
test/integration/scheduler/util.go
+52
-9
No files found.
test/integration/scheduler/preemption_test.go
View file @
d36fc302
...
@@ -41,8 +41,8 @@ import (
...
@@ -41,8 +41,8 @@ import (
var
lowPriority
,
mediumPriority
,
highPriority
=
int32
(
100
),
int32
(
200
),
int32
(
300
)
var
lowPriority
,
mediumPriority
,
highPriority
=
int32
(
100
),
int32
(
200
),
int32
(
300
)
func
waitForNominatedNodeName
(
cs
clientset
.
Interface
,
pod
*
v1
.
Pod
)
error
{
func
waitForNominatedNodeName
WithTimeout
(
cs
clientset
.
Interface
,
pod
*
v1
.
Pod
,
timeout
time
.
Duration
)
error
{
if
err
:=
wait
.
Poll
(
100
*
time
.
Millisecond
,
wait
.
ForeverTestT
imeout
,
func
()
(
bool
,
error
)
{
if
err
:=
wait
.
Poll
(
100
*
time
.
Millisecond
,
t
imeout
,
func
()
(
bool
,
error
)
{
pod
,
err
:=
cs
.
CoreV1
()
.
Pods
(
pod
.
Namespace
)
.
Get
(
pod
.
Name
,
metav1
.
GetOptions
{})
pod
,
err
:=
cs
.
CoreV1
()
.
Pods
(
pod
.
Namespace
)
.
Get
(
pod
.
Name
,
metav1
.
GetOptions
{})
if
err
!=
nil
{
if
err
!=
nil
{
return
false
,
err
return
false
,
err
...
@@ -57,6 +57,10 @@ func waitForNominatedNodeName(cs clientset.Interface, pod *v1.Pod) error {
...
@@ -57,6 +57,10 @@ func waitForNominatedNodeName(cs clientset.Interface, pod *v1.Pod) error {
return
nil
return
nil
}
}
func
waitForNominatedNodeName
(
cs
clientset
.
Interface
,
pod
*
v1
.
Pod
)
error
{
return
waitForNominatedNodeNameWithTimeout
(
cs
,
pod
,
wait
.
ForeverTestTimeout
)
}
// TestPreemption tests a few preemption scenarios.
// TestPreemption tests a few preemption scenarios.
func
TestPreemption
(
t
*
testing
.
T
)
{
func
TestPreemption
(
t
*
testing
.
T
)
{
// Enable PodPriority feature gate.
// Enable PodPriority feature gate.
...
@@ -285,6 +289,88 @@ func TestPreemption(t *testing.T) {
...
@@ -285,6 +289,88 @@ func TestPreemption(t *testing.T) {
}
}
}
}
// TestDisablePreemption tests disable pod preemption of scheduler works as expected.
func
TestDisablePreemption
(
t
*
testing
.
T
)
{
// Enable PodPriority feature gate.
utilfeature
.
DefaultFeatureGate
.
Set
(
fmt
.
Sprintf
(
"%s=true"
,
features
.
PodPriority
))
// Initialize scheduler, and disable preemption.
context
:=
initTestDisablePreemption
(
t
,
"disable-preemption"
)
defer
cleanupTest
(
t
,
context
)
cs
:=
context
.
clientSet
tests
:=
[]
struct
{
description
string
existingPods
[]
*
v1
.
Pod
pod
*
v1
.
Pod
}{
{
description
:
"pod preemption will not happen"
,
existingPods
:
[]
*
v1
.
Pod
{
initPausePod
(
context
.
clientSet
,
&
pausePodConfig
{
Name
:
"victim-pod"
,
Namespace
:
context
.
ns
.
Name
,
Priority
:
&
lowPriority
,
Resources
:
&
v1
.
ResourceRequirements
{
Requests
:
v1
.
ResourceList
{
v1
.
ResourceCPU
:
*
resource
.
NewMilliQuantity
(
400
,
resource
.
DecimalSI
),
v1
.
ResourceMemory
:
*
resource
.
NewQuantity
(
200
,
resource
.
BinarySI
)},
},
}),
},
pod
:
initPausePod
(
cs
,
&
pausePodConfig
{
Name
:
"preemptor-pod"
,
Namespace
:
context
.
ns
.
Name
,
Priority
:
&
highPriority
,
Resources
:
&
v1
.
ResourceRequirements
{
Requests
:
v1
.
ResourceList
{
v1
.
ResourceCPU
:
*
resource
.
NewMilliQuantity
(
300
,
resource
.
DecimalSI
),
v1
.
ResourceMemory
:
*
resource
.
NewQuantity
(
200
,
resource
.
BinarySI
)},
},
}),
},
}
// Create a node with some resources and a label.
nodeRes
:=
&
v1
.
ResourceList
{
v1
.
ResourcePods
:
*
resource
.
NewQuantity
(
32
,
resource
.
DecimalSI
),
v1
.
ResourceCPU
:
*
resource
.
NewMilliQuantity
(
500
,
resource
.
DecimalSI
),
v1
.
ResourceMemory
:
*
resource
.
NewQuantity
(
500
,
resource
.
BinarySI
),
}
_
,
err
:=
createNode
(
context
.
clientSet
,
"node1"
,
nodeRes
)
if
err
!=
nil
{
t
.
Fatalf
(
"Error creating nodes: %v"
,
err
)
}
for
_
,
test
:=
range
tests
{
pods
:=
make
([]
*
v1
.
Pod
,
len
(
test
.
existingPods
))
// Create and run existingPods.
for
i
,
p
:=
range
test
.
existingPods
{
pods
[
i
],
err
=
runPausePod
(
cs
,
p
)
if
err
!=
nil
{
t
.
Fatalf
(
"Test [%v]: Error running pause pod: %v"
,
test
.
description
,
err
)
}
}
// Create the "pod".
preemptor
,
err
:=
createPausePod
(
cs
,
test
.
pod
)
if
err
!=
nil
{
t
.
Errorf
(
"Error while creating high priority pod: %v"
,
err
)
}
// Ensure preemptor should keep unschedulable.
if
err
:=
waitForPodUnschedulable
(
cs
,
preemptor
);
err
!=
nil
{
t
.
Errorf
(
"Test [%v]: Preemptor %v should not become scheduled"
,
test
.
description
,
preemptor
.
Name
)
}
// Ensure preemptor should not be nominated.
if
err
:=
waitForNominatedNodeNameWithTimeout
(
cs
,
preemptor
,
5
*
time
.
Second
);
err
==
nil
{
t
.
Errorf
(
"Test [%v]: Preemptor %v should not be nominated"
,
test
.
description
,
preemptor
.
Name
)
}
// Cleanup
pods
=
append
(
pods
,
preemptor
)
cleanupPods
(
cs
,
t
,
pods
)
}
}
func
mkPriorityPodWithGrace
(
tc
*
TestContext
,
name
string
,
priority
int32
,
grace
int64
)
*
v1
.
Pod
{
func
mkPriorityPodWithGrace
(
tc
*
TestContext
,
name
string
,
priority
int32
,
grace
int64
)
*
v1
.
Pod
{
defaultPodRes
:=
&
v1
.
ResourceRequirements
{
Requests
:
v1
.
ResourceList
{
defaultPodRes
:=
&
v1
.
ResourceRequirements
{
Requests
:
v1
.
ResourceList
{
v1
.
ResourceCPU
:
*
resource
.
NewMilliQuantity
(
100
,
resource
.
DecimalSI
),
v1
.
ResourceCPU
:
*
resource
.
NewMilliQuantity
(
100
,
resource
.
DecimalSI
),
...
...
test/integration/scheduler/util.go
View file @
d36fc302
...
@@ -63,7 +63,7 @@ type TestContext struct {
...
@@ -63,7 +63,7 @@ type TestContext struct {
scheduler
*
scheduler
.
Scheduler
scheduler
*
scheduler
.
Scheduler
}
}
// createConfiguratorWithPodInformer create
a configurator for scheduler with given informer factory, custom name and pod inform
er.
// createConfiguratorWithPodInformer create
s a configurator for schedul
er.
func
createConfiguratorWithPodInformer
(
func
createConfiguratorWithPodInformer
(
schedulerName
string
,
schedulerName
string
,
clientSet
clientset
.
Interface
,
clientSet
clientset
.
Interface
,
...
@@ -116,7 +116,14 @@ func initTestMaster(t *testing.T, nsPrefix string, admission admission.Interface
...
@@ -116,7 +116,14 @@ func initTestMaster(t *testing.T, nsPrefix string, admission admission.Interface
}
}
// 2. Create kubeclient
// 2. Create kubeclient
context
.
clientSet
=
clientset
.
NewForConfigOrDie
(
&
restclient
.
Config
{
QPS
:
-
1
,
Host
:
s
.
URL
,
ContentConfig
:
restclient
.
ContentConfig
{
GroupVersion
:
testapi
.
Groups
[
v1
.
GroupName
]
.
GroupVersion
()}})
context
.
clientSet
=
clientset
.
NewForConfigOrDie
(
&
restclient
.
Config
{
QPS
:
-
1
,
Host
:
s
.
URL
,
ContentConfig
:
restclient
.
ContentConfig
{
GroupVersion
:
testapi
.
Groups
[
v1
.
GroupName
]
.
GroupVersion
(),
},
},
)
return
&
context
return
&
context
}
}
...
@@ -129,6 +136,21 @@ func initTestScheduler(
...
@@ -129,6 +136,21 @@ func initTestScheduler(
setPodInformer
bool
,
setPodInformer
bool
,
policy
*
schedulerapi
.
Policy
,
policy
*
schedulerapi
.
Policy
,
)
*
TestContext
{
)
*
TestContext
{
// Pod preemption is enabled by default scheduler configuration, but preemption only happens when PodPriority
// feature gate is enabled at the same time.
return
initTestSchedulerWithOptions
(
t
,
context
,
controllerCh
,
setPodInformer
,
policy
,
false
)
}
// initTestSchedulerWithOptions initializes a test environment and creates a scheduler with default
// configuration and other options.
func
initTestSchedulerWithOptions
(
t
*
testing
.
T
,
context
*
TestContext
,
controllerCh
chan
struct
{},
setPodInformer
bool
,
policy
*
schedulerapi
.
Policy
,
disablePreemption
bool
,
)
*
TestContext
{
// Enable EnableEquivalenceClassCache for all integration tests.
// Enable EnableEquivalenceClassCache for all integration tests.
defer
utilfeaturetesting
.
SetFeatureGateDuringTest
(
defer
utilfeaturetesting
.
SetFeatureGateDuringTest
(
t
,
t
,
...
@@ -167,19 +189,29 @@ func initTestScheduler(
...
@@ -167,19 +189,29 @@ func initTestScheduler(
context
.
schedulerConfig
.
StopEverything
=
controllerCh
context
.
schedulerConfig
.
StopEverything
=
controllerCh
}
}
// set DisablePreemption option
context
.
schedulerConfig
.
DisablePreemption
=
disablePreemption
// set setPodInformer if provided.
// set setPodInformer if provided.
if
setPodInformer
{
if
setPodInformer
{
go
podInformer
.
Informer
()
.
Run
(
context
.
schedulerConfig
.
StopEverything
)
go
podInformer
.
Informer
()
.
Run
(
context
.
schedulerConfig
.
StopEverything
)
}
}
eventBroadcaster
:=
record
.
NewBroadcaster
()
eventBroadcaster
:=
record
.
NewBroadcaster
()
context
.
schedulerConfig
.
Recorder
=
eventBroadcaster
.
NewRecorder
(
legacyscheme
.
Scheme
,
v1
.
EventSource
{
Component
:
v1
.
DefaultSchedulerName
})
context
.
schedulerConfig
.
Recorder
=
eventBroadcaster
.
NewRecorder
(
eventBroadcaster
.
StartRecordingToSink
(
&
clientv1core
.
EventSinkImpl
{
Interface
:
context
.
clientSet
.
CoreV1
()
.
Events
(
""
)})
legacyscheme
.
Scheme
,
v1
.
EventSource
{
Component
:
v1
.
DefaultSchedulerName
},
)
eventBroadcaster
.
StartRecordingToSink
(
&
clientv1core
.
EventSinkImpl
{
Interface
:
context
.
clientSet
.
CoreV1
()
.
Events
(
""
),
})
context
.
informerFactory
.
Start
(
context
.
schedulerConfig
.
StopEverything
)
context
.
informerFactory
.
Start
(
context
.
schedulerConfig
.
StopEverything
)
context
.
informerFactory
.
WaitForCacheSync
(
context
.
schedulerConfig
.
StopEverything
)
context
.
informerFactory
.
WaitForCacheSync
(
context
.
schedulerConfig
.
StopEverything
)
context
.
scheduler
,
err
=
scheduler
.
NewFromConfigurator
(
&
scheduler
.
FakeConfigurator
{
Config
:
context
.
schedulerConfig
},
nil
...
)
context
.
scheduler
,
err
=
scheduler
.
NewFromConfigurator
(
&
scheduler
.
FakeConfigurator
{
Config
:
context
.
schedulerConfig
},
nil
...
)
if
err
!=
nil
{
if
err
!=
nil
{
t
.
Fatalf
(
"Couldn't create scheduler: %v"
,
err
)
t
.
Fatalf
(
"Couldn't create scheduler: %v"
,
err
)
}
}
...
@@ -193,6 +225,13 @@ func initTest(t *testing.T, nsPrefix string) *TestContext {
...
@@ -193,6 +225,13 @@ func initTest(t *testing.T, nsPrefix string) *TestContext {
return
initTestScheduler
(
t
,
initTestMaster
(
t
,
nsPrefix
,
nil
),
nil
,
true
,
nil
)
return
initTestScheduler
(
t
,
initTestMaster
(
t
,
nsPrefix
,
nil
),
nil
,
true
,
nil
)
}
}
// initTestDisablePreemption initializes a test environment and creates master and scheduler with default
// configuration but with pod preemption disabled.
func
initTestDisablePreemption
(
t
*
testing
.
T
,
nsPrefix
string
)
*
TestContext
{
return
initTestSchedulerWithOptions
(
t
,
initTestMaster
(
t
,
nsPrefix
,
nil
),
nil
,
true
,
nil
,
true
)
}
// cleanupTest deletes the scheduler and the test namespace. It should be called
// cleanupTest deletes the scheduler and the test namespace. It should be called
// at the end of a test.
// at the end of a test.
func
cleanupTest
(
t
*
testing
.
T
,
context
*
TestContext
)
{
func
cleanupTest
(
t
*
testing
.
T
,
context
*
TestContext
)
{
...
@@ -206,7 +245,8 @@ func cleanupTest(t *testing.T, context *TestContext) {
...
@@ -206,7 +245,8 @@ func cleanupTest(t *testing.T, context *TestContext) {
// waitForReflection waits till the passFunc confirms that the object it expects
// waitForReflection waits till the passFunc confirms that the object it expects
// to see is in the store. Used to observe reflected events.
// to see is in the store. Used to observe reflected events.
func
waitForReflection
(
t
*
testing
.
T
,
nodeLister
corelisters
.
NodeLister
,
key
string
,
passFunc
func
(
n
interface
{})
bool
)
error
{
func
waitForReflection
(
t
*
testing
.
T
,
nodeLister
corelisters
.
NodeLister
,
key
string
,
passFunc
func
(
n
interface
{})
bool
)
error
{
nodes
:=
[]
*
v1
.
Node
{}
nodes
:=
[]
*
v1
.
Node
{}
err
:=
wait
.
Poll
(
time
.
Millisecond
*
100
,
wait
.
ForeverTestTimeout
,
func
()
(
bool
,
error
)
{
err
:=
wait
.
Poll
(
time
.
Millisecond
*
100
,
wait
.
ForeverTestTimeout
,
func
()
(
bool
,
error
)
{
n
,
err
:=
nodeLister
.
Get
(
key
)
n
,
err
:=
nodeLister
.
Get
(
key
)
...
@@ -345,7 +385,8 @@ func createPausePod(cs clientset.Interface, p *v1.Pod) (*v1.Pod, error) {
...
@@ -345,7 +385,8 @@ func createPausePod(cs clientset.Interface, p *v1.Pod) (*v1.Pod, error) {
// createPausePodWithResource creates a pod with "Pause" image and the given
// createPausePodWithResource creates a pod with "Pause" image and the given
// resources and returns its pointer and error status. The resource list can be
// resources and returns its pointer and error status. The resource list can be
// nil.
// nil.
func
createPausePodWithResource
(
cs
clientset
.
Interface
,
podName
string
,
nsName
string
,
res
*
v1
.
ResourceList
)
(
*
v1
.
Pod
,
error
)
{
func
createPausePodWithResource
(
cs
clientset
.
Interface
,
podName
string
,
nsName
string
,
res
*
v1
.
ResourceList
)
(
*
v1
.
Pod
,
error
)
{
var
conf
pausePodConfig
var
conf
pausePodConfig
if
res
==
nil
{
if
res
==
nil
{
conf
=
pausePodConfig
{
conf
=
pausePodConfig
{
...
@@ -439,7 +480,8 @@ func podUnschedulable(c clientset.Interface, podNamespace, podName string) wait.
...
@@ -439,7 +480,8 @@ func podUnschedulable(c clientset.Interface, podNamespace, podName string) wait.
return
false
,
nil
return
false
,
nil
}
}
_
,
cond
:=
podutil
.
GetPodCondition
(
&
pod
.
Status
,
v1
.
PodScheduled
)
_
,
cond
:=
podutil
.
GetPodCondition
(
&
pod
.
Status
,
v1
.
PodScheduled
)
return
cond
!=
nil
&&
cond
.
Status
==
v1
.
ConditionFalse
&&
cond
.
Reason
==
v1
.
PodReasonUnschedulable
,
nil
return
cond
!=
nil
&&
cond
.
Status
==
v1
.
ConditionFalse
&&
cond
.
Reason
==
v1
.
PodReasonUnschedulable
,
nil
}
}
}
}
...
@@ -481,7 +523,8 @@ func cleanupPods(cs clientset.Interface, t *testing.T, pods []*v1.Pod) {
...
@@ -481,7 +523,8 @@ func cleanupPods(cs clientset.Interface, t *testing.T, pods []*v1.Pod) {
}
}
}
}
for
_
,
p
:=
range
pods
{
for
_
,
p
:=
range
pods
{
if
err
:=
wait
.
Poll
(
time
.
Second
,
wait
.
ForeverTestTimeout
,
podDeleted
(
cs
,
p
.
Namespace
,
p
.
Name
));
err
!=
nil
{
if
err
:=
wait
.
Poll
(
time
.
Second
,
wait
.
ForeverTestTimeout
,
podDeleted
(
cs
,
p
.
Namespace
,
p
.
Name
));
err
!=
nil
{
t
.
Errorf
(
"error while waiting for pod %v/%v to get deleted: %v"
,
p
.
Namespace
,
p
.
Name
,
err
)
t
.
Errorf
(
"error while waiting for pod %v/%v to get deleted: %v"
,
p
.
Namespace
,
p
.
Name
,
err
)
}
}
}
}
...
...
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