node_info_test.go 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979
  1. /*
  2. Copyright 2018 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 nodeinfo
  14. import (
  15. "fmt"
  16. "reflect"
  17. "strings"
  18. "testing"
  19. "k8s.io/api/core/v1"
  20. "k8s.io/apimachinery/pkg/api/resource"
  21. metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
  22. "k8s.io/apimachinery/pkg/types"
  23. utilfeature "k8s.io/apiserver/pkg/util/feature"
  24. featuregatetesting "k8s.io/component-base/featuregate/testing"
  25. "k8s.io/kubernetes/pkg/features"
  26. )
  27. func TestNewResource(t *testing.T) {
  28. tests := []struct {
  29. resourceList v1.ResourceList
  30. expected *Resource
  31. }{
  32. {
  33. resourceList: map[v1.ResourceName]resource.Quantity{},
  34. expected: &Resource{},
  35. },
  36. {
  37. resourceList: map[v1.ResourceName]resource.Quantity{
  38. v1.ResourceCPU: *resource.NewScaledQuantity(4, -3),
  39. v1.ResourceMemory: *resource.NewQuantity(2000, resource.BinarySI),
  40. v1.ResourcePods: *resource.NewQuantity(80, resource.BinarySI),
  41. v1.ResourceEphemeralStorage: *resource.NewQuantity(5000, resource.BinarySI),
  42. "scalar.test/" + "scalar1": *resource.NewQuantity(1, resource.DecimalSI),
  43. v1.ResourceHugePagesPrefix + "test": *resource.NewQuantity(2, resource.BinarySI),
  44. },
  45. expected: &Resource{
  46. MilliCPU: 4,
  47. Memory: 2000,
  48. EphemeralStorage: 5000,
  49. AllowedPodNumber: 80,
  50. ScalarResources: map[v1.ResourceName]int64{"scalar.test/scalar1": 1, "hugepages-test": 2},
  51. },
  52. },
  53. }
  54. for _, test := range tests {
  55. r := NewResource(test.resourceList)
  56. if !reflect.DeepEqual(test.expected, r) {
  57. t.Errorf("expected: %#v, got: %#v", test.expected, r)
  58. }
  59. }
  60. }
  61. func TestResourceList(t *testing.T) {
  62. tests := []struct {
  63. resource *Resource
  64. expected v1.ResourceList
  65. }{
  66. {
  67. resource: &Resource{},
  68. expected: map[v1.ResourceName]resource.Quantity{
  69. v1.ResourceCPU: *resource.NewScaledQuantity(0, -3),
  70. v1.ResourceMemory: *resource.NewQuantity(0, resource.BinarySI),
  71. v1.ResourcePods: *resource.NewQuantity(0, resource.BinarySI),
  72. v1.ResourceEphemeralStorage: *resource.NewQuantity(0, resource.BinarySI),
  73. },
  74. },
  75. {
  76. resource: &Resource{
  77. MilliCPU: 4,
  78. Memory: 2000,
  79. EphemeralStorage: 5000,
  80. AllowedPodNumber: 80,
  81. ScalarResources: map[v1.ResourceName]int64{
  82. "scalar.test/scalar1": 1,
  83. "hugepages-test": 2,
  84. "attachable-volumes-aws-ebs": 39,
  85. },
  86. },
  87. expected: map[v1.ResourceName]resource.Quantity{
  88. v1.ResourceCPU: *resource.NewScaledQuantity(4, -3),
  89. v1.ResourceMemory: *resource.NewQuantity(2000, resource.BinarySI),
  90. v1.ResourcePods: *resource.NewQuantity(80, resource.BinarySI),
  91. v1.ResourceEphemeralStorage: *resource.NewQuantity(5000, resource.BinarySI),
  92. "scalar.test/" + "scalar1": *resource.NewQuantity(1, resource.DecimalSI),
  93. "attachable-volumes-aws-ebs": *resource.NewQuantity(39, resource.DecimalSI),
  94. v1.ResourceHugePagesPrefix + "test": *resource.NewQuantity(2, resource.BinarySI),
  95. },
  96. },
  97. }
  98. for _, test := range tests {
  99. rl := test.resource.ResourceList()
  100. if !reflect.DeepEqual(test.expected, rl) {
  101. t.Errorf("expected: %#v, got: %#v", test.expected, rl)
  102. }
  103. }
  104. }
  105. func TestResourceClone(t *testing.T) {
  106. tests := []struct {
  107. resource *Resource
  108. expected *Resource
  109. }{
  110. {
  111. resource: &Resource{},
  112. expected: &Resource{},
  113. },
  114. {
  115. resource: &Resource{
  116. MilliCPU: 4,
  117. Memory: 2000,
  118. EphemeralStorage: 5000,
  119. AllowedPodNumber: 80,
  120. ScalarResources: map[v1.ResourceName]int64{"scalar.test/scalar1": 1, "hugepages-test": 2},
  121. },
  122. expected: &Resource{
  123. MilliCPU: 4,
  124. Memory: 2000,
  125. EphemeralStorage: 5000,
  126. AllowedPodNumber: 80,
  127. ScalarResources: map[v1.ResourceName]int64{"scalar.test/scalar1": 1, "hugepages-test": 2},
  128. },
  129. },
  130. }
  131. for _, test := range tests {
  132. r := test.resource.Clone()
  133. // Modify the field to check if the result is a clone of the origin one.
  134. test.resource.MilliCPU += 1000
  135. if !reflect.DeepEqual(test.expected, r) {
  136. t.Errorf("expected: %#v, got: %#v", test.expected, r)
  137. }
  138. }
  139. }
  140. func TestResourceAddScalar(t *testing.T) {
  141. tests := []struct {
  142. resource *Resource
  143. scalarName v1.ResourceName
  144. scalarQuantity int64
  145. expected *Resource
  146. }{
  147. {
  148. resource: &Resource{},
  149. scalarName: "scalar1",
  150. scalarQuantity: 100,
  151. expected: &Resource{
  152. ScalarResources: map[v1.ResourceName]int64{"scalar1": 100},
  153. },
  154. },
  155. {
  156. resource: &Resource{
  157. MilliCPU: 4,
  158. Memory: 2000,
  159. EphemeralStorage: 5000,
  160. AllowedPodNumber: 80,
  161. ScalarResources: map[v1.ResourceName]int64{"hugepages-test": 2},
  162. },
  163. scalarName: "scalar2",
  164. scalarQuantity: 200,
  165. expected: &Resource{
  166. MilliCPU: 4,
  167. Memory: 2000,
  168. EphemeralStorage: 5000,
  169. AllowedPodNumber: 80,
  170. ScalarResources: map[v1.ResourceName]int64{"hugepages-test": 2, "scalar2": 200},
  171. },
  172. },
  173. }
  174. for _, test := range tests {
  175. test.resource.AddScalar(test.scalarName, test.scalarQuantity)
  176. if !reflect.DeepEqual(test.expected, test.resource) {
  177. t.Errorf("expected: %#v, got: %#v", test.expected, test.resource)
  178. }
  179. }
  180. }
  181. func TestSetMaxResource(t *testing.T) {
  182. tests := []struct {
  183. resource *Resource
  184. resourceList v1.ResourceList
  185. expected *Resource
  186. }{
  187. {
  188. resource: &Resource{},
  189. resourceList: map[v1.ResourceName]resource.Quantity{
  190. v1.ResourceCPU: *resource.NewScaledQuantity(4, -3),
  191. v1.ResourceMemory: *resource.NewQuantity(2000, resource.BinarySI),
  192. v1.ResourceEphemeralStorage: *resource.NewQuantity(5000, resource.BinarySI),
  193. },
  194. expected: &Resource{
  195. MilliCPU: 4,
  196. Memory: 2000,
  197. EphemeralStorage: 5000,
  198. },
  199. },
  200. {
  201. resource: &Resource{
  202. MilliCPU: 4,
  203. Memory: 4000,
  204. EphemeralStorage: 5000,
  205. ScalarResources: map[v1.ResourceName]int64{"scalar.test/scalar1": 1, "hugepages-test": 2},
  206. },
  207. resourceList: map[v1.ResourceName]resource.Quantity{
  208. v1.ResourceCPU: *resource.NewScaledQuantity(4, -3),
  209. v1.ResourceMemory: *resource.NewQuantity(2000, resource.BinarySI),
  210. v1.ResourceEphemeralStorage: *resource.NewQuantity(7000, resource.BinarySI),
  211. "scalar.test/scalar1": *resource.NewQuantity(4, resource.DecimalSI),
  212. v1.ResourceHugePagesPrefix + "test": *resource.NewQuantity(5, resource.BinarySI),
  213. },
  214. expected: &Resource{
  215. MilliCPU: 4,
  216. Memory: 4000,
  217. EphemeralStorage: 7000,
  218. ScalarResources: map[v1.ResourceName]int64{"scalar.test/scalar1": 4, "hugepages-test": 5},
  219. },
  220. },
  221. }
  222. for _, test := range tests {
  223. test.resource.SetMaxResource(test.resourceList)
  224. if !reflect.DeepEqual(test.expected, test.resource) {
  225. t.Errorf("expected: %#v, got: %#v", test.expected, test.resource)
  226. }
  227. }
  228. }
  229. type testingMode interface {
  230. Fatalf(format string, args ...interface{})
  231. }
  232. func makeBasePod(t testingMode, nodeName, objName, cpu, mem, extended string, ports []v1.ContainerPort) *v1.Pod {
  233. req := v1.ResourceList{}
  234. if cpu != "" {
  235. req = v1.ResourceList{
  236. v1.ResourceCPU: resource.MustParse(cpu),
  237. v1.ResourceMemory: resource.MustParse(mem),
  238. }
  239. if extended != "" {
  240. parts := strings.Split(extended, ":")
  241. if len(parts) != 2 {
  242. t.Fatalf("Invalid extended resource string: \"%s\"", extended)
  243. }
  244. req[v1.ResourceName(parts[0])] = resource.MustParse(parts[1])
  245. }
  246. }
  247. return &v1.Pod{
  248. ObjectMeta: metav1.ObjectMeta{
  249. UID: types.UID(objName),
  250. Namespace: "node_info_cache_test",
  251. Name: objName,
  252. },
  253. Spec: v1.PodSpec{
  254. Containers: []v1.Container{{
  255. Resources: v1.ResourceRequirements{
  256. Requests: req,
  257. },
  258. Ports: ports,
  259. }},
  260. NodeName: nodeName,
  261. },
  262. }
  263. }
  264. func TestNewNodeInfo(t *testing.T) {
  265. nodeName := "test-node"
  266. pods := []*v1.Pod{
  267. makeBasePod(t, nodeName, "test-1", "100m", "500", "", []v1.ContainerPort{{HostIP: "127.0.0.1", HostPort: 80, Protocol: "TCP"}}),
  268. makeBasePod(t, nodeName, "test-2", "200m", "1Ki", "", []v1.ContainerPort{{HostIP: "127.0.0.1", HostPort: 8080, Protocol: "TCP"}}),
  269. }
  270. expected := &NodeInfo{
  271. requestedResource: &Resource{
  272. MilliCPU: 300,
  273. Memory: 1524,
  274. EphemeralStorage: 0,
  275. AllowedPodNumber: 0,
  276. ScalarResources: map[v1.ResourceName]int64(nil),
  277. },
  278. nonzeroRequest: &Resource{
  279. MilliCPU: 300,
  280. Memory: 1524,
  281. EphemeralStorage: 0,
  282. AllowedPodNumber: 0,
  283. ScalarResources: map[v1.ResourceName]int64(nil),
  284. },
  285. TransientInfo: NewTransientSchedulerInfo(),
  286. allocatableResource: &Resource{},
  287. generation: 2,
  288. usedPorts: HostPortInfo{
  289. "127.0.0.1": map[ProtocolPort]struct{}{
  290. {Protocol: "TCP", Port: 80}: {},
  291. {Protocol: "TCP", Port: 8080}: {},
  292. },
  293. },
  294. imageStates: map[string]*ImageStateSummary{},
  295. pods: []*v1.Pod{
  296. {
  297. ObjectMeta: metav1.ObjectMeta{
  298. Namespace: "node_info_cache_test",
  299. Name: "test-1",
  300. UID: types.UID("test-1"),
  301. },
  302. Spec: v1.PodSpec{
  303. Containers: []v1.Container{
  304. {
  305. Resources: v1.ResourceRequirements{
  306. Requests: v1.ResourceList{
  307. v1.ResourceCPU: resource.MustParse("100m"),
  308. v1.ResourceMemory: resource.MustParse("500"),
  309. },
  310. },
  311. Ports: []v1.ContainerPort{
  312. {
  313. HostIP: "127.0.0.1",
  314. HostPort: 80,
  315. Protocol: "TCP",
  316. },
  317. },
  318. },
  319. },
  320. NodeName: nodeName,
  321. },
  322. },
  323. {
  324. ObjectMeta: metav1.ObjectMeta{
  325. Namespace: "node_info_cache_test",
  326. Name: "test-2",
  327. UID: types.UID("test-2"),
  328. },
  329. Spec: v1.PodSpec{
  330. Containers: []v1.Container{
  331. {
  332. Resources: v1.ResourceRequirements{
  333. Requests: v1.ResourceList{
  334. v1.ResourceCPU: resource.MustParse("200m"),
  335. v1.ResourceMemory: resource.MustParse("1Ki"),
  336. },
  337. },
  338. Ports: []v1.ContainerPort{
  339. {
  340. HostIP: "127.0.0.1",
  341. HostPort: 8080,
  342. Protocol: "TCP",
  343. },
  344. },
  345. },
  346. },
  347. NodeName: nodeName,
  348. },
  349. },
  350. },
  351. }
  352. gen := generation
  353. ni := NewNodeInfo(pods...)
  354. if ni.generation <= gen {
  355. t.Errorf("generation is not incremented. previous: %v, current: %v", gen, ni.generation)
  356. }
  357. expected.generation = ni.generation
  358. if !reflect.DeepEqual(expected, ni) {
  359. t.Errorf("expected: %#v, got: %#v", expected, ni)
  360. }
  361. }
  362. func TestNodeInfoClone(t *testing.T) {
  363. nodeName := "test-node"
  364. tests := []struct {
  365. nodeInfo *NodeInfo
  366. expected *NodeInfo
  367. }{
  368. {
  369. nodeInfo: &NodeInfo{
  370. requestedResource: &Resource{},
  371. nonzeroRequest: &Resource{},
  372. TransientInfo: NewTransientSchedulerInfo(),
  373. allocatableResource: &Resource{},
  374. generation: 2,
  375. usedPorts: HostPortInfo{
  376. "127.0.0.1": map[ProtocolPort]struct{}{
  377. {Protocol: "TCP", Port: 80}: {},
  378. {Protocol: "TCP", Port: 8080}: {},
  379. },
  380. },
  381. imageStates: map[string]*ImageStateSummary{},
  382. pods: []*v1.Pod{
  383. {
  384. ObjectMeta: metav1.ObjectMeta{
  385. Namespace: "node_info_cache_test",
  386. Name: "test-1",
  387. UID: types.UID("test-1"),
  388. },
  389. Spec: v1.PodSpec{
  390. Containers: []v1.Container{
  391. {
  392. Resources: v1.ResourceRequirements{
  393. Requests: v1.ResourceList{
  394. v1.ResourceCPU: resource.MustParse("100m"),
  395. v1.ResourceMemory: resource.MustParse("500"),
  396. },
  397. },
  398. Ports: []v1.ContainerPort{
  399. {
  400. HostIP: "127.0.0.1",
  401. HostPort: 80,
  402. Protocol: "TCP",
  403. },
  404. },
  405. },
  406. },
  407. NodeName: nodeName,
  408. },
  409. },
  410. {
  411. ObjectMeta: metav1.ObjectMeta{
  412. Namespace: "node_info_cache_test",
  413. Name: "test-2",
  414. UID: types.UID("test-2"),
  415. },
  416. Spec: v1.PodSpec{
  417. Containers: []v1.Container{
  418. {
  419. Resources: v1.ResourceRequirements{
  420. Requests: v1.ResourceList{
  421. v1.ResourceCPU: resource.MustParse("200m"),
  422. v1.ResourceMemory: resource.MustParse("1Ki"),
  423. },
  424. },
  425. Ports: []v1.ContainerPort{
  426. {
  427. HostIP: "127.0.0.1",
  428. HostPort: 8080,
  429. Protocol: "TCP",
  430. },
  431. },
  432. },
  433. },
  434. NodeName: nodeName,
  435. },
  436. },
  437. },
  438. },
  439. expected: &NodeInfo{
  440. requestedResource: &Resource{},
  441. nonzeroRequest: &Resource{},
  442. TransientInfo: NewTransientSchedulerInfo(),
  443. allocatableResource: &Resource{},
  444. generation: 2,
  445. usedPorts: HostPortInfo{
  446. "127.0.0.1": map[ProtocolPort]struct{}{
  447. {Protocol: "TCP", Port: 80}: {},
  448. {Protocol: "TCP", Port: 8080}: {},
  449. },
  450. },
  451. imageStates: map[string]*ImageStateSummary{},
  452. pods: []*v1.Pod{
  453. {
  454. ObjectMeta: metav1.ObjectMeta{
  455. Namespace: "node_info_cache_test",
  456. Name: "test-1",
  457. UID: types.UID("test-1"),
  458. },
  459. Spec: v1.PodSpec{
  460. Containers: []v1.Container{
  461. {
  462. Resources: v1.ResourceRequirements{
  463. Requests: v1.ResourceList{
  464. v1.ResourceCPU: resource.MustParse("100m"),
  465. v1.ResourceMemory: resource.MustParse("500"),
  466. },
  467. },
  468. Ports: []v1.ContainerPort{
  469. {
  470. HostIP: "127.0.0.1",
  471. HostPort: 80,
  472. Protocol: "TCP",
  473. },
  474. },
  475. },
  476. },
  477. NodeName: nodeName,
  478. },
  479. },
  480. {
  481. ObjectMeta: metav1.ObjectMeta{
  482. Namespace: "node_info_cache_test",
  483. Name: "test-2",
  484. UID: types.UID("test-2"),
  485. },
  486. Spec: v1.PodSpec{
  487. Containers: []v1.Container{
  488. {
  489. Resources: v1.ResourceRequirements{
  490. Requests: v1.ResourceList{
  491. v1.ResourceCPU: resource.MustParse("200m"),
  492. v1.ResourceMemory: resource.MustParse("1Ki"),
  493. },
  494. },
  495. Ports: []v1.ContainerPort{
  496. {
  497. HostIP: "127.0.0.1",
  498. HostPort: 8080,
  499. Protocol: "TCP",
  500. },
  501. },
  502. },
  503. },
  504. NodeName: nodeName,
  505. },
  506. },
  507. },
  508. },
  509. },
  510. }
  511. for _, test := range tests {
  512. ni := test.nodeInfo.Clone()
  513. // Modify the field to check if the result is a clone of the origin one.
  514. test.nodeInfo.generation += 10
  515. test.nodeInfo.usedPorts.Remove("127.0.0.1", "TCP", 80)
  516. if !reflect.DeepEqual(test.expected, ni) {
  517. t.Errorf("expected: %#v, got: %#v", test.expected, ni)
  518. }
  519. }
  520. }
  521. func TestNodeInfoAddPod(t *testing.T) {
  522. defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.PodOverhead, true)()
  523. nodeName := "test-node"
  524. pods := []*v1.Pod{
  525. {
  526. ObjectMeta: metav1.ObjectMeta{
  527. Namespace: "node_info_cache_test",
  528. Name: "test-1",
  529. UID: types.UID("test-1"),
  530. },
  531. Spec: v1.PodSpec{
  532. Containers: []v1.Container{
  533. {
  534. Resources: v1.ResourceRequirements{
  535. Requests: v1.ResourceList{
  536. v1.ResourceCPU: resource.MustParse("100m"),
  537. v1.ResourceMemory: resource.MustParse("500"),
  538. },
  539. },
  540. Ports: []v1.ContainerPort{
  541. {
  542. HostIP: "127.0.0.1",
  543. HostPort: 80,
  544. Protocol: "TCP",
  545. },
  546. },
  547. },
  548. },
  549. NodeName: nodeName,
  550. Overhead: v1.ResourceList{
  551. v1.ResourceCPU: resource.MustParse("500m"),
  552. },
  553. },
  554. },
  555. {
  556. ObjectMeta: metav1.ObjectMeta{
  557. Namespace: "node_info_cache_test",
  558. Name: "test-2",
  559. UID: types.UID("test-2"),
  560. },
  561. Spec: v1.PodSpec{
  562. Containers: []v1.Container{
  563. {
  564. Resources: v1.ResourceRequirements{
  565. Requests: v1.ResourceList{
  566. v1.ResourceCPU: resource.MustParse("200m"),
  567. },
  568. },
  569. Ports: []v1.ContainerPort{
  570. {
  571. HostIP: "127.0.0.1",
  572. HostPort: 8080,
  573. Protocol: "TCP",
  574. },
  575. },
  576. },
  577. },
  578. NodeName: nodeName,
  579. Overhead: v1.ResourceList{
  580. v1.ResourceCPU: resource.MustParse("500m"),
  581. v1.ResourceMemory: resource.MustParse("500"),
  582. },
  583. },
  584. },
  585. }
  586. expected := &NodeInfo{
  587. node: &v1.Node{
  588. ObjectMeta: metav1.ObjectMeta{
  589. Name: "test-node",
  590. },
  591. },
  592. requestedResource: &Resource{
  593. MilliCPU: 1300,
  594. Memory: 1000,
  595. EphemeralStorage: 0,
  596. AllowedPodNumber: 0,
  597. ScalarResources: map[v1.ResourceName]int64(nil),
  598. },
  599. nonzeroRequest: &Resource{
  600. MilliCPU: 1300,
  601. Memory: 209716200, //200MB + 1000 specified in requests/overhead
  602. EphemeralStorage: 0,
  603. AllowedPodNumber: 0,
  604. ScalarResources: map[v1.ResourceName]int64(nil),
  605. },
  606. TransientInfo: NewTransientSchedulerInfo(),
  607. allocatableResource: &Resource{},
  608. generation: 2,
  609. usedPorts: HostPortInfo{
  610. "127.0.0.1": map[ProtocolPort]struct{}{
  611. {Protocol: "TCP", Port: 80}: {},
  612. {Protocol: "TCP", Port: 8080}: {},
  613. },
  614. },
  615. imageStates: map[string]*ImageStateSummary{},
  616. pods: []*v1.Pod{
  617. {
  618. ObjectMeta: metav1.ObjectMeta{
  619. Namespace: "node_info_cache_test",
  620. Name: "test-1",
  621. UID: types.UID("test-1"),
  622. },
  623. Spec: v1.PodSpec{
  624. Containers: []v1.Container{
  625. {
  626. Resources: v1.ResourceRequirements{
  627. Requests: v1.ResourceList{
  628. v1.ResourceCPU: resource.MustParse("100m"),
  629. v1.ResourceMemory: resource.MustParse("500"),
  630. },
  631. },
  632. Ports: []v1.ContainerPort{
  633. {
  634. HostIP: "127.0.0.1",
  635. HostPort: 80,
  636. Protocol: "TCP",
  637. },
  638. },
  639. },
  640. },
  641. NodeName: nodeName,
  642. Overhead: v1.ResourceList{
  643. v1.ResourceCPU: resource.MustParse("500m"),
  644. },
  645. },
  646. },
  647. {
  648. ObjectMeta: metav1.ObjectMeta{
  649. Namespace: "node_info_cache_test",
  650. Name: "test-2",
  651. UID: types.UID("test-2"),
  652. },
  653. Spec: v1.PodSpec{
  654. Containers: []v1.Container{
  655. {
  656. Resources: v1.ResourceRequirements{
  657. Requests: v1.ResourceList{
  658. v1.ResourceCPU: resource.MustParse("200m"),
  659. },
  660. },
  661. Ports: []v1.ContainerPort{
  662. {
  663. HostIP: "127.0.0.1",
  664. HostPort: 8080,
  665. Protocol: "TCP",
  666. },
  667. },
  668. },
  669. },
  670. NodeName: nodeName,
  671. Overhead: v1.ResourceList{
  672. v1.ResourceCPU: resource.MustParse("500m"),
  673. v1.ResourceMemory: resource.MustParse("500"),
  674. },
  675. },
  676. },
  677. },
  678. }
  679. ni := fakeNodeInfo()
  680. gen := ni.generation
  681. for _, pod := range pods {
  682. ni.AddPod(pod)
  683. if ni.generation <= gen {
  684. t.Errorf("generation is not incremented. Prev: %v, current: %v", gen, ni.generation)
  685. }
  686. gen = ni.generation
  687. }
  688. expected.generation = ni.generation
  689. if !reflect.DeepEqual(expected, ni) {
  690. t.Errorf("expected: %#v, got: %#v", expected, ni)
  691. }
  692. }
  693. func TestNodeInfoRemovePod(t *testing.T) {
  694. defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.PodOverhead, true)()
  695. nodeName := "test-node"
  696. pods := []*v1.Pod{
  697. makeBasePod(t, nodeName, "test-1", "100m", "500", "", []v1.ContainerPort{{HostIP: "127.0.0.1", HostPort: 80, Protocol: "TCP"}}),
  698. makeBasePod(t, nodeName, "test-2", "200m", "1Ki", "", []v1.ContainerPort{{HostIP: "127.0.0.1", HostPort: 8080, Protocol: "TCP"}}),
  699. }
  700. // add pod Overhead
  701. for _, pod := range pods {
  702. pod.Spec.Overhead = v1.ResourceList{
  703. v1.ResourceCPU: resource.MustParse("500m"),
  704. v1.ResourceMemory: resource.MustParse("500"),
  705. }
  706. }
  707. tests := []struct {
  708. pod *v1.Pod
  709. errExpected bool
  710. expectedNodeInfo *NodeInfo
  711. }{
  712. {
  713. pod: makeBasePod(t, nodeName, "non-exist", "0", "0", "", []v1.ContainerPort{{}}),
  714. errExpected: true,
  715. expectedNodeInfo: &NodeInfo{
  716. node: &v1.Node{
  717. ObjectMeta: metav1.ObjectMeta{
  718. Name: "test-node",
  719. },
  720. },
  721. requestedResource: &Resource{
  722. MilliCPU: 1300,
  723. Memory: 2524,
  724. EphemeralStorage: 0,
  725. AllowedPodNumber: 0,
  726. ScalarResources: map[v1.ResourceName]int64(nil),
  727. },
  728. nonzeroRequest: &Resource{
  729. MilliCPU: 1300,
  730. Memory: 2524,
  731. EphemeralStorage: 0,
  732. AllowedPodNumber: 0,
  733. ScalarResources: map[v1.ResourceName]int64(nil),
  734. },
  735. TransientInfo: NewTransientSchedulerInfo(),
  736. allocatableResource: &Resource{},
  737. generation: 2,
  738. usedPorts: HostPortInfo{
  739. "127.0.0.1": map[ProtocolPort]struct{}{
  740. {Protocol: "TCP", Port: 80}: {},
  741. {Protocol: "TCP", Port: 8080}: {},
  742. },
  743. },
  744. imageStates: map[string]*ImageStateSummary{},
  745. pods: []*v1.Pod{
  746. {
  747. ObjectMeta: metav1.ObjectMeta{
  748. Namespace: "node_info_cache_test",
  749. Name: "test-1",
  750. UID: types.UID("test-1"),
  751. },
  752. Spec: v1.PodSpec{
  753. Containers: []v1.Container{
  754. {
  755. Resources: v1.ResourceRequirements{
  756. Requests: v1.ResourceList{
  757. v1.ResourceCPU: resource.MustParse("100m"),
  758. v1.ResourceMemory: resource.MustParse("500"),
  759. },
  760. },
  761. Ports: []v1.ContainerPort{
  762. {
  763. HostIP: "127.0.0.1",
  764. HostPort: 80,
  765. Protocol: "TCP",
  766. },
  767. },
  768. },
  769. },
  770. NodeName: nodeName,
  771. Overhead: v1.ResourceList{
  772. v1.ResourceCPU: resource.MustParse("500m"),
  773. v1.ResourceMemory: resource.MustParse("500"),
  774. },
  775. },
  776. },
  777. {
  778. ObjectMeta: metav1.ObjectMeta{
  779. Namespace: "node_info_cache_test",
  780. Name: "test-2",
  781. UID: types.UID("test-2"),
  782. },
  783. Spec: v1.PodSpec{
  784. Containers: []v1.Container{
  785. {
  786. Resources: v1.ResourceRequirements{
  787. Requests: v1.ResourceList{
  788. v1.ResourceCPU: resource.MustParse("200m"),
  789. v1.ResourceMemory: resource.MustParse("1Ki"),
  790. },
  791. },
  792. Ports: []v1.ContainerPort{
  793. {
  794. HostIP: "127.0.0.1",
  795. HostPort: 8080,
  796. Protocol: "TCP",
  797. },
  798. },
  799. },
  800. },
  801. NodeName: nodeName,
  802. Overhead: v1.ResourceList{
  803. v1.ResourceCPU: resource.MustParse("500m"),
  804. v1.ResourceMemory: resource.MustParse("500"),
  805. },
  806. },
  807. },
  808. },
  809. },
  810. },
  811. {
  812. pod: &v1.Pod{
  813. ObjectMeta: metav1.ObjectMeta{
  814. Namespace: "node_info_cache_test",
  815. Name: "test-1",
  816. UID: types.UID("test-1"),
  817. },
  818. Spec: v1.PodSpec{
  819. Containers: []v1.Container{
  820. {
  821. Resources: v1.ResourceRequirements{
  822. Requests: v1.ResourceList{
  823. v1.ResourceCPU: resource.MustParse("100m"),
  824. v1.ResourceMemory: resource.MustParse("500"),
  825. },
  826. },
  827. Ports: []v1.ContainerPort{
  828. {
  829. HostIP: "127.0.0.1",
  830. HostPort: 80,
  831. Protocol: "TCP",
  832. },
  833. },
  834. },
  835. },
  836. NodeName: nodeName,
  837. Overhead: v1.ResourceList{
  838. v1.ResourceCPU: resource.MustParse("500m"),
  839. v1.ResourceMemory: resource.MustParse("500"),
  840. },
  841. },
  842. },
  843. errExpected: false,
  844. expectedNodeInfo: &NodeInfo{
  845. node: &v1.Node{
  846. ObjectMeta: metav1.ObjectMeta{
  847. Name: "test-node",
  848. },
  849. },
  850. requestedResource: &Resource{
  851. MilliCPU: 700,
  852. Memory: 1524,
  853. EphemeralStorage: 0,
  854. AllowedPodNumber: 0,
  855. ScalarResources: map[v1.ResourceName]int64(nil),
  856. },
  857. nonzeroRequest: &Resource{
  858. MilliCPU: 700,
  859. Memory: 1524,
  860. EphemeralStorage: 0,
  861. AllowedPodNumber: 0,
  862. ScalarResources: map[v1.ResourceName]int64(nil),
  863. },
  864. TransientInfo: NewTransientSchedulerInfo(),
  865. allocatableResource: &Resource{},
  866. generation: 3,
  867. usedPorts: HostPortInfo{
  868. "127.0.0.1": map[ProtocolPort]struct{}{
  869. {Protocol: "TCP", Port: 8080}: {},
  870. },
  871. },
  872. imageStates: map[string]*ImageStateSummary{},
  873. pods: []*v1.Pod{
  874. {
  875. ObjectMeta: metav1.ObjectMeta{
  876. Namespace: "node_info_cache_test",
  877. Name: "test-2",
  878. UID: types.UID("test-2"),
  879. },
  880. Spec: v1.PodSpec{
  881. Containers: []v1.Container{
  882. {
  883. Resources: v1.ResourceRequirements{
  884. Requests: v1.ResourceList{
  885. v1.ResourceCPU: resource.MustParse("200m"),
  886. v1.ResourceMemory: resource.MustParse("1Ki"),
  887. },
  888. },
  889. Ports: []v1.ContainerPort{
  890. {
  891. HostIP: "127.0.0.1",
  892. HostPort: 8080,
  893. Protocol: "TCP",
  894. },
  895. },
  896. },
  897. },
  898. NodeName: nodeName,
  899. Overhead: v1.ResourceList{
  900. v1.ResourceCPU: resource.MustParse("500m"),
  901. v1.ResourceMemory: resource.MustParse("500"),
  902. },
  903. },
  904. },
  905. },
  906. },
  907. },
  908. }
  909. for _, test := range tests {
  910. ni := fakeNodeInfo(pods...)
  911. gen := ni.generation
  912. err := ni.RemovePod(test.pod)
  913. if err != nil {
  914. if test.errExpected {
  915. expectedErrorMsg := fmt.Errorf("no corresponding pod %s in pods of node %s", test.pod.Name, ni.Node().Name)
  916. if expectedErrorMsg == err {
  917. t.Errorf("expected error: %v, got: %v", expectedErrorMsg, err)
  918. }
  919. } else {
  920. t.Errorf("expected no error, got: %v", err)
  921. }
  922. } else {
  923. if ni.generation <= gen {
  924. t.Errorf("generation is not incremented. Prev: %v, current: %v", gen, ni.generation)
  925. }
  926. }
  927. test.expectedNodeInfo.generation = ni.generation
  928. if !reflect.DeepEqual(test.expectedNodeInfo, ni) {
  929. t.Errorf("expected: %#v, got: %#v", test.expectedNodeInfo, ni)
  930. }
  931. }
  932. }
  933. func fakeNodeInfo(pods ...*v1.Pod) *NodeInfo {
  934. ni := NewNodeInfo(pods...)
  935. ni.SetNode(&v1.Node{
  936. ObjectMeta: metav1.ObjectMeta{
  937. Name: "test-node",
  938. },
  939. })
  940. return ni
  941. }