taint_manager_test.go 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795
  1. /*
  2. Copyright 2017 The Kubernetes Authors.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. package scheduler
  14. import (
  15. "context"
  16. "fmt"
  17. "sort"
  18. "sync"
  19. "testing"
  20. "time"
  21. v1 "k8s.io/api/core/v1"
  22. "k8s.io/apimachinery/pkg/fields"
  23. "k8s.io/apimachinery/pkg/labels"
  24. "k8s.io/client-go/kubernetes/fake"
  25. "k8s.io/kubernetes/pkg/controller/testutil"
  26. metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
  27. clienttesting "k8s.io/client-go/testing"
  28. )
  29. var timeForControllerToProgress = 500 * time.Millisecond
  30. func getPodFromClientset(clientset *fake.Clientset) GetPodFunc {
  31. return func(name, namespace string) (*v1.Pod, error) {
  32. return clientset.CoreV1().Pods(namespace).Get(context.TODO(), name, metav1.GetOptions{})
  33. }
  34. }
  35. func getPodsAssignedToNode(c *fake.Clientset) GetPodsByNodeNameFunc {
  36. return func(nodeName string) ([]*v1.Pod, error) {
  37. selector := fields.SelectorFromSet(fields.Set{"spec.nodeName": nodeName})
  38. pods, err := c.CoreV1().Pods(v1.NamespaceAll).List(context.TODO(), metav1.ListOptions{
  39. FieldSelector: selector.String(),
  40. LabelSelector: labels.Everything().String(),
  41. })
  42. if err != nil {
  43. return []*v1.Pod{}, fmt.Errorf("failed to get Pods assigned to node %v", nodeName)
  44. }
  45. rPods := make([]*v1.Pod, len(pods.Items))
  46. for i := range pods.Items {
  47. rPods[i] = &pods.Items[i]
  48. }
  49. return rPods, nil
  50. }
  51. }
  52. func getNodeFromClientset(clientset *fake.Clientset) GetNodeFunc {
  53. return func(name string) (*v1.Node, error) {
  54. return clientset.CoreV1().Nodes().Get(context.TODO(), name, metav1.GetOptions{})
  55. }
  56. }
  57. type podHolder struct {
  58. pod *v1.Pod
  59. sync.Mutex
  60. }
  61. func (p *podHolder) getPod(name, namespace string) (*v1.Pod, error) {
  62. p.Lock()
  63. defer p.Unlock()
  64. return p.pod, nil
  65. }
  66. func (p *podHolder) setPod(pod *v1.Pod) {
  67. p.Lock()
  68. defer p.Unlock()
  69. p.pod = pod
  70. }
  71. type nodeHolder struct {
  72. node *v1.Node
  73. }
  74. func (n *nodeHolder) getNode(name string) (*v1.Node, error) {
  75. return n.node, nil
  76. }
  77. func createNoExecuteTaint(index int) v1.Taint {
  78. now := metav1.Now()
  79. return v1.Taint{
  80. Key: "testTaint" + fmt.Sprintf("%v", index),
  81. Value: "test" + fmt.Sprintf("%v", index),
  82. Effect: v1.TaintEffectNoExecute,
  83. TimeAdded: &now,
  84. }
  85. }
  86. func addToleration(pod *v1.Pod, index int, duration int64) *v1.Pod {
  87. if pod.Annotations == nil {
  88. pod.Annotations = map[string]string{}
  89. }
  90. if duration < 0 {
  91. pod.Spec.Tolerations = []v1.Toleration{{Key: "testTaint" + fmt.Sprintf("%v", index), Value: "test" + fmt.Sprintf("%v", index), Effect: v1.TaintEffectNoExecute}}
  92. } else {
  93. pod.Spec.Tolerations = []v1.Toleration{{Key: "testTaint" + fmt.Sprintf("%v", index), Value: "test" + fmt.Sprintf("%v", index), Effect: v1.TaintEffectNoExecute, TolerationSeconds: &duration}}
  94. }
  95. return pod
  96. }
  97. func addTaintsToNode(node *v1.Node, key, value string, indices []int) *v1.Node {
  98. taints := []v1.Taint{}
  99. for _, index := range indices {
  100. taints = append(taints, createNoExecuteTaint(index))
  101. }
  102. node.Spec.Taints = taints
  103. return node
  104. }
  105. type timestampedPod struct {
  106. names []string
  107. timestamp time.Duration
  108. }
  109. type durationSlice []timestampedPod
  110. func (a durationSlice) Len() int { return len(a) }
  111. func (a durationSlice) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
  112. func (a durationSlice) Less(i, j int) bool { return a[i].timestamp < a[j].timestamp }
  113. func TestFilterNoExecuteTaints(t *testing.T) {
  114. taints := []v1.Taint{
  115. {
  116. Key: "one",
  117. Value: "one",
  118. Effect: v1.TaintEffectNoExecute,
  119. },
  120. {
  121. Key: "two",
  122. Value: "two",
  123. Effect: v1.TaintEffectNoSchedule,
  124. },
  125. }
  126. taints = getNoExecuteTaints(taints)
  127. if len(taints) != 1 || taints[0].Key != "one" {
  128. t.Errorf("Filtering doesn't work. Got %v", taints)
  129. }
  130. }
  131. func TestCreatePod(t *testing.T) {
  132. testCases := []struct {
  133. description string
  134. pod *v1.Pod
  135. taintedNodes map[string][]v1.Taint
  136. expectDelete bool
  137. }{
  138. {
  139. description: "not scheduled - ignore",
  140. pod: testutil.NewPod("pod1", ""),
  141. taintedNodes: map[string][]v1.Taint{},
  142. expectDelete: false,
  143. },
  144. {
  145. description: "scheduled on untainted Node",
  146. pod: testutil.NewPod("pod1", "node1"),
  147. taintedNodes: map[string][]v1.Taint{},
  148. expectDelete: false,
  149. },
  150. {
  151. description: "schedule on tainted Node",
  152. pod: testutil.NewPod("pod1", "node1"),
  153. taintedNodes: map[string][]v1.Taint{
  154. "node1": {createNoExecuteTaint(1)},
  155. },
  156. expectDelete: true,
  157. },
  158. {
  159. description: "schedule on tainted Node with finite toleration",
  160. pod: addToleration(testutil.NewPod("pod1", "node1"), 1, 100),
  161. taintedNodes: map[string][]v1.Taint{
  162. "node1": {createNoExecuteTaint(1)},
  163. },
  164. expectDelete: false,
  165. },
  166. {
  167. description: "schedule on tainted Node with infinite toleration",
  168. pod: addToleration(testutil.NewPod("pod1", "node1"), 1, -1),
  169. taintedNodes: map[string][]v1.Taint{
  170. "node1": {createNoExecuteTaint(1)},
  171. },
  172. expectDelete: false,
  173. },
  174. {
  175. description: "schedule on tainted Node with infinite ivalid toleration",
  176. pod: addToleration(testutil.NewPod("pod1", "node1"), 2, -1),
  177. taintedNodes: map[string][]v1.Taint{
  178. "node1": {createNoExecuteTaint(1)},
  179. },
  180. expectDelete: true,
  181. },
  182. }
  183. for _, item := range testCases {
  184. stopCh := make(chan struct{})
  185. fakeClientset := fake.NewSimpleClientset()
  186. controller := NewNoExecuteTaintManager(fakeClientset, (&podHolder{pod: item.pod}).getPod, getNodeFromClientset(fakeClientset), getPodsAssignedToNode(fakeClientset))
  187. controller.recorder = testutil.NewFakeRecorder()
  188. go controller.Run(stopCh)
  189. controller.taintedNodes = item.taintedNodes
  190. controller.PodUpdated(nil, item.pod)
  191. // wait a bit
  192. time.Sleep(timeForControllerToProgress)
  193. podDeleted := false
  194. for _, action := range fakeClientset.Actions() {
  195. if action.GetVerb() == "delete" && action.GetResource().Resource == "pods" {
  196. podDeleted = true
  197. }
  198. }
  199. if podDeleted != item.expectDelete {
  200. t.Errorf("%v: Unexpected test result. Expected delete %v, got %v", item.description, item.expectDelete, podDeleted)
  201. }
  202. close(stopCh)
  203. }
  204. }
  205. func TestDeletePod(t *testing.T) {
  206. stopCh := make(chan struct{})
  207. fakeClientset := fake.NewSimpleClientset()
  208. controller := NewNoExecuteTaintManager(fakeClientset, getPodFromClientset(fakeClientset), getNodeFromClientset(fakeClientset), getPodsAssignedToNode(fakeClientset))
  209. controller.recorder = testutil.NewFakeRecorder()
  210. go controller.Run(stopCh)
  211. controller.taintedNodes = map[string][]v1.Taint{
  212. "node1": {createNoExecuteTaint(1)},
  213. }
  214. controller.PodUpdated(testutil.NewPod("pod1", "node1"), nil)
  215. // wait a bit to see if nothing will panic
  216. time.Sleep(timeForControllerToProgress)
  217. close(stopCh)
  218. }
  219. func TestUpdatePod(t *testing.T) {
  220. testCases := []struct {
  221. description string
  222. prevPod *v1.Pod
  223. newPod *v1.Pod
  224. taintedNodes map[string][]v1.Taint
  225. expectDelete bool
  226. additionalSleep time.Duration
  227. }{
  228. {
  229. description: "scheduling onto tainted Node",
  230. prevPod: testutil.NewPod("pod1", ""),
  231. newPod: testutil.NewPod("pod1", "node1"),
  232. taintedNodes: map[string][]v1.Taint{
  233. "node1": {createNoExecuteTaint(1)},
  234. },
  235. expectDelete: true,
  236. },
  237. {
  238. description: "scheduling onto tainted Node with toleration",
  239. prevPod: addToleration(testutil.NewPod("pod1", ""), 1, -1),
  240. newPod: addToleration(testutil.NewPod("pod1", "node1"), 1, -1),
  241. taintedNodes: map[string][]v1.Taint{
  242. "node1": {createNoExecuteTaint(1)},
  243. },
  244. expectDelete: false,
  245. },
  246. {
  247. description: "removing toleration",
  248. prevPod: addToleration(testutil.NewPod("pod1", "node1"), 1, 100),
  249. newPod: testutil.NewPod("pod1", "node1"),
  250. taintedNodes: map[string][]v1.Taint{
  251. "node1": {createNoExecuteTaint(1)},
  252. },
  253. expectDelete: true,
  254. },
  255. {
  256. description: "lengthening toleration shouldn't work",
  257. prevPod: addToleration(testutil.NewPod("pod1", "node1"), 1, 1),
  258. newPod: addToleration(testutil.NewPod("pod1", "node1"), 1, 100),
  259. taintedNodes: map[string][]v1.Taint{
  260. "node1": {createNoExecuteTaint(1)},
  261. },
  262. expectDelete: true,
  263. additionalSleep: 1500 * time.Millisecond,
  264. },
  265. }
  266. for _, item := range testCases {
  267. stopCh := make(chan struct{})
  268. fakeClientset := fake.NewSimpleClientset()
  269. holder := &podHolder{}
  270. controller := NewNoExecuteTaintManager(fakeClientset, holder.getPod, getNodeFromClientset(fakeClientset), getPodsAssignedToNode(fakeClientset))
  271. controller.recorder = testutil.NewFakeRecorder()
  272. go controller.Run(stopCh)
  273. controller.taintedNodes = item.taintedNodes
  274. holder.setPod(item.prevPod)
  275. controller.PodUpdated(nil, item.prevPod)
  276. fakeClientset.ClearActions()
  277. time.Sleep(timeForControllerToProgress)
  278. holder.setPod(item.newPod)
  279. controller.PodUpdated(item.prevPod, item.newPod)
  280. // wait a bit
  281. time.Sleep(timeForControllerToProgress)
  282. if item.additionalSleep > 0 {
  283. time.Sleep(item.additionalSleep)
  284. }
  285. podDeleted := false
  286. for _, action := range fakeClientset.Actions() {
  287. if action.GetVerb() == "delete" && action.GetResource().Resource == "pods" {
  288. podDeleted = true
  289. }
  290. }
  291. if podDeleted != item.expectDelete {
  292. t.Errorf("%v: Unexpected test result. Expected delete %v, got %v", item.description, item.expectDelete, podDeleted)
  293. }
  294. close(stopCh)
  295. }
  296. }
  297. func TestCreateNode(t *testing.T) {
  298. testCases := []struct {
  299. description string
  300. pods []v1.Pod
  301. node *v1.Node
  302. expectDelete bool
  303. }{
  304. {
  305. description: "Creating Node matching already assigned Pod",
  306. pods: []v1.Pod{
  307. *testutil.NewPod("pod1", "node1"),
  308. },
  309. node: testutil.NewNode("node1"),
  310. expectDelete: false,
  311. },
  312. {
  313. description: "Creating tainted Node matching already assigned Pod",
  314. pods: []v1.Pod{
  315. *testutil.NewPod("pod1", "node1"),
  316. },
  317. node: addTaintsToNode(testutil.NewNode("node1"), "testTaint1", "taint1", []int{1}),
  318. expectDelete: true,
  319. },
  320. {
  321. description: "Creating tainted Node matching already assigned tolerating Pod",
  322. pods: []v1.Pod{
  323. *addToleration(testutil.NewPod("pod1", "node1"), 1, -1),
  324. },
  325. node: addTaintsToNode(testutil.NewNode("node1"), "testTaint1", "taint1", []int{1}),
  326. expectDelete: false,
  327. },
  328. }
  329. for _, item := range testCases {
  330. stopCh := make(chan struct{})
  331. fakeClientset := fake.NewSimpleClientset(&v1.PodList{Items: item.pods})
  332. controller := NewNoExecuteTaintManager(fakeClientset, getPodFromClientset(fakeClientset), (&nodeHolder{item.node}).getNode, getPodsAssignedToNode(fakeClientset))
  333. controller.recorder = testutil.NewFakeRecorder()
  334. go controller.Run(stopCh)
  335. controller.NodeUpdated(nil, item.node)
  336. // wait a bit
  337. time.Sleep(timeForControllerToProgress)
  338. podDeleted := false
  339. for _, action := range fakeClientset.Actions() {
  340. if action.GetVerb() == "delete" && action.GetResource().Resource == "pods" {
  341. podDeleted = true
  342. }
  343. }
  344. if podDeleted != item.expectDelete {
  345. t.Errorf("%v: Unexpected test result. Expected delete %v, got %v", item.description, item.expectDelete, podDeleted)
  346. }
  347. close(stopCh)
  348. }
  349. }
  350. func TestDeleteNode(t *testing.T) {
  351. stopCh := make(chan struct{})
  352. fakeClientset := fake.NewSimpleClientset()
  353. controller := NewNoExecuteTaintManager(fakeClientset, getPodFromClientset(fakeClientset), getNodeFromClientset(fakeClientset), getPodsAssignedToNode(fakeClientset))
  354. controller.recorder = testutil.NewFakeRecorder()
  355. controller.taintedNodes = map[string][]v1.Taint{
  356. "node1": {createNoExecuteTaint(1)},
  357. }
  358. go controller.Run(stopCh)
  359. controller.NodeUpdated(testutil.NewNode("node1"), nil)
  360. // wait a bit to see if nothing will panic
  361. time.Sleep(timeForControllerToProgress)
  362. controller.taintedNodesLock.Lock()
  363. if _, ok := controller.taintedNodes["node1"]; ok {
  364. t.Error("Node should have been deleted from taintedNodes list")
  365. }
  366. controller.taintedNodesLock.Unlock()
  367. close(stopCh)
  368. }
  369. func TestUpdateNode(t *testing.T) {
  370. testCases := []struct {
  371. description string
  372. pods []v1.Pod
  373. oldNode *v1.Node
  374. newNode *v1.Node
  375. expectDelete bool
  376. additionalSleep time.Duration
  377. }{
  378. {
  379. description: "Added taint",
  380. pods: []v1.Pod{
  381. *testutil.NewPod("pod1", "node1"),
  382. },
  383. oldNode: testutil.NewNode("node1"),
  384. newNode: addTaintsToNode(testutil.NewNode("node1"), "testTaint1", "taint1", []int{1}),
  385. expectDelete: true,
  386. },
  387. {
  388. description: "Added tolerated taint",
  389. pods: []v1.Pod{
  390. *addToleration(testutil.NewPod("pod1", "node1"), 1, 100),
  391. },
  392. oldNode: testutil.NewNode("node1"),
  393. newNode: addTaintsToNode(testutil.NewNode("node1"), "testTaint1", "taint1", []int{1}),
  394. expectDelete: false,
  395. },
  396. {
  397. description: "Only one added taint tolerated",
  398. pods: []v1.Pod{
  399. *addToleration(testutil.NewPod("pod1", "node1"), 1, 100),
  400. },
  401. oldNode: testutil.NewNode("node1"),
  402. newNode: addTaintsToNode(testutil.NewNode("node1"), "testTaint1", "taint1", []int{1, 2}),
  403. expectDelete: true,
  404. },
  405. {
  406. description: "Taint removed",
  407. pods: []v1.Pod{
  408. *addToleration(testutil.NewPod("pod1", "node1"), 1, 1),
  409. },
  410. oldNode: addTaintsToNode(testutil.NewNode("node1"), "testTaint1", "taint1", []int{1}),
  411. newNode: testutil.NewNode("node1"),
  412. expectDelete: false,
  413. additionalSleep: 1500 * time.Millisecond,
  414. },
  415. {
  416. description: "Pod with multiple tolerations are evicted when first one runs out",
  417. pods: []v1.Pod{
  418. {
  419. ObjectMeta: metav1.ObjectMeta{
  420. Namespace: "default",
  421. Name: "pod1",
  422. },
  423. Spec: v1.PodSpec{
  424. NodeName: "node1",
  425. Tolerations: []v1.Toleration{
  426. {Key: "testTaint1", Value: "test1", Effect: v1.TaintEffectNoExecute, TolerationSeconds: &[]int64{1}[0]},
  427. {Key: "testTaint2", Value: "test2", Effect: v1.TaintEffectNoExecute, TolerationSeconds: &[]int64{100}[0]},
  428. },
  429. },
  430. Status: v1.PodStatus{
  431. Conditions: []v1.PodCondition{
  432. {
  433. Type: v1.PodReady,
  434. Status: v1.ConditionTrue,
  435. },
  436. },
  437. },
  438. },
  439. },
  440. oldNode: testutil.NewNode("node1"),
  441. newNode: addTaintsToNode(testutil.NewNode("node1"), "testTaint1", "taint1", []int{1, 2}),
  442. expectDelete: true,
  443. additionalSleep: 1500 * time.Millisecond,
  444. },
  445. }
  446. for _, item := range testCases {
  447. stopCh := make(chan struct{})
  448. fakeClientset := fake.NewSimpleClientset(&v1.PodList{Items: item.pods})
  449. controller := NewNoExecuteTaintManager(fakeClientset, getPodFromClientset(fakeClientset), (&nodeHolder{item.newNode}).getNode, getPodsAssignedToNode(fakeClientset))
  450. controller.recorder = testutil.NewFakeRecorder()
  451. go controller.Run(stopCh)
  452. controller.NodeUpdated(item.oldNode, item.newNode)
  453. // wait a bit
  454. time.Sleep(timeForControllerToProgress)
  455. if item.additionalSleep > 0 {
  456. time.Sleep(item.additionalSleep)
  457. }
  458. podDeleted := false
  459. for _, action := range fakeClientset.Actions() {
  460. if action.GetVerb() == "delete" && action.GetResource().Resource == "pods" {
  461. podDeleted = true
  462. }
  463. }
  464. if podDeleted != item.expectDelete {
  465. t.Errorf("%v: Unexpected test result. Expected delete %v, got %v", item.description, item.expectDelete, podDeleted)
  466. }
  467. close(stopCh)
  468. }
  469. }
  470. func TestUpdateNodeWithMultiplePods(t *testing.T) {
  471. testCases := []struct {
  472. description string
  473. pods []v1.Pod
  474. oldNode *v1.Node
  475. newNode *v1.Node
  476. expectedDeleteTimes durationSlice
  477. }{
  478. {
  479. description: "Pods with different toleration times are evicted appropriately",
  480. pods: []v1.Pod{
  481. *testutil.NewPod("pod1", "node1"),
  482. *addToleration(testutil.NewPod("pod2", "node1"), 1, 1),
  483. *addToleration(testutil.NewPod("pod3", "node1"), 1, -1),
  484. },
  485. oldNode: testutil.NewNode("node1"),
  486. newNode: addTaintsToNode(testutil.NewNode("node1"), "testTaint1", "taint1", []int{1}),
  487. expectedDeleteTimes: durationSlice{
  488. {[]string{"pod1"}, 0},
  489. {[]string{"pod2"}, time.Second},
  490. },
  491. },
  492. {
  493. description: "Evict all pods not matching all taints instantly",
  494. pods: []v1.Pod{
  495. *testutil.NewPod("pod1", "node1"),
  496. *addToleration(testutil.NewPod("pod2", "node1"), 1, 1),
  497. *addToleration(testutil.NewPod("pod3", "node1"), 1, -1),
  498. },
  499. oldNode: testutil.NewNode("node1"),
  500. newNode: addTaintsToNode(testutil.NewNode("node1"), "testTaint1", "taint1", []int{1, 2}),
  501. expectedDeleteTimes: durationSlice{
  502. {[]string{"pod1", "pod2", "pod3"}, 0},
  503. },
  504. },
  505. }
  506. for _, item := range testCases {
  507. t.Logf("Starting testcase %q", item.description)
  508. stopCh := make(chan struct{})
  509. fakeClientset := fake.NewSimpleClientset(&v1.PodList{Items: item.pods})
  510. sort.Sort(item.expectedDeleteTimes)
  511. controller := NewNoExecuteTaintManager(fakeClientset, getPodFromClientset(fakeClientset), (&nodeHolder{item.newNode}).getNode, getPodsAssignedToNode(fakeClientset))
  512. controller.recorder = testutil.NewFakeRecorder()
  513. go controller.Run(stopCh)
  514. controller.NodeUpdated(item.oldNode, item.newNode)
  515. startedAt := time.Now()
  516. for i := range item.expectedDeleteTimes {
  517. if i == 0 || item.expectedDeleteTimes[i-1].timestamp != item.expectedDeleteTimes[i].timestamp {
  518. // compute a grace duration to give controller time to process updates. Choose big
  519. // enough intervals in the test cases above to avoid flakes.
  520. var increment time.Duration
  521. if i == len(item.expectedDeleteTimes)-1 || item.expectedDeleteTimes[i+1].timestamp == item.expectedDeleteTimes[i].timestamp {
  522. increment = 500 * time.Millisecond
  523. } else {
  524. increment = ((item.expectedDeleteTimes[i+1].timestamp - item.expectedDeleteTimes[i].timestamp) / time.Duration(2))
  525. }
  526. sleepTime := item.expectedDeleteTimes[i].timestamp - time.Since(startedAt) + increment
  527. if sleepTime < 0 {
  528. sleepTime = 0
  529. }
  530. t.Logf("Sleeping for %v", sleepTime)
  531. time.Sleep(sleepTime)
  532. }
  533. for delay, podName := range item.expectedDeleteTimes[i].names {
  534. deleted := false
  535. for _, action := range fakeClientset.Actions() {
  536. deleteAction, ok := action.(clienttesting.DeleteActionImpl)
  537. if !ok {
  538. t.Logf("Found not-delete action with verb %v. Ignoring.", action.GetVerb())
  539. continue
  540. }
  541. if deleteAction.GetResource().Resource != "pods" {
  542. continue
  543. }
  544. if podName == deleteAction.GetName() {
  545. deleted = true
  546. }
  547. }
  548. if !deleted {
  549. t.Errorf("Failed to deleted pod %v after %v", podName, delay)
  550. }
  551. }
  552. for _, action := range fakeClientset.Actions() {
  553. deleteAction, ok := action.(clienttesting.DeleteActionImpl)
  554. if !ok {
  555. t.Logf("Found not-delete action with verb %v. Ignoring.", action.GetVerb())
  556. continue
  557. }
  558. if deleteAction.GetResource().Resource != "pods" {
  559. continue
  560. }
  561. deletedPodName := deleteAction.GetName()
  562. expected := false
  563. for _, podName := range item.expectedDeleteTimes[i].names {
  564. if podName == deletedPodName {
  565. expected = true
  566. }
  567. }
  568. if !expected {
  569. t.Errorf("Pod %v was deleted even though it shouldn't have", deletedPodName)
  570. }
  571. }
  572. fakeClientset.ClearActions()
  573. }
  574. close(stopCh)
  575. }
  576. }
  577. func TestGetMinTolerationTime(t *testing.T) {
  578. one := int64(1)
  579. two := int64(2)
  580. oneSec := 1 * time.Second
  581. tests := []struct {
  582. tolerations []v1.Toleration
  583. expected time.Duration
  584. }{
  585. {
  586. tolerations: []v1.Toleration{},
  587. expected: 0,
  588. },
  589. {
  590. tolerations: []v1.Toleration{
  591. {
  592. TolerationSeconds: nil,
  593. },
  594. },
  595. expected: -1,
  596. },
  597. {
  598. tolerations: []v1.Toleration{
  599. {
  600. TolerationSeconds: &one,
  601. },
  602. {
  603. TolerationSeconds: &two,
  604. },
  605. },
  606. expected: oneSec,
  607. },
  608. {
  609. tolerations: []v1.Toleration{
  610. {
  611. TolerationSeconds: &one,
  612. },
  613. {
  614. TolerationSeconds: nil,
  615. },
  616. },
  617. expected: oneSec,
  618. },
  619. {
  620. tolerations: []v1.Toleration{
  621. {
  622. TolerationSeconds: nil,
  623. },
  624. {
  625. TolerationSeconds: &one,
  626. },
  627. },
  628. expected: oneSec,
  629. },
  630. }
  631. for _, test := range tests {
  632. got := getMinTolerationTime(test.tolerations)
  633. if got != test.expected {
  634. t.Errorf("Incorrect min toleration time: got %v, expected %v", got, test.expected)
  635. }
  636. }
  637. }
  638. // TestEventualConsistency verifies if getPodsAssignedToNode returns incomplete data
  639. // (e.g. due to watch latency), it will reconcile the remaining pods eventually.
  640. // This scenario is partially covered by TestUpdatePods, but given this is an important
  641. // property of TaintManager, it's better to have explicit test for this.
  642. func TestEventualConsistency(t *testing.T) {
  643. testCases := []struct {
  644. description string
  645. pods []v1.Pod
  646. prevPod *v1.Pod
  647. newPod *v1.Pod
  648. oldNode *v1.Node
  649. newNode *v1.Node
  650. expectDelete bool
  651. }{
  652. {
  653. description: "existing pod2 scheduled onto tainted Node",
  654. pods: []v1.Pod{
  655. *testutil.NewPod("pod1", "node1"),
  656. },
  657. prevPod: testutil.NewPod("pod2", ""),
  658. newPod: testutil.NewPod("pod2", "node1"),
  659. oldNode: testutil.NewNode("node1"),
  660. newNode: addTaintsToNode(testutil.NewNode("node1"), "testTaint1", "taint1", []int{1}),
  661. expectDelete: true,
  662. },
  663. {
  664. description: "existing pod2 with taint toleration scheduled onto tainted Node",
  665. pods: []v1.Pod{
  666. *testutil.NewPod("pod1", "node1"),
  667. },
  668. prevPod: addToleration(testutil.NewPod("pod2", ""), 1, 100),
  669. newPod: addToleration(testutil.NewPod("pod2", "node1"), 1, 100),
  670. oldNode: testutil.NewNode("node1"),
  671. newNode: addTaintsToNode(testutil.NewNode("node1"), "testTaint1", "taint1", []int{1}),
  672. expectDelete: false,
  673. },
  674. {
  675. description: "new pod2 created on tainted Node",
  676. pods: []v1.Pod{
  677. *testutil.NewPod("pod1", "node1"),
  678. },
  679. prevPod: nil,
  680. newPod: testutil.NewPod("pod2", "node1"),
  681. oldNode: testutil.NewNode("node1"),
  682. newNode: addTaintsToNode(testutil.NewNode("node1"), "testTaint1", "taint1", []int{1}),
  683. expectDelete: true,
  684. },
  685. {
  686. description: "new pod2 with tait toleration created on tainted Node",
  687. pods: []v1.Pod{
  688. *testutil.NewPod("pod1", "node1"),
  689. },
  690. prevPod: nil,
  691. newPod: addToleration(testutil.NewPod("pod2", "node1"), 1, 100),
  692. oldNode: testutil.NewNode("node1"),
  693. newNode: addTaintsToNode(testutil.NewNode("node1"), "testTaint1", "taint1", []int{1}),
  694. expectDelete: false,
  695. },
  696. }
  697. for _, item := range testCases {
  698. stopCh := make(chan struct{})
  699. fakeClientset := fake.NewSimpleClientset(&v1.PodList{Items: item.pods})
  700. holder := &podHolder{}
  701. controller := NewNoExecuteTaintManager(fakeClientset, holder.getPod, (&nodeHolder{item.newNode}).getNode, getPodsAssignedToNode(fakeClientset))
  702. controller.recorder = testutil.NewFakeRecorder()
  703. go controller.Run(stopCh)
  704. if item.prevPod != nil {
  705. holder.setPod(item.prevPod)
  706. controller.PodUpdated(nil, item.prevPod)
  707. }
  708. // First we simulate NodeUpdate that should delete 'pod1'. It doesn't know about 'pod2' yet.
  709. controller.NodeUpdated(item.oldNode, item.newNode)
  710. // TODO(mborsz): Remove this sleep and other sleeps in this file.
  711. time.Sleep(timeForControllerToProgress)
  712. podDeleted := false
  713. for _, action := range fakeClientset.Actions() {
  714. if action.GetVerb() == "delete" && action.GetResource().Resource == "pods" {
  715. podDeleted = true
  716. }
  717. }
  718. if !podDeleted {
  719. t.Errorf("%v: Unexpected test result. Expected delete, got: %v", item.description, podDeleted)
  720. }
  721. fakeClientset.ClearActions()
  722. // And now the delayed update of 'pod2' comes to the TaintManager. We should delete it as well.
  723. holder.setPod(item.newPod)
  724. controller.PodUpdated(item.prevPod, item.newPod)
  725. // wait a bit
  726. time.Sleep(timeForControllerToProgress)
  727. podDeleted = false
  728. for _, action := range fakeClientset.Actions() {
  729. if action.GetVerb() == "delete" && action.GetResource().Resource == "pods" {
  730. podDeleted = true
  731. }
  732. }
  733. if podDeleted != item.expectDelete {
  734. t.Errorf("%v: Unexpected test result. Expected delete %v, got %v", item.description, item.expectDelete, podDeleted)
  735. }
  736. close(stopCh)
  737. }
  738. }