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
70441459
Commit
70441459
authored
Dec 17, 2018
by
Bobby (Babak) Salamat
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Fix race in setting nominated node
parent
55814978
Expand all
Show whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
116 additions
and
20 deletions
+116
-20
generic_scheduler.go
pkg/scheduler/core/generic_scheduler.go
+2
-2
scheduling_queue.go
pkg/scheduler/internal/queue/scheduling_queue.go
+0
-0
scheduling_queue_test.go
pkg/scheduler/internal/queue/scheduling_queue_test.go
+106
-18
scheduler.go
pkg/scheduler/scheduler.go
+8
-0
No files found.
pkg/scheduler/core/generic_scheduler.go
View file @
70441459
...
...
@@ -362,7 +362,7 @@ func (g *genericScheduler) processPreemptionWithExtenders(
// worth the complexity, especially because we generally expect to have a very
// small number of nominated pods per node.
func
(
g
*
genericScheduler
)
getLowerPriorityNominatedPods
(
pod
*
v1
.
Pod
,
nodeName
string
)
[]
*
v1
.
Pod
{
pods
:=
g
.
schedulingQueue
.
Waiting
PodsForNode
(
nodeName
)
pods
:=
g
.
schedulingQueue
.
Nominated
PodsForNode
(
nodeName
)
if
len
(
pods
)
==
0
{
return
nil
...
...
@@ -509,7 +509,7 @@ func addNominatedPods(pod *v1.Pod, meta predicates.PredicateMetadata,
// This may happen only in tests.
return
false
,
meta
,
nodeInfo
}
nominatedPods
:=
queue
.
Waiting
PodsForNode
(
nodeInfo
.
Node
()
.
Name
)
nominatedPods
:=
queue
.
Nominated
PodsForNode
(
nodeInfo
.
Node
()
.
Name
)
if
nominatedPods
==
nil
||
len
(
nominatedPods
)
==
0
{
return
false
,
meta
,
nodeInfo
}
...
...
pkg/scheduler/internal/queue/scheduling_queue.go
View file @
70441459
This diff is collapsed.
Click to expand it.
pkg/scheduler/internal/queue/scheduling_queue_test.go
View file @
70441459
...
...
@@ -105,8 +105,14 @@ func TestPriorityQueue_Add(t *testing.T) {
if
err
:=
q
.
Add
(
&
highPriorityPod
);
err
!=
nil
{
t
.
Errorf
(
"add failed: %v"
,
err
)
}
expectedNominatedPods
:=
map
[
string
][]
*
v1
.
Pod
{
expectedNominatedPods
:=
&
nominatedPodMap
{
nominatedPodToNode
:
map
[
types
.
UID
]
string
{
medPriorityPod
.
UID
:
"node1"
,
unschedulablePod
.
UID
:
"node1"
,
},
nominatedPods
:
map
[
string
][]
*
v1
.
Pod
{
"node1"
:
{
&
medPriorityPod
,
&
unschedulablePod
},
},
}
if
!
reflect
.
DeepEqual
(
q
.
nominatedPods
,
expectedNominatedPods
)
{
t
.
Errorf
(
"Unexpected nominated map after adding pods. Expected: %v, got: %v"
,
expectedNominatedPods
,
q
.
nominatedPods
)
...
...
@@ -120,8 +126,8 @@ func TestPriorityQueue_Add(t *testing.T) {
if
p
,
err
:=
q
.
Pop
();
err
!=
nil
||
p
!=
&
unschedulablePod
{
t
.
Errorf
(
"Expected: %v after Pop, but got: %v"
,
unschedulablePod
.
Name
,
p
.
Name
)
}
if
len
(
q
.
nominatedPods
[
"node1"
])
!=
2
{
t
.
Errorf
(
"Expected medPriorityPod and unschedulablePod to be still present in nomindatePods: %v"
,
q
.
nominatedPods
[
"node1"
])
if
len
(
q
.
nominatedPods
.
nominatedPods
[
"node1"
])
!=
2
{
t
.
Errorf
(
"Expected medPriorityPod and unschedulablePod to be still present in nomindatePods: %v"
,
q
.
nominatedPods
.
nominatedPods
[
"node1"
])
}
}
...
...
@@ -131,8 +137,14 @@ func TestPriorityQueue_AddIfNotPresent(t *testing.T) {
q
.
AddIfNotPresent
(
&
highPriNominatedPod
)
// Must not add anything.
q
.
AddIfNotPresent
(
&
medPriorityPod
)
q
.
AddIfNotPresent
(
&
unschedulablePod
)
expectedNominatedPods
:=
map
[
string
][]
*
v1
.
Pod
{
expectedNominatedPods
:=
&
nominatedPodMap
{
nominatedPodToNode
:
map
[
types
.
UID
]
string
{
medPriorityPod
.
UID
:
"node1"
,
unschedulablePod
.
UID
:
"node1"
,
},
nominatedPods
:
map
[
string
][]
*
v1
.
Pod
{
"node1"
:
{
&
medPriorityPod
,
&
unschedulablePod
},
},
}
if
!
reflect
.
DeepEqual
(
q
.
nominatedPods
,
expectedNominatedPods
)
{
t
.
Errorf
(
"Unexpected nominated map after adding pods. Expected: %v, got: %v"
,
expectedNominatedPods
,
q
.
nominatedPods
)
...
...
@@ -143,8 +155,8 @@ func TestPriorityQueue_AddIfNotPresent(t *testing.T) {
if
p
,
err
:=
q
.
Pop
();
err
!=
nil
||
p
!=
&
unschedulablePod
{
t
.
Errorf
(
"Expected: %v after Pop, but got: %v"
,
unschedulablePod
.
Name
,
p
.
Name
)
}
if
len
(
q
.
nominatedPods
[
"node1"
])
!=
2
{
t
.
Errorf
(
"Expected medPriorityPod and unschedulablePod to be still present in nomindatePods: %v"
,
q
.
nominatedPods
[
"node1"
])
if
len
(
q
.
nominatedPods
.
nominatedPods
[
"node1"
])
!=
2
{
t
.
Errorf
(
"Expected medPriorityPod and unschedulablePod to be still present in nomindatePods: %v"
,
q
.
nominatedPods
.
nominatedPods
[
"node1"
])
}
if
q
.
unschedulableQ
.
get
(
&
highPriNominatedPod
)
!=
&
highPriNominatedPod
{
t
.
Errorf
(
"Pod %v was not found in the unschedulableQ."
,
highPriNominatedPod
.
Name
)
...
...
@@ -157,8 +169,15 @@ func TestPriorityQueue_AddUnschedulableIfNotPresent(t *testing.T) {
q
.
AddUnschedulableIfNotPresent
(
&
highPriNominatedPod
)
// Must not add anything.
q
.
AddUnschedulableIfNotPresent
(
&
medPriorityPod
)
// This should go to activeQ.
q
.
AddUnschedulableIfNotPresent
(
&
unschedulablePod
)
expectedNominatedPods
:=
map
[
string
][]
*
v1
.
Pod
{
expectedNominatedPods
:=
&
nominatedPodMap
{
nominatedPodToNode
:
map
[
types
.
UID
]
string
{
medPriorityPod
.
UID
:
"node1"
,
unschedulablePod
.
UID
:
"node1"
,
highPriNominatedPod
.
UID
:
"node1"
,
},
nominatedPods
:
map
[
string
][]
*
v1
.
Pod
{
"node1"
:
{
&
highPriNominatedPod
,
&
medPriorityPod
,
&
unschedulablePod
},
},
}
if
!
reflect
.
DeepEqual
(
q
.
nominatedPods
,
expectedNominatedPods
)
{
t
.
Errorf
(
"Unexpected nominated map after adding pods. Expected: %v, got: %v"
,
expectedNominatedPods
,
q
.
nominatedPods
)
...
...
@@ -169,7 +188,7 @@ func TestPriorityQueue_AddUnschedulableIfNotPresent(t *testing.T) {
if
p
,
err
:=
q
.
Pop
();
err
!=
nil
||
p
!=
&
medPriorityPod
{
t
.
Errorf
(
"Expected: %v after Pop, but got: %v"
,
medPriorityPod
.
Name
,
p
.
Name
)
}
if
len
(
q
.
nominatedPods
)
!=
1
{
if
len
(
q
.
nominatedPods
.
nominatedPods
)
!=
1
{
t
.
Errorf
(
"Expected nomindatePods to have one element: %v"
,
q
.
nominatedPods
)
}
if
q
.
unschedulableQ
.
get
(
&
unschedulablePod
)
!=
&
unschedulablePod
{
...
...
@@ -186,8 +205,8 @@ func TestPriorityQueue_Pop(t *testing.T) {
if
p
,
err
:=
q
.
Pop
();
err
!=
nil
||
p
!=
&
medPriorityPod
{
t
.
Errorf
(
"Expected: %v after Pop, but got: %v"
,
medPriorityPod
.
Name
,
p
.
Name
)
}
if
len
(
q
.
nominatedPods
[
"node1"
])
!=
1
{
t
.
Errorf
(
"Expected medPriorityPod to be present in nomindatePods: %v"
,
q
.
nominatedPods
[
"node1"
])
if
len
(
q
.
nominatedPods
.
nominatedPods
[
"node1"
])
!=
1
{
t
.
Errorf
(
"Expected medPriorityPod to be present in nomindatePods: %v"
,
q
.
nominatedPods
.
nominatedPods
[
"node1"
])
}
}()
q
.
Add
(
&
medPriorityPod
)
...
...
@@ -200,7 +219,7 @@ func TestPriorityQueue_Update(t *testing.T) {
if
_
,
exists
,
_
:=
q
.
activeQ
.
Get
(
&
highPriorityPod
);
!
exists
{
t
.
Errorf
(
"Expected %v to be added to activeQ."
,
highPriorityPod
.
Name
)
}
if
len
(
q
.
nominatedPods
)
!=
0
{
if
len
(
q
.
nominatedPods
.
nominatedPods
)
!=
0
{
t
.
Errorf
(
"Expected nomindatePods to be empty: %v"
,
q
.
nominatedPods
)
}
// Update highPriorityPod and add a nominatedNodeName to it.
...
...
@@ -208,7 +227,7 @@ func TestPriorityQueue_Update(t *testing.T) {
if
q
.
activeQ
.
Len
()
!=
1
{
t
.
Error
(
"Expected only one item in activeQ."
)
}
if
len
(
q
.
nominatedPods
)
!=
1
{
if
len
(
q
.
nominatedPods
.
nominatedPods
)
!=
1
{
t
.
Errorf
(
"Expected one item in nomindatePods map: %v"
,
q
.
nominatedPods
)
}
// Updating an unschedulable pod which is not in any of the two queues, should
...
...
@@ -243,13 +262,13 @@ func TestPriorityQueue_Delete(t *testing.T) {
if
_
,
exists
,
_
:=
q
.
activeQ
.
Get
(
&
highPriNominatedPod
);
exists
{
t
.
Errorf
(
"Didn't expect %v to be in activeQ."
,
highPriorityPod
.
Name
)
}
if
len
(
q
.
nominatedPods
)
!=
1
{
t
.
Errorf
(
"Expected nomindatePods to have only 'unschedulablePod': %v"
,
q
.
nominatedPods
)
if
len
(
q
.
nominatedPods
.
nominatedPods
)
!=
1
{
t
.
Errorf
(
"Expected nomindatePods to have only 'unschedulablePod': %v"
,
q
.
nominatedPods
.
nominatedPods
)
}
if
err
:=
q
.
Delete
(
&
unschedulablePod
);
err
!=
nil
{
t
.
Errorf
(
"delete failed: %v"
,
err
)
}
if
len
(
q
.
nominatedPods
)
!=
0
{
if
len
(
q
.
nominatedPods
.
nominatedPods
)
!=
0
{
t
.
Errorf
(
"Expected nomindatePods to be empty: %v"
,
q
.
nominatedPods
)
}
}
...
...
@@ -321,7 +340,7 @@ func TestPriorityQueue_AssignedPodAdded(t *testing.T) {
}
}
func
TestPriorityQueue_
Waiting
PodsForNode
(
t
*
testing
.
T
)
{
func
TestPriorityQueue_
Nominated
PodsForNode
(
t
*
testing
.
T
)
{
q
:=
NewPriorityQueue
(
nil
)
q
.
Add
(
&
medPriorityPod
)
q
.
Add
(
&
unschedulablePod
)
...
...
@@ -330,10 +349,10 @@ func TestPriorityQueue_WaitingPodsForNode(t *testing.T) {
t
.
Errorf
(
"Expected: %v after Pop, but got: %v"
,
highPriorityPod
.
Name
,
p
.
Name
)
}
expectedList
:=
[]
*
v1
.
Pod
{
&
medPriorityPod
,
&
unschedulablePod
}
if
!
reflect
.
DeepEqual
(
expectedList
,
q
.
Waiting
PodsForNode
(
"node1"
))
{
if
!
reflect
.
DeepEqual
(
expectedList
,
q
.
Nominated
PodsForNode
(
"node1"
))
{
t
.
Error
(
"Unexpected list of nominated Pods for node."
)
}
if
q
.
Waiting
PodsForNode
(
"node2"
)
!=
nil
{
if
q
.
Nominated
PodsForNode
(
"node2"
)
!=
nil
{
t
.
Error
(
"Expected list of nominated Pods for node2 to be empty."
)
}
}
...
...
@@ -354,6 +373,75 @@ func TestPriorityQueue_PendingPods(t *testing.T) {
}
}
func
TestPriorityQueue_UpdateNominatedPodForNode
(
t
*
testing
.
T
)
{
q
:=
NewPriorityQueue
(
nil
)
if
err
:=
q
.
Add
(
&
medPriorityPod
);
err
!=
nil
{
t
.
Errorf
(
"add failed: %v"
,
err
)
}
// Update unschedulablePod on a different node than specified in the pod.
q
.
UpdateNominatedPodForNode
(
&
unschedulablePod
,
"node5"
)
// Update nominated node name of a pod on a node that is not specified in the pod object.
q
.
UpdateNominatedPodForNode
(
&
highPriorityPod
,
"node2"
)
expectedNominatedPods
:=
&
nominatedPodMap
{
nominatedPodToNode
:
map
[
types
.
UID
]
string
{
medPriorityPod
.
UID
:
"node1"
,
highPriorityPod
.
UID
:
"node2"
,
unschedulablePod
.
UID
:
"node5"
,
},
nominatedPods
:
map
[
string
][]
*
v1
.
Pod
{
"node1"
:
{
&
medPriorityPod
},
"node2"
:
{
&
highPriorityPod
},
"node5"
:
{
&
unschedulablePod
},
},
}
if
!
reflect
.
DeepEqual
(
q
.
nominatedPods
,
expectedNominatedPods
)
{
t
.
Errorf
(
"Unexpected nominated map after adding pods. Expected: %v, got: %v"
,
expectedNominatedPods
,
q
.
nominatedPods
)
}
if
p
,
err
:=
q
.
Pop
();
err
!=
nil
||
p
!=
&
medPriorityPod
{
t
.
Errorf
(
"Expected: %v after Pop, but got: %v"
,
medPriorityPod
.
Name
,
p
.
Name
)
}
// List of nominated pods shouldn't change after popping them from the queue.
if
!
reflect
.
DeepEqual
(
q
.
nominatedPods
,
expectedNominatedPods
)
{
t
.
Errorf
(
"Unexpected nominated map after popping pods. Expected: %v, got: %v"
,
expectedNominatedPods
,
q
.
nominatedPods
)
}
// Update one of the nominated pods that doesn't have nominatedNodeName in the
// pod object. It should be updated correctly.
q
.
UpdateNominatedPodForNode
(
&
highPriorityPod
,
"node4"
)
expectedNominatedPods
=
&
nominatedPodMap
{
nominatedPodToNode
:
map
[
types
.
UID
]
string
{
medPriorityPod
.
UID
:
"node1"
,
highPriorityPod
.
UID
:
"node4"
,
unschedulablePod
.
UID
:
"node5"
,
},
nominatedPods
:
map
[
string
][]
*
v1
.
Pod
{
"node1"
:
{
&
medPriorityPod
},
"node4"
:
{
&
highPriorityPod
},
"node5"
:
{
&
unschedulablePod
},
},
}
if
!
reflect
.
DeepEqual
(
q
.
nominatedPods
,
expectedNominatedPods
)
{
t
.
Errorf
(
"Unexpected nominated map after updating pods. Expected: %v, got: %v"
,
expectedNominatedPods
,
q
.
nominatedPods
)
}
// Delete a nominated pod that doesn't have nominatedNodeName in the pod
// object. It should be deleted.
q
.
DeleteNominatedPodIfExists
(
&
highPriorityPod
)
expectedNominatedPods
=
&
nominatedPodMap
{
nominatedPodToNode
:
map
[
types
.
UID
]
string
{
medPriorityPod
.
UID
:
"node1"
,
unschedulablePod
.
UID
:
"node5"
,
},
nominatedPods
:
map
[
string
][]
*
v1
.
Pod
{
"node1"
:
{
&
medPriorityPod
},
"node5"
:
{
&
unschedulablePod
},
},
}
if
!
reflect
.
DeepEqual
(
q
.
nominatedPods
,
expectedNominatedPods
)
{
t
.
Errorf
(
"Unexpected nominated map after deleting pods. Expected: %v, got: %v"
,
expectedNominatedPods
,
q
.
nominatedPods
)
}
}
func
TestUnschedulablePodsMap
(
t
*
testing
.
T
)
{
var
pods
=
[]
*
v1
.
Pod
{
{
...
...
pkg/scheduler/scheduler.go
View file @
70441459
...
...
@@ -320,11 +320,19 @@ func (sched *Scheduler) preempt(preemptor *v1.Pod, scheduleErr error) (string, e
var
nodeName
=
""
if
node
!=
nil
{
nodeName
=
node
.
Name
// Update the scheduling queue with the nominated pod information. Without
// this, there would be a race condition between the next scheduling cycle
// and the time the scheduler receives a Pod Update for the nominated pod.
sched
.
config
.
SchedulingQueue
.
UpdateNominatedPodForNode
(
preemptor
,
nodeName
)
// Make a call to update nominated node name of the pod on the API server.
err
=
sched
.
config
.
PodPreemptor
.
SetNominatedNodeName
(
preemptor
,
nodeName
)
if
err
!=
nil
{
klog
.
Errorf
(
"Error in preemption process. Cannot update pod %v/%v annotations: %v"
,
preemptor
.
Namespace
,
preemptor
.
Name
,
err
)
sched
.
config
.
SchedulingQueue
.
DeleteNominatedPodIfExists
(
preemptor
)
return
""
,
err
}
for
_
,
victim
:=
range
victims
{
if
err
:=
sched
.
config
.
PodPreemptor
.
DeletePod
(
victim
);
err
!=
nil
{
klog
.
Errorf
(
"Error preempting pod %v/%v: %v"
,
victim
.
Namespace
,
victim
.
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