node_container_manager_linux_test.go 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403
  1. // +build linux
  2. /*
  3. Copyright 2017 The Kubernetes Authors.
  4. Licensed under the Apache License, Version 2.0 (the "License");
  5. you may not use this file except in compliance with the License.
  6. You may obtain a copy of the License at
  7. http://www.apache.org/licenses/LICENSE-2.0
  8. Unless required by applicable law or agreed to in writing, software
  9. distributed under the License is distributed on an "AS IS" BASIS,
  10. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  11. See the License for the specific language governing permissions and
  12. limitations under the License.
  13. */
  14. package cm
  15. import (
  16. "testing"
  17. "github.com/stretchr/testify/assert"
  18. "k8s.io/api/core/v1"
  19. "k8s.io/apimachinery/pkg/api/resource"
  20. evictionapi "k8s.io/kubernetes/pkg/kubelet/eviction/api"
  21. )
  22. func TestNodeAllocatableReservationForScheduling(t *testing.T) {
  23. memoryEvictionThreshold := resource.MustParse("100Mi")
  24. cpuMemCases := []struct {
  25. kubeReserved v1.ResourceList
  26. systemReserved v1.ResourceList
  27. expected v1.ResourceList
  28. capacity v1.ResourceList
  29. hardThreshold evictionapi.ThresholdValue
  30. }{
  31. {
  32. kubeReserved: getResourceList("100m", "100Mi"),
  33. systemReserved: getResourceList("50m", "50Mi"),
  34. capacity: getResourceList("10", "10Gi"),
  35. expected: getResourceList("150m", "150Mi"),
  36. },
  37. {
  38. kubeReserved: getResourceList("100m", "100Mi"),
  39. systemReserved: getResourceList("50m", "50Mi"),
  40. hardThreshold: evictionapi.ThresholdValue{
  41. Quantity: &memoryEvictionThreshold,
  42. },
  43. capacity: getResourceList("10", "10Gi"),
  44. expected: getResourceList("150m", "250Mi"),
  45. },
  46. {
  47. kubeReserved: getResourceList("100m", "100Mi"),
  48. systemReserved: getResourceList("50m", "50Mi"),
  49. capacity: getResourceList("10", "10Gi"),
  50. hardThreshold: evictionapi.ThresholdValue{
  51. Percentage: 0.05,
  52. },
  53. expected: getResourceList("150m", "694157320"),
  54. },
  55. {
  56. kubeReserved: v1.ResourceList{},
  57. systemReserved: v1.ResourceList{},
  58. capacity: getResourceList("10", "10Gi"),
  59. expected: getResourceList("", ""),
  60. },
  61. {
  62. kubeReserved: getResourceList("", "100Mi"),
  63. systemReserved: getResourceList("50m", "50Mi"),
  64. capacity: getResourceList("10", "10Gi"),
  65. expected: getResourceList("50m", "150Mi"),
  66. },
  67. {
  68. kubeReserved: getResourceList("50m", "100Mi"),
  69. systemReserved: getResourceList("", "50Mi"),
  70. capacity: getResourceList("10", "10Gi"),
  71. expected: getResourceList("50m", "150Mi"),
  72. },
  73. {
  74. kubeReserved: getResourceList("", "100Mi"),
  75. systemReserved: getResourceList("", "50Mi"),
  76. capacity: getResourceList("10", ""),
  77. expected: getResourceList("", "150Mi"),
  78. },
  79. }
  80. for idx, tc := range cpuMemCases {
  81. nc := NodeConfig{
  82. NodeAllocatableConfig: NodeAllocatableConfig{
  83. KubeReserved: tc.kubeReserved,
  84. SystemReserved: tc.systemReserved,
  85. HardEvictionThresholds: []evictionapi.Threshold{
  86. {
  87. Signal: evictionapi.SignalMemoryAvailable,
  88. Operator: evictionapi.OpLessThan,
  89. Value: tc.hardThreshold,
  90. },
  91. },
  92. },
  93. }
  94. cm := &containerManagerImpl{
  95. NodeConfig: nc,
  96. capacity: tc.capacity,
  97. }
  98. for k, v := range cm.GetNodeAllocatableReservation() {
  99. expected, exists := tc.expected[k]
  100. assert.True(t, exists, "test case %d expected resource %q", idx+1, k)
  101. assert.Equal(t, expected.MilliValue(), v.MilliValue(), "test case %d failed for resource %q", idx+1, k)
  102. }
  103. }
  104. ephemeralStorageEvictionThreshold := resource.MustParse("100Mi")
  105. ephemeralStorageTestCases := []struct {
  106. kubeReserved v1.ResourceList
  107. expected v1.ResourceList
  108. capacity v1.ResourceList
  109. hardThreshold evictionapi.ThresholdValue
  110. }{
  111. {
  112. kubeReserved: getEphemeralStorageResourceList("100Mi"),
  113. capacity: getEphemeralStorageResourceList("10Gi"),
  114. expected: getEphemeralStorageResourceList("100Mi"),
  115. },
  116. {
  117. kubeReserved: getEphemeralStorageResourceList("100Mi"),
  118. hardThreshold: evictionapi.ThresholdValue{
  119. Quantity: &ephemeralStorageEvictionThreshold,
  120. },
  121. capacity: getEphemeralStorageResourceList("10Gi"),
  122. expected: getEphemeralStorageResourceList("200Mi"),
  123. },
  124. {
  125. kubeReserved: getEphemeralStorageResourceList("150Mi"),
  126. capacity: getEphemeralStorageResourceList("10Gi"),
  127. hardThreshold: evictionapi.ThresholdValue{
  128. Percentage: 0.05,
  129. },
  130. expected: getEphemeralStorageResourceList("694157320"),
  131. },
  132. {
  133. kubeReserved: v1.ResourceList{},
  134. capacity: getEphemeralStorageResourceList("10Gi"),
  135. expected: getEphemeralStorageResourceList(""),
  136. },
  137. }
  138. for idx, tc := range ephemeralStorageTestCases {
  139. nc := NodeConfig{
  140. NodeAllocatableConfig: NodeAllocatableConfig{
  141. KubeReserved: tc.kubeReserved,
  142. HardEvictionThresholds: []evictionapi.Threshold{
  143. {
  144. Signal: evictionapi.SignalNodeFsAvailable,
  145. Operator: evictionapi.OpLessThan,
  146. Value: tc.hardThreshold,
  147. },
  148. },
  149. },
  150. }
  151. cm := &containerManagerImpl{
  152. NodeConfig: nc,
  153. capacity: tc.capacity,
  154. }
  155. for k, v := range cm.GetNodeAllocatableReservation() {
  156. expected, exists := tc.expected[k]
  157. assert.True(t, exists, "test case %d expected resource %q", idx+1, k)
  158. assert.Equal(t, expected.MilliValue(), v.MilliValue(), "test case %d failed for resource %q", idx+1, k)
  159. }
  160. }
  161. }
  162. func TestNodeAllocatableForEnforcement(t *testing.T) {
  163. memoryEvictionThreshold := resource.MustParse("100Mi")
  164. testCases := []struct {
  165. kubeReserved v1.ResourceList
  166. systemReserved v1.ResourceList
  167. capacity v1.ResourceList
  168. expected v1.ResourceList
  169. hardThreshold evictionapi.ThresholdValue
  170. }{
  171. {
  172. kubeReserved: getResourceList("100m", "100Mi"),
  173. systemReserved: getResourceList("50m", "50Mi"),
  174. capacity: getResourceList("10", "10Gi"),
  175. expected: getResourceList("9850m", "10090Mi"),
  176. },
  177. {
  178. kubeReserved: getResourceList("100m", "100Mi"),
  179. systemReserved: getResourceList("50m", "50Mi"),
  180. hardThreshold: evictionapi.ThresholdValue{
  181. Quantity: &memoryEvictionThreshold,
  182. },
  183. capacity: getResourceList("10", "10Gi"),
  184. expected: getResourceList("9850m", "10090Mi"),
  185. },
  186. {
  187. kubeReserved: getResourceList("100m", "100Mi"),
  188. systemReserved: getResourceList("50m", "50Mi"),
  189. hardThreshold: evictionapi.ThresholdValue{
  190. Percentage: 0.05,
  191. },
  192. capacity: getResourceList("10", "10Gi"),
  193. expected: getResourceList("9850m", "10090Mi"),
  194. },
  195. {
  196. kubeReserved: v1.ResourceList{},
  197. systemReserved: v1.ResourceList{},
  198. capacity: getResourceList("10", "10Gi"),
  199. expected: getResourceList("10", "10Gi"),
  200. },
  201. {
  202. kubeReserved: getResourceList("", "100Mi"),
  203. systemReserved: getResourceList("50m", "50Mi"),
  204. capacity: getResourceList("10", "10Gi"),
  205. expected: getResourceList("9950m", "10090Mi"),
  206. },
  207. {
  208. kubeReserved: getResourceList("50m", "100Mi"),
  209. systemReserved: getResourceList("", "50Mi"),
  210. capacity: getResourceList("10", "10Gi"),
  211. expected: getResourceList("9950m", "10090Mi"),
  212. },
  213. {
  214. kubeReserved: getResourceList("", "100Mi"),
  215. systemReserved: getResourceList("", "50Mi"),
  216. capacity: getResourceList("10", ""),
  217. expected: getResourceList("10", ""),
  218. },
  219. }
  220. for idx, tc := range testCases {
  221. nc := NodeConfig{
  222. NodeAllocatableConfig: NodeAllocatableConfig{
  223. KubeReserved: tc.kubeReserved,
  224. SystemReserved: tc.systemReserved,
  225. HardEvictionThresholds: []evictionapi.Threshold{
  226. {
  227. Signal: evictionapi.SignalMemoryAvailable,
  228. Operator: evictionapi.OpLessThan,
  229. Value: tc.hardThreshold,
  230. },
  231. },
  232. },
  233. }
  234. cm := &containerManagerImpl{
  235. NodeConfig: nc,
  236. capacity: tc.capacity,
  237. }
  238. for k, v := range cm.getNodeAllocatableAbsolute() {
  239. expected, exists := tc.expected[k]
  240. assert.True(t, exists)
  241. assert.Equal(t, expected.MilliValue(), v.MilliValue(), "test case %d failed for resource %q", idx+1, k)
  242. }
  243. }
  244. }
  245. func TestNodeAllocatableInputValidation(t *testing.T) {
  246. memoryEvictionThreshold := resource.MustParse("100Mi")
  247. highMemoryEvictionThreshold := resource.MustParse("2Gi")
  248. cpuMemTestCases := []struct {
  249. kubeReserved v1.ResourceList
  250. systemReserved v1.ResourceList
  251. capacity v1.ResourceList
  252. hardThreshold evictionapi.ThresholdValue
  253. invalidConfiguration bool
  254. }{
  255. {
  256. kubeReserved: getResourceList("100m", "100Mi"),
  257. systemReserved: getResourceList("50m", "50Mi"),
  258. capacity: getResourceList("10", "10Gi"),
  259. },
  260. {
  261. kubeReserved: getResourceList("100m", "100Mi"),
  262. systemReserved: getResourceList("50m", "50Mi"),
  263. hardThreshold: evictionapi.ThresholdValue{
  264. Quantity: &memoryEvictionThreshold,
  265. },
  266. capacity: getResourceList("10", "10Gi"),
  267. },
  268. {
  269. kubeReserved: getResourceList("100m", "100Mi"),
  270. systemReserved: getResourceList("50m", "50Mi"),
  271. hardThreshold: evictionapi.ThresholdValue{
  272. Percentage: 0.05,
  273. },
  274. capacity: getResourceList("10", "10Gi"),
  275. },
  276. {
  277. kubeReserved: v1.ResourceList{},
  278. systemReserved: v1.ResourceList{},
  279. capacity: getResourceList("10", "10Gi"),
  280. },
  281. {
  282. kubeReserved: getResourceList("", "100Mi"),
  283. systemReserved: getResourceList("50m", "50Mi"),
  284. capacity: getResourceList("10", "10Gi"),
  285. },
  286. {
  287. kubeReserved: getResourceList("50m", "100Mi"),
  288. systemReserved: getResourceList("", "50Mi"),
  289. capacity: getResourceList("10", "10Gi"),
  290. },
  291. {
  292. kubeReserved: getResourceList("", "100Mi"),
  293. systemReserved: getResourceList("", "50Mi"),
  294. capacity: getResourceList("10", ""),
  295. },
  296. {
  297. kubeReserved: getResourceList("5", "10Gi"),
  298. systemReserved: getResourceList("5", "10Gi"),
  299. hardThreshold: evictionapi.ThresholdValue{
  300. Quantity: &highMemoryEvictionThreshold,
  301. },
  302. capacity: getResourceList("10", "11Gi"),
  303. invalidConfiguration: true,
  304. },
  305. }
  306. for _, tc := range cpuMemTestCases {
  307. nc := NodeConfig{
  308. NodeAllocatableConfig: NodeAllocatableConfig{
  309. KubeReserved: tc.kubeReserved,
  310. SystemReserved: tc.systemReserved,
  311. HardEvictionThresholds: []evictionapi.Threshold{
  312. {
  313. Signal: evictionapi.SignalMemoryAvailable,
  314. Operator: evictionapi.OpLessThan,
  315. Value: tc.hardThreshold,
  316. },
  317. },
  318. },
  319. }
  320. cm := &containerManagerImpl{
  321. NodeConfig: nc,
  322. capacity: tc.capacity,
  323. }
  324. err := cm.validateNodeAllocatable()
  325. if err == nil && tc.invalidConfiguration {
  326. t.Fatalf("Expected invalid node allocatable configuration")
  327. } else if err != nil && !tc.invalidConfiguration {
  328. t.Fatalf("Expected valid node allocatable configuration: %v", err)
  329. }
  330. }
  331. ephemeralStorageEvictionThreshold := resource.MustParse("100Mi")
  332. ephemeralStorageTestCases := []struct {
  333. kubeReserved v1.ResourceList
  334. capacity v1.ResourceList
  335. hardThreshold evictionapi.ThresholdValue
  336. invalidConfiguration bool
  337. }{
  338. {
  339. kubeReserved: getEphemeralStorageResourceList("100Mi"),
  340. capacity: getEphemeralStorageResourceList("500Mi"),
  341. },
  342. {
  343. kubeReserved: getEphemeralStorageResourceList("20Gi"),
  344. hardThreshold: evictionapi.ThresholdValue{
  345. Quantity: &ephemeralStorageEvictionThreshold,
  346. },
  347. capacity: getEphemeralStorageResourceList("20Gi"),
  348. invalidConfiguration: true,
  349. },
  350. }
  351. for _, tc := range ephemeralStorageTestCases {
  352. nc := NodeConfig{
  353. NodeAllocatableConfig: NodeAllocatableConfig{
  354. KubeReserved: tc.kubeReserved,
  355. HardEvictionThresholds: []evictionapi.Threshold{
  356. {
  357. Signal: evictionapi.SignalNodeFsAvailable,
  358. Operator: evictionapi.OpLessThan,
  359. Value: tc.hardThreshold,
  360. },
  361. },
  362. },
  363. }
  364. cm := &containerManagerImpl{
  365. NodeConfig: nc,
  366. capacity: tc.capacity,
  367. }
  368. err := cm.validateNodeAllocatable()
  369. if err == nil && tc.invalidConfiguration {
  370. t.Fatalf("Expected invalid node allocatable configuration")
  371. } else if err != nil && !tc.invalidConfiguration {
  372. t.Fatalf("Expected valid node allocatable configuration: %v", err)
  373. }
  374. }
  375. }
  376. // getEphemeralStorageResourceList returns a ResourceList with the
  377. // specified ephemeral storage resource values
  378. func getEphemeralStorageResourceList(storage string) v1.ResourceList {
  379. res := v1.ResourceList{}
  380. if storage != "" {
  381. res[v1.ResourceEphemeralStorage] = resource.MustParse(storage)
  382. }
  383. return res
  384. }