extender_test.go 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300
  1. /*
  2. Copyright 2015 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. "fmt"
  16. "testing"
  17. "k8s.io/kubernetes/pkg/api"
  18. "k8s.io/kubernetes/plugin/pkg/scheduler/algorithm"
  19. schedulerapi "k8s.io/kubernetes/plugin/pkg/scheduler/api"
  20. "k8s.io/kubernetes/plugin/pkg/scheduler/schedulercache"
  21. schedulertesting "k8s.io/kubernetes/plugin/pkg/scheduler/testing"
  22. )
  23. type fitPredicate func(pod *api.Pod, node *api.Node) (bool, error)
  24. type priorityFunc func(pod *api.Pod, nodes []*api.Node) (*schedulerapi.HostPriorityList, error)
  25. type priorityConfig struct {
  26. function priorityFunc
  27. weight int
  28. }
  29. func errorPredicateExtender(pod *api.Pod, node *api.Node) (bool, error) {
  30. return false, fmt.Errorf("Some error")
  31. }
  32. func falsePredicateExtender(pod *api.Pod, node *api.Node) (bool, error) {
  33. return false, nil
  34. }
  35. func truePredicateExtender(pod *api.Pod, node *api.Node) (bool, error) {
  36. return true, nil
  37. }
  38. func machine1PredicateExtender(pod *api.Pod, node *api.Node) (bool, error) {
  39. if node.Name == "machine1" {
  40. return true, nil
  41. }
  42. return false, nil
  43. }
  44. func machine2PredicateExtender(pod *api.Pod, node *api.Node) (bool, error) {
  45. if node.Name == "machine2" {
  46. return true, nil
  47. }
  48. return false, nil
  49. }
  50. func errorPrioritizerExtender(pod *api.Pod, nodes []*api.Node) (*schedulerapi.HostPriorityList, error) {
  51. return &schedulerapi.HostPriorityList{}, fmt.Errorf("Some error")
  52. }
  53. func machine1PrioritizerExtender(pod *api.Pod, nodes []*api.Node) (*schedulerapi.HostPriorityList, error) {
  54. result := schedulerapi.HostPriorityList{}
  55. for _, node := range nodes {
  56. score := 1
  57. if node.Name == "machine1" {
  58. score = 10
  59. }
  60. result = append(result, schedulerapi.HostPriority{Host: node.Name, Score: score})
  61. }
  62. return &result, nil
  63. }
  64. func machine2PrioritizerExtender(pod *api.Pod, nodes []*api.Node) (*schedulerapi.HostPriorityList, error) {
  65. result := schedulerapi.HostPriorityList{}
  66. for _, node := range nodes {
  67. score := 1
  68. if node.Name == "machine2" {
  69. score = 10
  70. }
  71. result = append(result, schedulerapi.HostPriority{Host: node.Name, Score: score})
  72. }
  73. return &result, nil
  74. }
  75. func machine2Prioritizer(_ *api.Pod, nodeNameToInfo map[string]*schedulercache.NodeInfo, nodes []*api.Node) (schedulerapi.HostPriorityList, error) {
  76. result := []schedulerapi.HostPriority{}
  77. for _, node := range nodes {
  78. score := 1
  79. if node.Name == "machine2" {
  80. score = 10
  81. }
  82. result = append(result, schedulerapi.HostPriority{Host: node.Name, Score: score})
  83. }
  84. return result, nil
  85. }
  86. type FakeExtender struct {
  87. predicates []fitPredicate
  88. prioritizers []priorityConfig
  89. weight int
  90. }
  91. func (f *FakeExtender) Filter(pod *api.Pod, nodes []*api.Node) ([]*api.Node, schedulerapi.FailedNodesMap, error) {
  92. filtered := []*api.Node{}
  93. failedNodesMap := schedulerapi.FailedNodesMap{}
  94. for _, node := range nodes {
  95. fits := true
  96. for _, predicate := range f.predicates {
  97. fit, err := predicate(pod, node)
  98. if err != nil {
  99. return []*api.Node{}, schedulerapi.FailedNodesMap{}, err
  100. }
  101. if !fit {
  102. fits = false
  103. break
  104. }
  105. }
  106. if fits {
  107. filtered = append(filtered, node)
  108. } else {
  109. failedNodesMap[node.Name] = "FakeExtender failed"
  110. }
  111. }
  112. return filtered, failedNodesMap, nil
  113. }
  114. func (f *FakeExtender) Prioritize(pod *api.Pod, nodes []*api.Node) (*schedulerapi.HostPriorityList, int, error) {
  115. result := schedulerapi.HostPriorityList{}
  116. combinedScores := map[string]int{}
  117. for _, prioritizer := range f.prioritizers {
  118. weight := prioritizer.weight
  119. if weight == 0 {
  120. continue
  121. }
  122. priorityFunc := prioritizer.function
  123. prioritizedList, err := priorityFunc(pod, nodes)
  124. if err != nil {
  125. return &schedulerapi.HostPriorityList{}, 0, err
  126. }
  127. for _, hostEntry := range *prioritizedList {
  128. combinedScores[hostEntry.Host] += hostEntry.Score * weight
  129. }
  130. }
  131. for host, score := range combinedScores {
  132. result = append(result, schedulerapi.HostPriority{Host: host, Score: score})
  133. }
  134. return &result, f.weight, nil
  135. }
  136. func TestGenericSchedulerWithExtenders(t *testing.T) {
  137. tests := []struct {
  138. name string
  139. predicates map[string]algorithm.FitPredicate
  140. prioritizers []algorithm.PriorityConfig
  141. extenders []FakeExtender
  142. extenderPredicates []fitPredicate
  143. extenderPrioritizers []priorityConfig
  144. nodes []string
  145. pod *api.Pod
  146. pods []*api.Pod
  147. expectedHost string
  148. expectsErr bool
  149. }{
  150. {
  151. predicates: map[string]algorithm.FitPredicate{"true": truePredicate},
  152. prioritizers: []algorithm.PriorityConfig{{Function: EqualPriority, Weight: 1}},
  153. extenders: []FakeExtender{
  154. {
  155. predicates: []fitPredicate{truePredicateExtender},
  156. },
  157. {
  158. predicates: []fitPredicate{errorPredicateExtender},
  159. },
  160. },
  161. nodes: []string{"machine1", "machine2"},
  162. expectsErr: true,
  163. name: "test 1",
  164. },
  165. {
  166. predicates: map[string]algorithm.FitPredicate{"true": truePredicate},
  167. prioritizers: []algorithm.PriorityConfig{{Function: EqualPriority, Weight: 1}},
  168. extenders: []FakeExtender{
  169. {
  170. predicates: []fitPredicate{truePredicateExtender},
  171. },
  172. {
  173. predicates: []fitPredicate{falsePredicateExtender},
  174. },
  175. },
  176. nodes: []string{"machine1", "machine2"},
  177. expectsErr: true,
  178. name: "test 2",
  179. },
  180. {
  181. predicates: map[string]algorithm.FitPredicate{"true": truePredicate},
  182. prioritizers: []algorithm.PriorityConfig{{Function: EqualPriority, Weight: 1}},
  183. extenders: []FakeExtender{
  184. {
  185. predicates: []fitPredicate{truePredicateExtender},
  186. },
  187. {
  188. predicates: []fitPredicate{machine1PredicateExtender},
  189. },
  190. },
  191. nodes: []string{"machine1", "machine2"},
  192. expectedHost: "machine1",
  193. name: "test 3",
  194. },
  195. {
  196. predicates: map[string]algorithm.FitPredicate{"true": truePredicate},
  197. prioritizers: []algorithm.PriorityConfig{{Function: EqualPriority, Weight: 1}},
  198. extenders: []FakeExtender{
  199. {
  200. predicates: []fitPredicate{machine2PredicateExtender},
  201. },
  202. {
  203. predicates: []fitPredicate{machine1PredicateExtender},
  204. },
  205. },
  206. nodes: []string{"machine1", "machine2"},
  207. expectsErr: true,
  208. name: "test 4",
  209. },
  210. {
  211. predicates: map[string]algorithm.FitPredicate{"true": truePredicate},
  212. prioritizers: []algorithm.PriorityConfig{{Function: EqualPriority, Weight: 1}},
  213. extenders: []FakeExtender{
  214. {
  215. predicates: []fitPredicate{truePredicateExtender},
  216. prioritizers: []priorityConfig{{errorPrioritizerExtender, 10}},
  217. weight: 1,
  218. },
  219. },
  220. nodes: []string{"machine1"},
  221. expectedHost: "machine1",
  222. name: "test 5",
  223. },
  224. {
  225. predicates: map[string]algorithm.FitPredicate{"true": truePredicate},
  226. prioritizers: []algorithm.PriorityConfig{{Function: EqualPriority, Weight: 1}},
  227. extenders: []FakeExtender{
  228. {
  229. predicates: []fitPredicate{truePredicateExtender},
  230. prioritizers: []priorityConfig{{machine1PrioritizerExtender, 10}},
  231. weight: 1,
  232. },
  233. {
  234. predicates: []fitPredicate{truePredicateExtender},
  235. prioritizers: []priorityConfig{{machine2PrioritizerExtender, 10}},
  236. weight: 5,
  237. },
  238. },
  239. nodes: []string{"machine1", "machine2"},
  240. expectedHost: "machine2",
  241. name: "test 6",
  242. },
  243. {
  244. predicates: map[string]algorithm.FitPredicate{"true": truePredicate},
  245. prioritizers: []algorithm.PriorityConfig{{Function: machine2Prioritizer, Weight: 20}},
  246. extenders: []FakeExtender{
  247. {
  248. predicates: []fitPredicate{truePredicateExtender},
  249. prioritizers: []priorityConfig{{machine1PrioritizerExtender, 10}},
  250. weight: 1,
  251. },
  252. },
  253. nodes: []string{"machine1", "machine2"},
  254. expectedHost: "machine2", // machine2 has higher score
  255. name: "test 7",
  256. },
  257. }
  258. for _, test := range tests {
  259. extenders := []algorithm.SchedulerExtender{}
  260. for ii := range test.extenders {
  261. extenders = append(extenders, &test.extenders[ii])
  262. }
  263. scheduler := NewGenericScheduler(schedulertesting.PodsToCache(test.pods), test.predicates, test.prioritizers, extenders)
  264. machine, err := scheduler.Schedule(test.pod, algorithm.FakeNodeLister(makeNodeList(test.nodes)))
  265. if test.expectsErr {
  266. if err == nil {
  267. t.Errorf("Unexpected non-error for %s, machine %s", test.name, machine)
  268. }
  269. } else {
  270. if err != nil {
  271. t.Errorf("Unexpected error: %v", err)
  272. }
  273. if test.expectedHost != machine {
  274. t.Errorf("Failed : %s, Expected: %s, Saw: %s", test.name, test.expectedHost, machine)
  275. }
  276. }
  277. }
  278. }