setters_test.go 55 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720
  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 nodestatus
  14. import (
  15. "errors"
  16. "fmt"
  17. "net"
  18. "sort"
  19. "strconv"
  20. "testing"
  21. "time"
  22. cadvisorapiv1 "github.com/google/cadvisor/info/v1"
  23. "k8s.io/api/core/v1"
  24. apiequality "k8s.io/apimachinery/pkg/api/equality"
  25. "k8s.io/apimachinery/pkg/api/resource"
  26. metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
  27. "k8s.io/apimachinery/pkg/util/diff"
  28. "k8s.io/apimachinery/pkg/util/rand"
  29. "k8s.io/apimachinery/pkg/util/uuid"
  30. fakecloud "k8s.io/cloud-provider/fake"
  31. "k8s.io/kubernetes/pkg/kubelet/cm"
  32. kubecontainer "k8s.io/kubernetes/pkg/kubelet/container"
  33. kubecontainertest "k8s.io/kubernetes/pkg/kubelet/container/testing"
  34. "k8s.io/kubernetes/pkg/kubelet/events"
  35. "k8s.io/kubernetes/pkg/kubelet/util/sliceutils"
  36. "k8s.io/kubernetes/pkg/version"
  37. "k8s.io/kubernetes/pkg/volume"
  38. volumetest "k8s.io/kubernetes/pkg/volume/testing"
  39. "github.com/stretchr/testify/assert"
  40. "github.com/stretchr/testify/require"
  41. )
  42. const (
  43. testKubeletHostname = "127.0.0.1"
  44. )
  45. // TODO(mtaufen): below is ported from the old kubelet_node_status_test.go code, potentially add more test coverage for NodeAddress setter in future
  46. func TestNodeAddress(t *testing.T) {
  47. cases := []struct {
  48. name string
  49. hostnameOverride bool
  50. nodeIP net.IP
  51. nodeAddresses []v1.NodeAddress
  52. expectedAddresses []v1.NodeAddress
  53. shouldError bool
  54. }{
  55. {
  56. name: "A single InternalIP",
  57. nodeIP: net.ParseIP("10.1.1.1"),
  58. nodeAddresses: []v1.NodeAddress{
  59. {Type: v1.NodeInternalIP, Address: "10.1.1.1"},
  60. {Type: v1.NodeHostName, Address: testKubeletHostname},
  61. },
  62. expectedAddresses: []v1.NodeAddress{
  63. {Type: v1.NodeInternalIP, Address: "10.1.1.1"},
  64. {Type: v1.NodeHostName, Address: testKubeletHostname},
  65. },
  66. shouldError: false,
  67. },
  68. {
  69. name: "NodeIP is external",
  70. nodeIP: net.ParseIP("55.55.55.55"),
  71. nodeAddresses: []v1.NodeAddress{
  72. {Type: v1.NodeInternalIP, Address: "10.1.1.1"},
  73. {Type: v1.NodeExternalIP, Address: "55.55.55.55"},
  74. {Type: v1.NodeHostName, Address: testKubeletHostname},
  75. },
  76. expectedAddresses: []v1.NodeAddress{
  77. {Type: v1.NodeInternalIP, Address: "10.1.1.1"},
  78. {Type: v1.NodeExternalIP, Address: "55.55.55.55"},
  79. {Type: v1.NodeHostName, Address: testKubeletHostname},
  80. },
  81. shouldError: false,
  82. },
  83. {
  84. // Accommodating #45201 and #49202
  85. name: "InternalIP and ExternalIP are the same",
  86. nodeIP: net.ParseIP("55.55.55.55"),
  87. nodeAddresses: []v1.NodeAddress{
  88. {Type: v1.NodeInternalIP, Address: "44.44.44.44"},
  89. {Type: v1.NodeExternalIP, Address: "44.44.44.44"},
  90. {Type: v1.NodeInternalIP, Address: "55.55.55.55"},
  91. {Type: v1.NodeExternalIP, Address: "55.55.55.55"},
  92. {Type: v1.NodeHostName, Address: testKubeletHostname},
  93. },
  94. expectedAddresses: []v1.NodeAddress{
  95. {Type: v1.NodeInternalIP, Address: "55.55.55.55"},
  96. {Type: v1.NodeExternalIP, Address: "55.55.55.55"},
  97. {Type: v1.NodeHostName, Address: testKubeletHostname},
  98. },
  99. shouldError: false,
  100. },
  101. {
  102. name: "An Internal/ExternalIP, an Internal/ExternalDNS",
  103. nodeIP: net.ParseIP("10.1.1.1"),
  104. nodeAddresses: []v1.NodeAddress{
  105. {Type: v1.NodeInternalIP, Address: "10.1.1.1"},
  106. {Type: v1.NodeExternalIP, Address: "55.55.55.55"},
  107. {Type: v1.NodeInternalDNS, Address: "ip-10-1-1-1.us-west-2.compute.internal"},
  108. {Type: v1.NodeExternalDNS, Address: "ec2-55-55-55-55.us-west-2.compute.amazonaws.com"},
  109. {Type: v1.NodeHostName, Address: testKubeletHostname},
  110. },
  111. expectedAddresses: []v1.NodeAddress{
  112. {Type: v1.NodeInternalIP, Address: "10.1.1.1"},
  113. {Type: v1.NodeExternalIP, Address: "55.55.55.55"},
  114. {Type: v1.NodeInternalDNS, Address: "ip-10-1-1-1.us-west-2.compute.internal"},
  115. {Type: v1.NodeExternalDNS, Address: "ec2-55-55-55-55.us-west-2.compute.amazonaws.com"},
  116. {Type: v1.NodeHostName, Address: testKubeletHostname},
  117. },
  118. shouldError: false,
  119. },
  120. {
  121. name: "An Internal with multiple internal IPs",
  122. nodeIP: net.ParseIP("10.1.1.1"),
  123. nodeAddresses: []v1.NodeAddress{
  124. {Type: v1.NodeInternalIP, Address: "10.1.1.1"},
  125. {Type: v1.NodeInternalIP, Address: "10.2.2.2"},
  126. {Type: v1.NodeInternalIP, Address: "10.3.3.3"},
  127. {Type: v1.NodeExternalIP, Address: "55.55.55.55"},
  128. {Type: v1.NodeHostName, Address: testKubeletHostname},
  129. },
  130. expectedAddresses: []v1.NodeAddress{
  131. {Type: v1.NodeInternalIP, Address: "10.1.1.1"},
  132. {Type: v1.NodeExternalIP, Address: "55.55.55.55"},
  133. {Type: v1.NodeHostName, Address: testKubeletHostname},
  134. },
  135. shouldError: false,
  136. },
  137. {
  138. name: "An InternalIP that isn't valid: should error",
  139. nodeIP: net.ParseIP("10.2.2.2"),
  140. nodeAddresses: []v1.NodeAddress{
  141. {Type: v1.NodeInternalIP, Address: "10.1.1.1"},
  142. {Type: v1.NodeExternalIP, Address: "55.55.55.55"},
  143. {Type: v1.NodeHostName, Address: testKubeletHostname},
  144. },
  145. expectedAddresses: nil,
  146. shouldError: true,
  147. },
  148. {
  149. name: "no cloud reported hostnames",
  150. nodeAddresses: []v1.NodeAddress{},
  151. expectedAddresses: []v1.NodeAddress{
  152. {Type: v1.NodeHostName, Address: testKubeletHostname}, // detected hostname is auto-added in the absence of cloud-reported hostnames
  153. },
  154. shouldError: false,
  155. },
  156. {
  157. name: "cloud reports hostname, no override",
  158. nodeAddresses: []v1.NodeAddress{
  159. {Type: v1.NodeInternalIP, Address: "10.1.1.1"},
  160. {Type: v1.NodeExternalIP, Address: "55.55.55.55"},
  161. {Type: v1.NodeHostName, Address: "cloud-host"},
  162. },
  163. expectedAddresses: []v1.NodeAddress{
  164. {Type: v1.NodeInternalIP, Address: "10.1.1.1"},
  165. {Type: v1.NodeExternalIP, Address: "55.55.55.55"},
  166. {Type: v1.NodeHostName, Address: "cloud-host"}, // cloud-reported hostname wins over detected hostname
  167. },
  168. shouldError: false,
  169. },
  170. {
  171. name: "cloud reports hostname, overridden",
  172. nodeAddresses: []v1.NodeAddress{
  173. {Type: v1.NodeInternalIP, Address: "10.1.1.1"},
  174. {Type: v1.NodeHostName, Address: "cloud-host"},
  175. {Type: v1.NodeExternalIP, Address: "55.55.55.55"},
  176. },
  177. expectedAddresses: []v1.NodeAddress{
  178. {Type: v1.NodeInternalIP, Address: "10.1.1.1"},
  179. {Type: v1.NodeHostName, Address: testKubeletHostname}, // hostname-override wins over cloud-reported hostname
  180. {Type: v1.NodeExternalIP, Address: "55.55.55.55"},
  181. },
  182. hostnameOverride: true,
  183. shouldError: false,
  184. },
  185. {
  186. name: "cloud doesn't report hostname, no override, detected hostname mismatch",
  187. nodeAddresses: []v1.NodeAddress{
  188. {Type: v1.NodeInternalIP, Address: "10.1.1.1"},
  189. {Type: v1.NodeExternalIP, Address: "55.55.55.55"},
  190. },
  191. expectedAddresses: []v1.NodeAddress{
  192. {Type: v1.NodeInternalIP, Address: "10.1.1.1"},
  193. {Type: v1.NodeExternalIP, Address: "55.55.55.55"},
  194. // detected hostname is not auto-added if it doesn't match any cloud-reported addresses
  195. },
  196. shouldError: false,
  197. },
  198. {
  199. name: "cloud doesn't report hostname, no override, detected hostname match",
  200. nodeAddresses: []v1.NodeAddress{
  201. {Type: v1.NodeInternalIP, Address: "10.1.1.1"},
  202. {Type: v1.NodeExternalIP, Address: "55.55.55.55"},
  203. {Type: v1.NodeExternalDNS, Address: testKubeletHostname}, // cloud-reported address value matches detected hostname
  204. },
  205. expectedAddresses: []v1.NodeAddress{
  206. {Type: v1.NodeInternalIP, Address: "10.1.1.1"},
  207. {Type: v1.NodeExternalIP, Address: "55.55.55.55"},
  208. {Type: v1.NodeExternalDNS, Address: testKubeletHostname},
  209. {Type: v1.NodeHostName, Address: testKubeletHostname}, // detected hostname gets auto-added
  210. },
  211. shouldError: false,
  212. },
  213. {
  214. name: "cloud doesn't report hostname, hostname override, hostname mismatch",
  215. nodeAddresses: []v1.NodeAddress{
  216. {Type: v1.NodeInternalIP, Address: "10.1.1.1"},
  217. {Type: v1.NodeExternalIP, Address: "55.55.55.55"},
  218. },
  219. expectedAddresses: []v1.NodeAddress{
  220. {Type: v1.NodeInternalIP, Address: "10.1.1.1"},
  221. {Type: v1.NodeExternalIP, Address: "55.55.55.55"},
  222. {Type: v1.NodeHostName, Address: testKubeletHostname}, // overridden hostname gets auto-added
  223. },
  224. hostnameOverride: true,
  225. shouldError: false,
  226. },
  227. }
  228. for _, testCase := range cases {
  229. t.Run(testCase.name, func(t *testing.T) {
  230. // testCase setup
  231. existingNode := &v1.Node{
  232. ObjectMeta: metav1.ObjectMeta{Name: testKubeletHostname, Annotations: make(map[string]string)},
  233. Spec: v1.NodeSpec{},
  234. }
  235. nodeIP := testCase.nodeIP
  236. nodeIPValidator := func(nodeIP net.IP) error {
  237. return nil
  238. }
  239. hostname := testKubeletHostname
  240. externalCloudProvider := false
  241. cloud := &fakecloud.Cloud{
  242. Addresses: testCase.nodeAddresses,
  243. Err: nil,
  244. }
  245. nodeAddressesFunc := func() ([]v1.NodeAddress, error) {
  246. return testCase.nodeAddresses, nil
  247. }
  248. // construct setter
  249. setter := NodeAddress(nodeIP,
  250. nodeIPValidator,
  251. hostname,
  252. testCase.hostnameOverride,
  253. externalCloudProvider,
  254. cloud,
  255. nodeAddressesFunc)
  256. // call setter on existing node
  257. err := setter(existingNode)
  258. if err != nil && !testCase.shouldError {
  259. t.Fatalf("unexpected error: %v", err)
  260. } else if err != nil && testCase.shouldError {
  261. // expected an error, and got one, so just return early here
  262. return
  263. }
  264. // Sort both sets for consistent equality
  265. sortNodeAddresses(testCase.expectedAddresses)
  266. sortNodeAddresses(existingNode.Status.Addresses)
  267. assert.True(t, apiequality.Semantic.DeepEqual(testCase.expectedAddresses, existingNode.Status.Addresses),
  268. "Diff: %s", diff.ObjectDiff(testCase.expectedAddresses, existingNode.Status.Addresses))
  269. })
  270. }
  271. }
  272. func TestMachineInfo(t *testing.T) {
  273. const nodeName = "test-node"
  274. type dprc struct {
  275. capacity v1.ResourceList
  276. allocatable v1.ResourceList
  277. inactive []string
  278. }
  279. cases := []struct {
  280. desc string
  281. node *v1.Node
  282. maxPods int
  283. podsPerCore int
  284. machineInfo *cadvisorapiv1.MachineInfo
  285. machineInfoError error
  286. capacity v1.ResourceList
  287. devicePluginResourceCapacity dprc
  288. nodeAllocatableReservation v1.ResourceList
  289. expectNode *v1.Node
  290. expectEvents []testEvent
  291. }{
  292. {
  293. desc: "machine identifiers, basic capacity and allocatable",
  294. node: &v1.Node{},
  295. maxPods: 110,
  296. machineInfo: &cadvisorapiv1.MachineInfo{
  297. MachineID: "MachineID",
  298. SystemUUID: "SystemUUID",
  299. NumCores: 2,
  300. MemoryCapacity: 1024,
  301. },
  302. expectNode: &v1.Node{
  303. Status: v1.NodeStatus{
  304. NodeInfo: v1.NodeSystemInfo{
  305. MachineID: "MachineID",
  306. SystemUUID: "SystemUUID",
  307. },
  308. Capacity: v1.ResourceList{
  309. v1.ResourceCPU: *resource.NewMilliQuantity(2000, resource.DecimalSI),
  310. v1.ResourceMemory: *resource.NewQuantity(1024, resource.BinarySI),
  311. v1.ResourcePods: *resource.NewQuantity(110, resource.DecimalSI),
  312. },
  313. Allocatable: v1.ResourceList{
  314. v1.ResourceCPU: *resource.NewMilliQuantity(2000, resource.DecimalSI),
  315. v1.ResourceMemory: *resource.NewQuantity(1024, resource.BinarySI),
  316. v1.ResourcePods: *resource.NewQuantity(110, resource.DecimalSI),
  317. },
  318. },
  319. },
  320. },
  321. {
  322. desc: "podsPerCore greater than zero, but less than maxPods/cores",
  323. node: &v1.Node{},
  324. maxPods: 10,
  325. podsPerCore: 4,
  326. machineInfo: &cadvisorapiv1.MachineInfo{
  327. NumCores: 2,
  328. MemoryCapacity: 1024,
  329. },
  330. expectNode: &v1.Node{
  331. Status: v1.NodeStatus{
  332. Capacity: v1.ResourceList{
  333. v1.ResourceCPU: *resource.NewMilliQuantity(2000, resource.DecimalSI),
  334. v1.ResourceMemory: *resource.NewQuantity(1024, resource.BinarySI),
  335. v1.ResourcePods: *resource.NewQuantity(8, resource.DecimalSI),
  336. },
  337. Allocatable: v1.ResourceList{
  338. v1.ResourceCPU: *resource.NewMilliQuantity(2000, resource.DecimalSI),
  339. v1.ResourceMemory: *resource.NewQuantity(1024, resource.BinarySI),
  340. v1.ResourcePods: *resource.NewQuantity(8, resource.DecimalSI),
  341. },
  342. },
  343. },
  344. },
  345. {
  346. desc: "podsPerCore greater than maxPods/cores",
  347. node: &v1.Node{},
  348. maxPods: 10,
  349. podsPerCore: 6,
  350. machineInfo: &cadvisorapiv1.MachineInfo{
  351. NumCores: 2,
  352. MemoryCapacity: 1024,
  353. },
  354. expectNode: &v1.Node{
  355. Status: v1.NodeStatus{
  356. Capacity: v1.ResourceList{
  357. v1.ResourceCPU: *resource.NewMilliQuantity(2000, resource.DecimalSI),
  358. v1.ResourceMemory: *resource.NewQuantity(1024, resource.BinarySI),
  359. v1.ResourcePods: *resource.NewQuantity(10, resource.DecimalSI),
  360. },
  361. Allocatable: v1.ResourceList{
  362. v1.ResourceCPU: *resource.NewMilliQuantity(2000, resource.DecimalSI),
  363. v1.ResourceMemory: *resource.NewQuantity(1024, resource.BinarySI),
  364. v1.ResourcePods: *resource.NewQuantity(10, resource.DecimalSI),
  365. },
  366. },
  367. },
  368. },
  369. {
  370. desc: "allocatable should equal capacity minus reservations",
  371. node: &v1.Node{},
  372. maxPods: 110,
  373. machineInfo: &cadvisorapiv1.MachineInfo{
  374. NumCores: 2,
  375. MemoryCapacity: 1024,
  376. },
  377. nodeAllocatableReservation: v1.ResourceList{
  378. // reserve 1 unit for each resource
  379. v1.ResourceCPU: *resource.NewMilliQuantity(1, resource.DecimalSI),
  380. v1.ResourceMemory: *resource.NewQuantity(1, resource.BinarySI),
  381. v1.ResourcePods: *resource.NewQuantity(1, resource.DecimalSI),
  382. v1.ResourceEphemeralStorage: *resource.NewQuantity(1, resource.BinarySI),
  383. },
  384. expectNode: &v1.Node{
  385. Status: v1.NodeStatus{
  386. Capacity: v1.ResourceList{
  387. v1.ResourceCPU: *resource.NewMilliQuantity(2000, resource.DecimalSI),
  388. v1.ResourceMemory: *resource.NewQuantity(1024, resource.BinarySI),
  389. v1.ResourcePods: *resource.NewQuantity(110, resource.DecimalSI),
  390. },
  391. Allocatable: v1.ResourceList{
  392. v1.ResourceCPU: *resource.NewMilliQuantity(1999, resource.DecimalSI),
  393. v1.ResourceMemory: *resource.NewQuantity(1023, resource.BinarySI),
  394. v1.ResourcePods: *resource.NewQuantity(109, resource.DecimalSI),
  395. },
  396. },
  397. },
  398. },
  399. {
  400. desc: "allocatable memory does not double-count hugepages reservations",
  401. node: &v1.Node{
  402. Status: v1.NodeStatus{
  403. Capacity: v1.ResourceList{
  404. // it's impossible on any real system to reserve 1 byte,
  405. // but we just need to test that the setter does the math
  406. v1.ResourceHugePagesPrefix + "test": *resource.NewQuantity(1, resource.BinarySI),
  407. },
  408. },
  409. },
  410. maxPods: 110,
  411. machineInfo: &cadvisorapiv1.MachineInfo{
  412. NumCores: 2,
  413. MemoryCapacity: 1024,
  414. },
  415. expectNode: &v1.Node{
  416. Status: v1.NodeStatus{
  417. Capacity: v1.ResourceList{
  418. v1.ResourceCPU: *resource.NewMilliQuantity(2000, resource.DecimalSI),
  419. v1.ResourceMemory: *resource.NewQuantity(1024, resource.BinarySI),
  420. v1.ResourceHugePagesPrefix + "test": *resource.NewQuantity(1, resource.BinarySI),
  421. v1.ResourcePods: *resource.NewQuantity(110, resource.DecimalSI),
  422. },
  423. Allocatable: v1.ResourceList{
  424. v1.ResourceCPU: *resource.NewMilliQuantity(2000, resource.DecimalSI),
  425. // memory has 1-unit difference for hugepages reservation
  426. v1.ResourceMemory: *resource.NewQuantity(1023, resource.BinarySI),
  427. v1.ResourceHugePagesPrefix + "test": *resource.NewQuantity(1, resource.BinarySI),
  428. v1.ResourcePods: *resource.NewQuantity(110, resource.DecimalSI),
  429. },
  430. },
  431. },
  432. },
  433. {
  434. desc: "negative capacity resources should be set to 0 in allocatable",
  435. node: &v1.Node{
  436. Status: v1.NodeStatus{
  437. Capacity: v1.ResourceList{
  438. "negative-resource": *resource.NewQuantity(-1, resource.BinarySI),
  439. },
  440. },
  441. },
  442. maxPods: 110,
  443. machineInfo: &cadvisorapiv1.MachineInfo{
  444. NumCores: 2,
  445. MemoryCapacity: 1024,
  446. },
  447. expectNode: &v1.Node{
  448. Status: v1.NodeStatus{
  449. Capacity: v1.ResourceList{
  450. v1.ResourceCPU: *resource.NewMilliQuantity(2000, resource.DecimalSI),
  451. v1.ResourceMemory: *resource.NewQuantity(1024, resource.BinarySI),
  452. v1.ResourcePods: *resource.NewQuantity(110, resource.DecimalSI),
  453. "negative-resource": *resource.NewQuantity(-1, resource.BinarySI),
  454. },
  455. Allocatable: v1.ResourceList{
  456. v1.ResourceCPU: *resource.NewMilliQuantity(2000, resource.DecimalSI),
  457. v1.ResourceMemory: *resource.NewQuantity(1024, resource.BinarySI),
  458. v1.ResourcePods: *resource.NewQuantity(110, resource.DecimalSI),
  459. "negative-resource": *resource.NewQuantity(0, resource.BinarySI),
  460. },
  461. },
  462. },
  463. },
  464. {
  465. desc: "ephemeral storage is reflected in capacity and allocatable",
  466. node: &v1.Node{},
  467. maxPods: 110,
  468. machineInfo: &cadvisorapiv1.MachineInfo{
  469. NumCores: 2,
  470. MemoryCapacity: 1024,
  471. },
  472. capacity: v1.ResourceList{
  473. v1.ResourceEphemeralStorage: *resource.NewQuantity(5000, resource.BinarySI),
  474. },
  475. expectNode: &v1.Node{
  476. Status: v1.NodeStatus{
  477. Capacity: v1.ResourceList{
  478. v1.ResourceCPU: *resource.NewMilliQuantity(2000, resource.DecimalSI),
  479. v1.ResourceMemory: *resource.NewQuantity(1024, resource.BinarySI),
  480. v1.ResourcePods: *resource.NewQuantity(110, resource.DecimalSI),
  481. v1.ResourceEphemeralStorage: *resource.NewQuantity(5000, resource.BinarySI),
  482. },
  483. Allocatable: v1.ResourceList{
  484. v1.ResourceCPU: *resource.NewMilliQuantity(2000, resource.DecimalSI),
  485. v1.ResourceMemory: *resource.NewQuantity(1024, resource.BinarySI),
  486. v1.ResourcePods: *resource.NewQuantity(110, resource.DecimalSI),
  487. v1.ResourceEphemeralStorage: *resource.NewQuantity(5000, resource.BinarySI),
  488. },
  489. },
  490. },
  491. },
  492. {
  493. desc: "device plugin resources are reflected in capacity and allocatable",
  494. node: &v1.Node{},
  495. maxPods: 110,
  496. machineInfo: &cadvisorapiv1.MachineInfo{
  497. NumCores: 2,
  498. MemoryCapacity: 1024,
  499. },
  500. devicePluginResourceCapacity: dprc{
  501. capacity: v1.ResourceList{
  502. "device-plugin": *resource.NewQuantity(1, resource.BinarySI),
  503. },
  504. allocatable: v1.ResourceList{
  505. "device-plugin": *resource.NewQuantity(1, resource.BinarySI),
  506. },
  507. },
  508. expectNode: &v1.Node{
  509. Status: v1.NodeStatus{
  510. Capacity: v1.ResourceList{
  511. v1.ResourceCPU: *resource.NewMilliQuantity(2000, resource.DecimalSI),
  512. v1.ResourceMemory: *resource.NewQuantity(1024, resource.BinarySI),
  513. v1.ResourcePods: *resource.NewQuantity(110, resource.DecimalSI),
  514. "device-plugin": *resource.NewQuantity(1, resource.BinarySI),
  515. },
  516. Allocatable: v1.ResourceList{
  517. v1.ResourceCPU: *resource.NewMilliQuantity(2000, resource.DecimalSI),
  518. v1.ResourceMemory: *resource.NewQuantity(1024, resource.BinarySI),
  519. v1.ResourcePods: *resource.NewQuantity(110, resource.DecimalSI),
  520. "device-plugin": *resource.NewQuantity(1, resource.BinarySI),
  521. },
  522. },
  523. },
  524. },
  525. {
  526. desc: "inactive device plugin resources should have their capacity set to 0",
  527. node: &v1.Node{
  528. Status: v1.NodeStatus{
  529. Capacity: v1.ResourceList{
  530. "inactive": *resource.NewQuantity(1, resource.BinarySI),
  531. },
  532. },
  533. },
  534. maxPods: 110,
  535. machineInfo: &cadvisorapiv1.MachineInfo{
  536. NumCores: 2,
  537. MemoryCapacity: 1024,
  538. },
  539. devicePluginResourceCapacity: dprc{
  540. inactive: []string{"inactive"},
  541. },
  542. expectNode: &v1.Node{
  543. Status: v1.NodeStatus{
  544. Capacity: v1.ResourceList{
  545. v1.ResourceCPU: *resource.NewMilliQuantity(2000, resource.DecimalSI),
  546. v1.ResourceMemory: *resource.NewQuantity(1024, resource.BinarySI),
  547. v1.ResourcePods: *resource.NewQuantity(110, resource.DecimalSI),
  548. "inactive": *resource.NewQuantity(0, resource.BinarySI),
  549. },
  550. Allocatable: v1.ResourceList{
  551. v1.ResourceCPU: *resource.NewMilliQuantity(2000, resource.DecimalSI),
  552. v1.ResourceMemory: *resource.NewQuantity(1024, resource.BinarySI),
  553. v1.ResourcePods: *resource.NewQuantity(110, resource.DecimalSI),
  554. "inactive": *resource.NewQuantity(0, resource.BinarySI),
  555. },
  556. },
  557. },
  558. },
  559. {
  560. desc: "extended resources not present in capacity are removed from allocatable",
  561. node: &v1.Node{
  562. Status: v1.NodeStatus{
  563. Allocatable: v1.ResourceList{
  564. "example.com/extended": *resource.NewQuantity(1, resource.BinarySI),
  565. },
  566. },
  567. },
  568. maxPods: 110,
  569. machineInfo: &cadvisorapiv1.MachineInfo{
  570. NumCores: 2,
  571. MemoryCapacity: 1024,
  572. },
  573. expectNode: &v1.Node{
  574. Status: v1.NodeStatus{
  575. Capacity: v1.ResourceList{
  576. v1.ResourceCPU: *resource.NewMilliQuantity(2000, resource.DecimalSI),
  577. v1.ResourceMemory: *resource.NewQuantity(1024, resource.BinarySI),
  578. v1.ResourcePods: *resource.NewQuantity(110, resource.DecimalSI),
  579. },
  580. Allocatable: v1.ResourceList{
  581. v1.ResourceCPU: *resource.NewMilliQuantity(2000, resource.DecimalSI),
  582. v1.ResourceMemory: *resource.NewQuantity(1024, resource.BinarySI),
  583. v1.ResourcePods: *resource.NewQuantity(110, resource.DecimalSI),
  584. },
  585. },
  586. },
  587. },
  588. {
  589. desc: "on failure to get machine info, allocatable and capacity for memory and cpu are set to 0, pods to maxPods",
  590. node: &v1.Node{},
  591. maxPods: 110,
  592. // podsPerCore is not accounted for when getting machine info fails
  593. podsPerCore: 1,
  594. machineInfoError: fmt.Errorf("foo"),
  595. expectNode: &v1.Node{
  596. Status: v1.NodeStatus{
  597. Capacity: v1.ResourceList{
  598. v1.ResourceCPU: *resource.NewMilliQuantity(0, resource.DecimalSI),
  599. v1.ResourceMemory: resource.MustParse("0Gi"),
  600. v1.ResourcePods: *resource.NewQuantity(110, resource.DecimalSI),
  601. },
  602. Allocatable: v1.ResourceList{
  603. v1.ResourceCPU: *resource.NewMilliQuantity(0, resource.DecimalSI),
  604. v1.ResourceMemory: resource.MustParse("0Gi"),
  605. v1.ResourcePods: *resource.NewQuantity(110, resource.DecimalSI),
  606. },
  607. },
  608. },
  609. },
  610. {
  611. desc: "node reboot event is recorded",
  612. node: &v1.Node{
  613. Status: v1.NodeStatus{
  614. NodeInfo: v1.NodeSystemInfo{
  615. BootID: "foo",
  616. },
  617. },
  618. },
  619. maxPods: 110,
  620. machineInfo: &cadvisorapiv1.MachineInfo{
  621. BootID: "bar",
  622. NumCores: 2,
  623. MemoryCapacity: 1024,
  624. },
  625. expectNode: &v1.Node{
  626. Status: v1.NodeStatus{
  627. NodeInfo: v1.NodeSystemInfo{
  628. BootID: "bar",
  629. },
  630. Capacity: v1.ResourceList{
  631. v1.ResourceCPU: *resource.NewMilliQuantity(2000, resource.DecimalSI),
  632. v1.ResourceMemory: *resource.NewQuantity(1024, resource.BinarySI),
  633. v1.ResourcePods: *resource.NewQuantity(110, resource.DecimalSI),
  634. },
  635. Allocatable: v1.ResourceList{
  636. v1.ResourceCPU: *resource.NewMilliQuantity(2000, resource.DecimalSI),
  637. v1.ResourceMemory: *resource.NewQuantity(1024, resource.BinarySI),
  638. v1.ResourcePods: *resource.NewQuantity(110, resource.DecimalSI),
  639. },
  640. },
  641. },
  642. expectEvents: []testEvent{
  643. {
  644. eventType: v1.EventTypeWarning,
  645. event: events.NodeRebooted,
  646. message: fmt.Sprintf("Node %s has been rebooted, boot id: %s", nodeName, "bar"),
  647. },
  648. },
  649. },
  650. }
  651. for _, tc := range cases {
  652. t.Run(tc.desc, func(t *testing.T) {
  653. machineInfoFunc := func() (*cadvisorapiv1.MachineInfo, error) {
  654. return tc.machineInfo, tc.machineInfoError
  655. }
  656. capacityFunc := func() v1.ResourceList {
  657. return tc.capacity
  658. }
  659. devicePluginResourceCapacityFunc := func() (v1.ResourceList, v1.ResourceList, []string) {
  660. c := tc.devicePluginResourceCapacity
  661. return c.capacity, c.allocatable, c.inactive
  662. }
  663. nodeAllocatableReservationFunc := func() v1.ResourceList {
  664. return tc.nodeAllocatableReservation
  665. }
  666. events := []testEvent{}
  667. recordEventFunc := func(eventType, event, message string) {
  668. events = append(events, testEvent{
  669. eventType: eventType,
  670. event: event,
  671. message: message,
  672. })
  673. }
  674. // construct setter
  675. setter := MachineInfo(nodeName, tc.maxPods, tc.podsPerCore, machineInfoFunc, capacityFunc,
  676. devicePluginResourceCapacityFunc, nodeAllocatableReservationFunc, recordEventFunc)
  677. // call setter on node
  678. if err := setter(tc.node); err != nil {
  679. t.Fatalf("unexpected error: %v", err)
  680. }
  681. // check expected node
  682. assert.True(t, apiequality.Semantic.DeepEqual(tc.expectNode, tc.node),
  683. "Diff: %s", diff.ObjectDiff(tc.expectNode, tc.node))
  684. // check expected events
  685. require.Equal(t, len(tc.expectEvents), len(events))
  686. for i := range tc.expectEvents {
  687. assert.Equal(t, tc.expectEvents[i], events[i])
  688. }
  689. })
  690. }
  691. }
  692. func TestVersionInfo(t *testing.T) {
  693. cases := []struct {
  694. desc string
  695. node *v1.Node
  696. versionInfo *cadvisorapiv1.VersionInfo
  697. versionInfoError error
  698. runtimeType string
  699. runtimeVersion kubecontainer.Version
  700. runtimeVersionError error
  701. expectNode *v1.Node
  702. expectError error
  703. }{
  704. {
  705. desc: "versions set in node info",
  706. node: &v1.Node{},
  707. versionInfo: &cadvisorapiv1.VersionInfo{
  708. KernelVersion: "KernelVersion",
  709. ContainerOsVersion: "ContainerOSVersion",
  710. },
  711. runtimeType: "RuntimeType",
  712. runtimeVersion: &kubecontainertest.FakeVersion{
  713. Version: "RuntimeVersion",
  714. },
  715. expectNode: &v1.Node{
  716. Status: v1.NodeStatus{
  717. NodeInfo: v1.NodeSystemInfo{
  718. KernelVersion: "KernelVersion",
  719. OSImage: "ContainerOSVersion",
  720. ContainerRuntimeVersion: "RuntimeType://RuntimeVersion",
  721. KubeletVersion: version.Get().String(),
  722. KubeProxyVersion: version.Get().String(),
  723. },
  724. },
  725. },
  726. },
  727. {
  728. desc: "error getting version info",
  729. node: &v1.Node{},
  730. versionInfoError: fmt.Errorf("foo"),
  731. expectNode: &v1.Node{},
  732. expectError: fmt.Errorf("error getting version info: foo"),
  733. },
  734. {
  735. desc: "error getting runtime version results in Unknown runtime",
  736. node: &v1.Node{},
  737. versionInfo: &cadvisorapiv1.VersionInfo{},
  738. runtimeType: "RuntimeType",
  739. runtimeVersionError: fmt.Errorf("foo"),
  740. expectNode: &v1.Node{
  741. Status: v1.NodeStatus{
  742. NodeInfo: v1.NodeSystemInfo{
  743. ContainerRuntimeVersion: "RuntimeType://Unknown",
  744. KubeletVersion: version.Get().String(),
  745. KubeProxyVersion: version.Get().String(),
  746. },
  747. },
  748. },
  749. },
  750. }
  751. for _, tc := range cases {
  752. t.Run(tc.desc, func(t *testing.T) {
  753. versionInfoFunc := func() (*cadvisorapiv1.VersionInfo, error) {
  754. return tc.versionInfo, tc.versionInfoError
  755. }
  756. runtimeTypeFunc := func() string {
  757. return tc.runtimeType
  758. }
  759. runtimeVersionFunc := func() (kubecontainer.Version, error) {
  760. return tc.runtimeVersion, tc.runtimeVersionError
  761. }
  762. // construct setter
  763. setter := VersionInfo(versionInfoFunc, runtimeTypeFunc, runtimeVersionFunc)
  764. // call setter on node
  765. err := setter(tc.node)
  766. require.Equal(t, tc.expectError, err)
  767. // check expected node
  768. assert.True(t, apiequality.Semantic.DeepEqual(tc.expectNode, tc.node),
  769. "Diff: %s", diff.ObjectDiff(tc.expectNode, tc.node))
  770. })
  771. }
  772. }
  773. func TestImages(t *testing.T) {
  774. const (
  775. minImageSize = 23 * 1024 * 1024
  776. maxImageSize = 1000 * 1024 * 1024
  777. )
  778. cases := []struct {
  779. desc string
  780. maxImages int32
  781. imageList []kubecontainer.Image
  782. imageListError error
  783. expectError error
  784. }{
  785. {
  786. desc: "max images enforced",
  787. maxImages: 1,
  788. imageList: makeImageList(2, 1, minImageSize, maxImageSize),
  789. },
  790. {
  791. desc: "no max images cap for -1",
  792. maxImages: -1,
  793. imageList: makeImageList(2, 1, minImageSize, maxImageSize),
  794. },
  795. {
  796. desc: "max names per image enforced",
  797. maxImages: -1,
  798. imageList: makeImageList(1, MaxNamesPerImageInNodeStatus+1, minImageSize, maxImageSize),
  799. },
  800. {
  801. desc: "images are sorted by size, descending",
  802. maxImages: -1,
  803. // makeExpectedImageList will sort them for expectedNode when the test case is run
  804. imageList: []kubecontainer.Image{{Size: 3}, {Size: 1}, {Size: 4}, {Size: 2}},
  805. },
  806. {
  807. desc: "repo digests and tags both show up in image names",
  808. maxImages: -1,
  809. // makeExpectedImageList will use both digests and tags
  810. imageList: []kubecontainer.Image{
  811. {
  812. RepoDigests: []string{"foo", "bar"},
  813. RepoTags: []string{"baz", "quux"},
  814. },
  815. },
  816. },
  817. {
  818. desc: "error getting image list, image list on node is reset to empty",
  819. maxImages: -1,
  820. imageListError: fmt.Errorf("foo"),
  821. expectError: fmt.Errorf("error getting image list: foo"),
  822. },
  823. }
  824. for _, tc := range cases {
  825. t.Run(tc.desc, func(t *testing.T) {
  826. imageListFunc := func() ([]kubecontainer.Image, error) {
  827. // today, imageListFunc is expected to return a sorted list,
  828. // but we may choose to sort in the setter at some future point
  829. // (e.g. if the image cache stopped sorting for us)
  830. sort.Sort(sliceutils.ByImageSize(tc.imageList))
  831. return tc.imageList, tc.imageListError
  832. }
  833. // construct setter
  834. setter := Images(tc.maxImages, imageListFunc)
  835. // call setter on node
  836. node := &v1.Node{}
  837. err := setter(node)
  838. require.Equal(t, tc.expectError, err)
  839. // check expected node, image list should be reset to empty when there is an error
  840. expectNode := &v1.Node{}
  841. if err == nil {
  842. expectNode.Status.Images = makeExpectedImageList(tc.imageList, tc.maxImages, MaxNamesPerImageInNodeStatus)
  843. }
  844. assert.True(t, apiequality.Semantic.DeepEqual(expectNode, node),
  845. "Diff: %s", diff.ObjectDiff(expectNode, node))
  846. })
  847. }
  848. }
  849. func TestReadyCondition(t *testing.T) {
  850. now := time.Now()
  851. before := now.Add(-time.Second)
  852. nowFunc := func() time.Time { return now }
  853. withCapacity := &v1.Node{
  854. Status: v1.NodeStatus{
  855. Capacity: v1.ResourceList{
  856. v1.ResourceCPU: *resource.NewMilliQuantity(2000, resource.DecimalSI),
  857. v1.ResourceMemory: *resource.NewQuantity(10E9, resource.BinarySI),
  858. v1.ResourcePods: *resource.NewQuantity(100, resource.DecimalSI),
  859. v1.ResourceEphemeralStorage: *resource.NewQuantity(5000, resource.BinarySI),
  860. },
  861. },
  862. }
  863. cases := []struct {
  864. desc string
  865. node *v1.Node
  866. runtimeErrors error
  867. networkErrors error
  868. storageErrors error
  869. appArmorValidateHostFunc func() error
  870. cmStatus cm.Status
  871. expectConditions []v1.NodeCondition
  872. expectEvents []testEvent
  873. }{
  874. {
  875. desc: "new, ready",
  876. node: withCapacity.DeepCopy(),
  877. expectConditions: []v1.NodeCondition{*makeReadyCondition(true, "kubelet is posting ready status", now, now)},
  878. // TODO(mtaufen): The current behavior is that we don't send an event for the initial NodeReady condition,
  879. // the reason for this is unclear, so we may want to actually send an event, and change these test cases
  880. // to ensure an event is sent.
  881. },
  882. {
  883. desc: "new, ready: apparmor validator passed",
  884. node: withCapacity.DeepCopy(),
  885. appArmorValidateHostFunc: func() error { return nil },
  886. expectConditions: []v1.NodeCondition{*makeReadyCondition(true, "kubelet is posting ready status. AppArmor enabled", now, now)},
  887. },
  888. {
  889. desc: "new, ready: apparmor validator failed",
  890. node: withCapacity.DeepCopy(),
  891. appArmorValidateHostFunc: func() error { return fmt.Errorf("foo") },
  892. // absence of an additional message is understood to mean that AppArmor is disabled
  893. expectConditions: []v1.NodeCondition{*makeReadyCondition(true, "kubelet is posting ready status", now, now)},
  894. },
  895. {
  896. desc: "new, ready: soft requirement warning",
  897. node: withCapacity.DeepCopy(),
  898. cmStatus: cm.Status{
  899. SoftRequirements: fmt.Errorf("foo"),
  900. },
  901. expectConditions: []v1.NodeCondition{*makeReadyCondition(true, "kubelet is posting ready status. WARNING: foo", now, now)},
  902. },
  903. {
  904. desc: "new, not ready: storage errors",
  905. node: withCapacity.DeepCopy(),
  906. storageErrors: errors.New("some storage error"),
  907. expectConditions: []v1.NodeCondition{*makeReadyCondition(false, "some storage error", now, now)},
  908. },
  909. {
  910. desc: "new, not ready: runtime and network errors",
  911. node: withCapacity.DeepCopy(),
  912. runtimeErrors: errors.New("runtime"),
  913. networkErrors: errors.New("network"),
  914. expectConditions: []v1.NodeCondition{*makeReadyCondition(false, "[runtime, network]", now, now)},
  915. },
  916. {
  917. desc: "new, not ready: missing capacities",
  918. node: &v1.Node{},
  919. expectConditions: []v1.NodeCondition{*makeReadyCondition(false, "Missing node capacity for resources: cpu, memory, pods, ephemeral-storage", now, now)},
  920. },
  921. // the transition tests ensure timestamps are set correctly, no need to test the entire condition matrix in this section
  922. {
  923. desc: "transition to ready",
  924. node: func() *v1.Node {
  925. node := withCapacity.DeepCopy()
  926. node.Status.Conditions = []v1.NodeCondition{*makeReadyCondition(false, "", before, before)}
  927. return node
  928. }(),
  929. expectConditions: []v1.NodeCondition{*makeReadyCondition(true, "kubelet is posting ready status", now, now)},
  930. expectEvents: []testEvent{
  931. {
  932. eventType: v1.EventTypeNormal,
  933. event: events.NodeReady,
  934. },
  935. },
  936. },
  937. {
  938. desc: "transition to not ready",
  939. node: func() *v1.Node {
  940. node := withCapacity.DeepCopy()
  941. node.Status.Conditions = []v1.NodeCondition{*makeReadyCondition(true, "", before, before)}
  942. return node
  943. }(),
  944. runtimeErrors: errors.New("foo"),
  945. expectConditions: []v1.NodeCondition{*makeReadyCondition(false, "foo", now, now)},
  946. expectEvents: []testEvent{
  947. {
  948. eventType: v1.EventTypeNormal,
  949. event: events.NodeNotReady,
  950. },
  951. },
  952. },
  953. {
  954. desc: "ready, no transition",
  955. node: func() *v1.Node {
  956. node := withCapacity.DeepCopy()
  957. node.Status.Conditions = []v1.NodeCondition{*makeReadyCondition(true, "", before, before)}
  958. return node
  959. }(),
  960. expectConditions: []v1.NodeCondition{*makeReadyCondition(true, "kubelet is posting ready status", before, now)},
  961. expectEvents: []testEvent{},
  962. },
  963. {
  964. desc: "not ready, no transition",
  965. node: func() *v1.Node {
  966. node := withCapacity.DeepCopy()
  967. node.Status.Conditions = []v1.NodeCondition{*makeReadyCondition(false, "", before, before)}
  968. return node
  969. }(),
  970. runtimeErrors: errors.New("foo"),
  971. expectConditions: []v1.NodeCondition{*makeReadyCondition(false, "foo", before, now)},
  972. expectEvents: []testEvent{},
  973. },
  974. }
  975. for _, tc := range cases {
  976. t.Run(tc.desc, func(t *testing.T) {
  977. runtimeErrorsFunc := func() error {
  978. return tc.runtimeErrors
  979. }
  980. networkErrorsFunc := func() error {
  981. return tc.networkErrors
  982. }
  983. storageErrorsFunc := func() error {
  984. return tc.storageErrors
  985. }
  986. cmStatusFunc := func() cm.Status {
  987. return tc.cmStatus
  988. }
  989. events := []testEvent{}
  990. recordEventFunc := func(eventType, event string) {
  991. events = append(events, testEvent{
  992. eventType: eventType,
  993. event: event,
  994. })
  995. }
  996. // construct setter
  997. setter := ReadyCondition(nowFunc, runtimeErrorsFunc, networkErrorsFunc, storageErrorsFunc, tc.appArmorValidateHostFunc, cmStatusFunc, recordEventFunc)
  998. // call setter on node
  999. if err := setter(tc.node); err != nil {
  1000. t.Fatalf("unexpected error: %v", err)
  1001. }
  1002. // check expected condition
  1003. assert.True(t, apiequality.Semantic.DeepEqual(tc.expectConditions, tc.node.Status.Conditions),
  1004. "Diff: %s", diff.ObjectDiff(tc.expectConditions, tc.node.Status.Conditions))
  1005. // check expected events
  1006. require.Equal(t, len(tc.expectEvents), len(events))
  1007. for i := range tc.expectEvents {
  1008. assert.Equal(t, tc.expectEvents[i], events[i])
  1009. }
  1010. })
  1011. }
  1012. }
  1013. func TestMemoryPressureCondition(t *testing.T) {
  1014. now := time.Now()
  1015. before := now.Add(-time.Second)
  1016. nowFunc := func() time.Time { return now }
  1017. cases := []struct {
  1018. desc string
  1019. node *v1.Node
  1020. pressure bool
  1021. expectConditions []v1.NodeCondition
  1022. expectEvents []testEvent
  1023. }{
  1024. {
  1025. desc: "new, no pressure",
  1026. node: &v1.Node{},
  1027. pressure: false,
  1028. expectConditions: []v1.NodeCondition{*makeMemoryPressureCondition(false, now, now)},
  1029. expectEvents: []testEvent{
  1030. {
  1031. eventType: v1.EventTypeNormal,
  1032. event: "NodeHasSufficientMemory",
  1033. },
  1034. },
  1035. },
  1036. {
  1037. desc: "new, pressure",
  1038. node: &v1.Node{},
  1039. pressure: true,
  1040. expectConditions: []v1.NodeCondition{*makeMemoryPressureCondition(true, now, now)},
  1041. expectEvents: []testEvent{
  1042. {
  1043. eventType: v1.EventTypeNormal,
  1044. event: "NodeHasInsufficientMemory",
  1045. },
  1046. },
  1047. },
  1048. {
  1049. desc: "transition to pressure",
  1050. node: &v1.Node{
  1051. Status: v1.NodeStatus{
  1052. Conditions: []v1.NodeCondition{*makeMemoryPressureCondition(false, before, before)},
  1053. },
  1054. },
  1055. pressure: true,
  1056. expectConditions: []v1.NodeCondition{*makeMemoryPressureCondition(true, now, now)},
  1057. expectEvents: []testEvent{
  1058. {
  1059. eventType: v1.EventTypeNormal,
  1060. event: "NodeHasInsufficientMemory",
  1061. },
  1062. },
  1063. },
  1064. {
  1065. desc: "transition to no pressure",
  1066. node: &v1.Node{
  1067. Status: v1.NodeStatus{
  1068. Conditions: []v1.NodeCondition{*makeMemoryPressureCondition(true, before, before)},
  1069. },
  1070. },
  1071. pressure: false,
  1072. expectConditions: []v1.NodeCondition{*makeMemoryPressureCondition(false, now, now)},
  1073. expectEvents: []testEvent{
  1074. {
  1075. eventType: v1.EventTypeNormal,
  1076. event: "NodeHasSufficientMemory",
  1077. },
  1078. },
  1079. },
  1080. {
  1081. desc: "pressure, no transition",
  1082. node: &v1.Node{
  1083. Status: v1.NodeStatus{
  1084. Conditions: []v1.NodeCondition{*makeMemoryPressureCondition(true, before, before)},
  1085. },
  1086. },
  1087. pressure: true,
  1088. expectConditions: []v1.NodeCondition{*makeMemoryPressureCondition(true, before, now)},
  1089. expectEvents: []testEvent{},
  1090. },
  1091. {
  1092. desc: "no pressure, no transition",
  1093. node: &v1.Node{
  1094. Status: v1.NodeStatus{
  1095. Conditions: []v1.NodeCondition{*makeMemoryPressureCondition(false, before, before)},
  1096. },
  1097. },
  1098. pressure: false,
  1099. expectConditions: []v1.NodeCondition{*makeMemoryPressureCondition(false, before, now)},
  1100. expectEvents: []testEvent{},
  1101. },
  1102. }
  1103. for _, tc := range cases {
  1104. t.Run(tc.desc, func(t *testing.T) {
  1105. events := []testEvent{}
  1106. recordEventFunc := func(eventType, event string) {
  1107. events = append(events, testEvent{
  1108. eventType: eventType,
  1109. event: event,
  1110. })
  1111. }
  1112. pressureFunc := func() bool {
  1113. return tc.pressure
  1114. }
  1115. // construct setter
  1116. setter := MemoryPressureCondition(nowFunc, pressureFunc, recordEventFunc)
  1117. // call setter on node
  1118. if err := setter(tc.node); err != nil {
  1119. t.Fatalf("unexpected error: %v", err)
  1120. }
  1121. // check expected condition
  1122. assert.True(t, apiequality.Semantic.DeepEqual(tc.expectConditions, tc.node.Status.Conditions),
  1123. "Diff: %s", diff.ObjectDiff(tc.expectConditions, tc.node.Status.Conditions))
  1124. // check expected events
  1125. require.Equal(t, len(tc.expectEvents), len(events))
  1126. for i := range tc.expectEvents {
  1127. assert.Equal(t, tc.expectEvents[i], events[i])
  1128. }
  1129. })
  1130. }
  1131. }
  1132. func TestPIDPressureCondition(t *testing.T) {
  1133. now := time.Now()
  1134. before := now.Add(-time.Second)
  1135. nowFunc := func() time.Time { return now }
  1136. cases := []struct {
  1137. desc string
  1138. node *v1.Node
  1139. pressure bool
  1140. expectConditions []v1.NodeCondition
  1141. expectEvents []testEvent
  1142. }{
  1143. {
  1144. desc: "new, no pressure",
  1145. node: &v1.Node{},
  1146. pressure: false,
  1147. expectConditions: []v1.NodeCondition{*makePIDPressureCondition(false, now, now)},
  1148. expectEvents: []testEvent{
  1149. {
  1150. eventType: v1.EventTypeNormal,
  1151. event: "NodeHasSufficientPID",
  1152. },
  1153. },
  1154. },
  1155. {
  1156. desc: "new, pressure",
  1157. node: &v1.Node{},
  1158. pressure: true,
  1159. expectConditions: []v1.NodeCondition{*makePIDPressureCondition(true, now, now)},
  1160. expectEvents: []testEvent{
  1161. {
  1162. eventType: v1.EventTypeNormal,
  1163. event: "NodeHasInsufficientPID",
  1164. },
  1165. },
  1166. },
  1167. {
  1168. desc: "transition to pressure",
  1169. node: &v1.Node{
  1170. Status: v1.NodeStatus{
  1171. Conditions: []v1.NodeCondition{*makePIDPressureCondition(false, before, before)},
  1172. },
  1173. },
  1174. pressure: true,
  1175. expectConditions: []v1.NodeCondition{*makePIDPressureCondition(true, now, now)},
  1176. expectEvents: []testEvent{
  1177. {
  1178. eventType: v1.EventTypeNormal,
  1179. event: "NodeHasInsufficientPID",
  1180. },
  1181. },
  1182. },
  1183. {
  1184. desc: "transition to no pressure",
  1185. node: &v1.Node{
  1186. Status: v1.NodeStatus{
  1187. Conditions: []v1.NodeCondition{*makePIDPressureCondition(true, before, before)},
  1188. },
  1189. },
  1190. pressure: false,
  1191. expectConditions: []v1.NodeCondition{*makePIDPressureCondition(false, now, now)},
  1192. expectEvents: []testEvent{
  1193. {
  1194. eventType: v1.EventTypeNormal,
  1195. event: "NodeHasSufficientPID",
  1196. },
  1197. },
  1198. },
  1199. {
  1200. desc: "pressure, no transition",
  1201. node: &v1.Node{
  1202. Status: v1.NodeStatus{
  1203. Conditions: []v1.NodeCondition{*makePIDPressureCondition(true, before, before)},
  1204. },
  1205. },
  1206. pressure: true,
  1207. expectConditions: []v1.NodeCondition{*makePIDPressureCondition(true, before, now)},
  1208. expectEvents: []testEvent{},
  1209. },
  1210. {
  1211. desc: "no pressure, no transition",
  1212. node: &v1.Node{
  1213. Status: v1.NodeStatus{
  1214. Conditions: []v1.NodeCondition{*makePIDPressureCondition(false, before, before)},
  1215. },
  1216. },
  1217. pressure: false,
  1218. expectConditions: []v1.NodeCondition{*makePIDPressureCondition(false, before, now)},
  1219. expectEvents: []testEvent{},
  1220. },
  1221. }
  1222. for _, tc := range cases {
  1223. t.Run(tc.desc, func(t *testing.T) {
  1224. events := []testEvent{}
  1225. recordEventFunc := func(eventType, event string) {
  1226. events = append(events, testEvent{
  1227. eventType: eventType,
  1228. event: event,
  1229. })
  1230. }
  1231. pressureFunc := func() bool {
  1232. return tc.pressure
  1233. }
  1234. // construct setter
  1235. setter := PIDPressureCondition(nowFunc, pressureFunc, recordEventFunc)
  1236. // call setter on node
  1237. if err := setter(tc.node); err != nil {
  1238. t.Fatalf("unexpected error: %v", err)
  1239. }
  1240. // check expected condition
  1241. assert.True(t, apiequality.Semantic.DeepEqual(tc.expectConditions, tc.node.Status.Conditions),
  1242. "Diff: %s", diff.ObjectDiff(tc.expectConditions, tc.node.Status.Conditions))
  1243. // check expected events
  1244. require.Equal(t, len(tc.expectEvents), len(events))
  1245. for i := range tc.expectEvents {
  1246. assert.Equal(t, tc.expectEvents[i], events[i])
  1247. }
  1248. })
  1249. }
  1250. }
  1251. func TestDiskPressureCondition(t *testing.T) {
  1252. now := time.Now()
  1253. before := now.Add(-time.Second)
  1254. nowFunc := func() time.Time { return now }
  1255. cases := []struct {
  1256. desc string
  1257. node *v1.Node
  1258. pressure bool
  1259. expectConditions []v1.NodeCondition
  1260. expectEvents []testEvent
  1261. }{
  1262. {
  1263. desc: "new, no pressure",
  1264. node: &v1.Node{},
  1265. pressure: false,
  1266. expectConditions: []v1.NodeCondition{*makeDiskPressureCondition(false, now, now)},
  1267. expectEvents: []testEvent{
  1268. {
  1269. eventType: v1.EventTypeNormal,
  1270. event: "NodeHasNoDiskPressure",
  1271. },
  1272. },
  1273. },
  1274. {
  1275. desc: "new, pressure",
  1276. node: &v1.Node{},
  1277. pressure: true,
  1278. expectConditions: []v1.NodeCondition{*makeDiskPressureCondition(true, now, now)},
  1279. expectEvents: []testEvent{
  1280. {
  1281. eventType: v1.EventTypeNormal,
  1282. event: "NodeHasDiskPressure",
  1283. },
  1284. },
  1285. },
  1286. {
  1287. desc: "transition to pressure",
  1288. node: &v1.Node{
  1289. Status: v1.NodeStatus{
  1290. Conditions: []v1.NodeCondition{*makeDiskPressureCondition(false, before, before)},
  1291. },
  1292. },
  1293. pressure: true,
  1294. expectConditions: []v1.NodeCondition{*makeDiskPressureCondition(true, now, now)},
  1295. expectEvents: []testEvent{
  1296. {
  1297. eventType: v1.EventTypeNormal,
  1298. event: "NodeHasDiskPressure",
  1299. },
  1300. },
  1301. },
  1302. {
  1303. desc: "transition to no pressure",
  1304. node: &v1.Node{
  1305. Status: v1.NodeStatus{
  1306. Conditions: []v1.NodeCondition{*makeDiskPressureCondition(true, before, before)},
  1307. },
  1308. },
  1309. pressure: false,
  1310. expectConditions: []v1.NodeCondition{*makeDiskPressureCondition(false, now, now)},
  1311. expectEvents: []testEvent{
  1312. {
  1313. eventType: v1.EventTypeNormal,
  1314. event: "NodeHasNoDiskPressure",
  1315. },
  1316. },
  1317. },
  1318. {
  1319. desc: "pressure, no transition",
  1320. node: &v1.Node{
  1321. Status: v1.NodeStatus{
  1322. Conditions: []v1.NodeCondition{*makeDiskPressureCondition(true, before, before)},
  1323. },
  1324. },
  1325. pressure: true,
  1326. expectConditions: []v1.NodeCondition{*makeDiskPressureCondition(true, before, now)},
  1327. expectEvents: []testEvent{},
  1328. },
  1329. {
  1330. desc: "no pressure, no transition",
  1331. node: &v1.Node{
  1332. Status: v1.NodeStatus{
  1333. Conditions: []v1.NodeCondition{*makeDiskPressureCondition(false, before, before)},
  1334. },
  1335. },
  1336. pressure: false,
  1337. expectConditions: []v1.NodeCondition{*makeDiskPressureCondition(false, before, now)},
  1338. expectEvents: []testEvent{},
  1339. },
  1340. }
  1341. for _, tc := range cases {
  1342. t.Run(tc.desc, func(t *testing.T) {
  1343. events := []testEvent{}
  1344. recordEventFunc := func(eventType, event string) {
  1345. events = append(events, testEvent{
  1346. eventType: eventType,
  1347. event: event,
  1348. })
  1349. }
  1350. pressureFunc := func() bool {
  1351. return tc.pressure
  1352. }
  1353. // construct setter
  1354. setter := DiskPressureCondition(nowFunc, pressureFunc, recordEventFunc)
  1355. // call setter on node
  1356. if err := setter(tc.node); err != nil {
  1357. t.Fatalf("unexpected error: %v", err)
  1358. }
  1359. // check expected condition
  1360. assert.True(t, apiequality.Semantic.DeepEqual(tc.expectConditions, tc.node.Status.Conditions),
  1361. "Diff: %s", diff.ObjectDiff(tc.expectConditions, tc.node.Status.Conditions))
  1362. // check expected events
  1363. require.Equal(t, len(tc.expectEvents), len(events))
  1364. for i := range tc.expectEvents {
  1365. assert.Equal(t, tc.expectEvents[i], events[i])
  1366. }
  1367. })
  1368. }
  1369. }
  1370. func TestVolumesInUse(t *testing.T) {
  1371. withVolumesInUse := &v1.Node{
  1372. Status: v1.NodeStatus{
  1373. VolumesInUse: []v1.UniqueVolumeName{"foo"},
  1374. },
  1375. }
  1376. cases := []struct {
  1377. desc string
  1378. node *v1.Node
  1379. synced bool
  1380. volumesInUse []v1.UniqueVolumeName
  1381. expectVolumesInUse []v1.UniqueVolumeName
  1382. }{
  1383. {
  1384. desc: "synced",
  1385. node: withVolumesInUse.DeepCopy(),
  1386. synced: true,
  1387. volumesInUse: []v1.UniqueVolumeName{"bar"},
  1388. expectVolumesInUse: []v1.UniqueVolumeName{"bar"},
  1389. },
  1390. {
  1391. desc: "not synced",
  1392. node: withVolumesInUse.DeepCopy(),
  1393. synced: false,
  1394. volumesInUse: []v1.UniqueVolumeName{"bar"},
  1395. expectVolumesInUse: []v1.UniqueVolumeName{"foo"},
  1396. },
  1397. }
  1398. for _, tc := range cases {
  1399. t.Run(tc.desc, func(t *testing.T) {
  1400. syncedFunc := func() bool {
  1401. return tc.synced
  1402. }
  1403. volumesInUseFunc := func() []v1.UniqueVolumeName {
  1404. return tc.volumesInUse
  1405. }
  1406. // construct setter
  1407. setter := VolumesInUse(syncedFunc, volumesInUseFunc)
  1408. // call setter on node
  1409. if err := setter(tc.node); err != nil {
  1410. t.Fatalf("unexpected error: %v", err)
  1411. }
  1412. // check expected volumes
  1413. assert.True(t, apiequality.Semantic.DeepEqual(tc.expectVolumesInUse, tc.node.Status.VolumesInUse),
  1414. "Diff: %s", diff.ObjectDiff(tc.expectVolumesInUse, tc.node.Status.VolumesInUse))
  1415. })
  1416. }
  1417. }
  1418. func TestVolumeLimits(t *testing.T) {
  1419. const (
  1420. volumeLimitKey = "attachable-volumes-fake-provider"
  1421. volumeLimitVal = 16
  1422. )
  1423. var cases = []struct {
  1424. desc string
  1425. volumePluginList []volume.VolumePluginWithAttachLimits
  1426. expectNode *v1.Node
  1427. }{
  1428. {
  1429. desc: "translate limits to capacity and allocatable for plugins that return successfully from GetVolumeLimits",
  1430. volumePluginList: []volume.VolumePluginWithAttachLimits{
  1431. &volumetest.FakeVolumePlugin{
  1432. VolumeLimits: map[string]int64{volumeLimitKey: volumeLimitVal},
  1433. },
  1434. },
  1435. expectNode: &v1.Node{
  1436. Status: v1.NodeStatus{
  1437. Capacity: v1.ResourceList{
  1438. volumeLimitKey: *resource.NewQuantity(volumeLimitVal, resource.DecimalSI),
  1439. },
  1440. Allocatable: v1.ResourceList{
  1441. volumeLimitKey: *resource.NewQuantity(volumeLimitVal, resource.DecimalSI),
  1442. },
  1443. },
  1444. },
  1445. },
  1446. {
  1447. desc: "skip plugins that return errors from GetVolumeLimits",
  1448. volumePluginList: []volume.VolumePluginWithAttachLimits{
  1449. &volumetest.FakeVolumePlugin{
  1450. VolumeLimitsError: fmt.Errorf("foo"),
  1451. },
  1452. },
  1453. expectNode: &v1.Node{},
  1454. },
  1455. {
  1456. desc: "no plugins",
  1457. expectNode: &v1.Node{},
  1458. },
  1459. }
  1460. for _, tc := range cases {
  1461. t.Run(tc.desc, func(t *testing.T) {
  1462. volumePluginListFunc := func() []volume.VolumePluginWithAttachLimits {
  1463. return tc.volumePluginList
  1464. }
  1465. // construct setter
  1466. setter := VolumeLimits(volumePluginListFunc)
  1467. // call setter on node
  1468. node := &v1.Node{}
  1469. if err := setter(node); err != nil {
  1470. t.Fatalf("unexpected error: %v", err)
  1471. }
  1472. // check expected node
  1473. assert.True(t, apiequality.Semantic.DeepEqual(tc.expectNode, node),
  1474. "Diff: %s", diff.ObjectDiff(tc.expectNode, node))
  1475. })
  1476. }
  1477. }
  1478. func TestRemoveOutOfDiskCondition(t *testing.T) {
  1479. now := time.Now()
  1480. var cases = []struct {
  1481. desc string
  1482. inputNode *v1.Node
  1483. expectNode *v1.Node
  1484. }{
  1485. {
  1486. desc: "should remove stale OutOfDiskCondition from node status",
  1487. inputNode: &v1.Node{
  1488. Status: v1.NodeStatus{
  1489. Conditions: []v1.NodeCondition{
  1490. *makeMemoryPressureCondition(false, now, now),
  1491. {
  1492. Type: v1.NodeOutOfDisk,
  1493. Status: v1.ConditionFalse,
  1494. },
  1495. *makeDiskPressureCondition(false, now, now),
  1496. },
  1497. },
  1498. },
  1499. expectNode: &v1.Node{
  1500. Status: v1.NodeStatus{
  1501. Conditions: []v1.NodeCondition{
  1502. *makeMemoryPressureCondition(false, now, now),
  1503. *makeDiskPressureCondition(false, now, now),
  1504. },
  1505. },
  1506. },
  1507. },
  1508. }
  1509. for _, tc := range cases {
  1510. t.Run(tc.desc, func(t *testing.T) {
  1511. // construct setter
  1512. setter := RemoveOutOfDiskCondition()
  1513. // call setter on node
  1514. if err := setter(tc.inputNode); err != nil {
  1515. t.Fatalf("unexpected error: %v", err)
  1516. }
  1517. // check expected node
  1518. assert.True(t, apiequality.Semantic.DeepEqual(tc.expectNode, tc.inputNode),
  1519. "Diff: %s", diff.ObjectDiff(tc.expectNode, tc.inputNode))
  1520. })
  1521. }
  1522. }
  1523. // Test Helpers:
  1524. // sortableNodeAddress is a type for sorting []v1.NodeAddress
  1525. type sortableNodeAddress []v1.NodeAddress
  1526. func (s sortableNodeAddress) Len() int { return len(s) }
  1527. func (s sortableNodeAddress) Less(i, j int) bool {
  1528. return (string(s[i].Type) + s[i].Address) < (string(s[j].Type) + s[j].Address)
  1529. }
  1530. func (s sortableNodeAddress) Swap(i, j int) { s[j], s[i] = s[i], s[j] }
  1531. func sortNodeAddresses(addrs sortableNodeAddress) {
  1532. sort.Sort(addrs)
  1533. }
  1534. // testEvent is used to record events for tests
  1535. type testEvent struct {
  1536. eventType string
  1537. event string
  1538. message string
  1539. }
  1540. // makeImageList randomly generates a list of images with the given count
  1541. func makeImageList(numImages, numTags, minSize, maxSize int32) []kubecontainer.Image {
  1542. images := make([]kubecontainer.Image, numImages)
  1543. for i := range images {
  1544. image := &images[i]
  1545. image.ID = string(uuid.NewUUID())
  1546. image.RepoTags = makeImageTags(numTags)
  1547. image.Size = rand.Int63nRange(int64(minSize), int64(maxSize+1))
  1548. }
  1549. return images
  1550. }
  1551. func makeExpectedImageList(imageList []kubecontainer.Image, maxImages, maxNames int32) []v1.ContainerImage {
  1552. // copy the imageList, we do not want to mutate it in-place and accidentally edit a test case
  1553. images := make([]kubecontainer.Image, len(imageList))
  1554. copy(images, imageList)
  1555. // sort images by size
  1556. sort.Sort(sliceutils.ByImageSize(images))
  1557. // convert to []v1.ContainerImage and truncate the list of names
  1558. expectedImages := make([]v1.ContainerImage, len(images))
  1559. for i := range images {
  1560. image := &images[i]
  1561. expectedImage := &expectedImages[i]
  1562. names := append(image.RepoDigests, image.RepoTags...)
  1563. if len(names) > int(maxNames) {
  1564. names = names[0:maxNames]
  1565. }
  1566. expectedImage.Names = names
  1567. expectedImage.SizeBytes = image.Size
  1568. }
  1569. // -1 means no limit, truncate result list if necessary.
  1570. if maxImages > -1 &&
  1571. int(maxImages) < len(expectedImages) {
  1572. return expectedImages[0:maxImages]
  1573. }
  1574. return expectedImages
  1575. }
  1576. func makeImageTags(num int32) []string {
  1577. tags := make([]string, num)
  1578. for i := range tags {
  1579. tags[i] = "k8s.gcr.io:v" + strconv.Itoa(i)
  1580. }
  1581. return tags
  1582. }
  1583. func makeReadyCondition(ready bool, message string, transition, heartbeat time.Time) *v1.NodeCondition {
  1584. if ready {
  1585. return &v1.NodeCondition{
  1586. Type: v1.NodeReady,
  1587. Status: v1.ConditionTrue,
  1588. Reason: "KubeletReady",
  1589. Message: message,
  1590. LastTransitionTime: metav1.NewTime(transition),
  1591. LastHeartbeatTime: metav1.NewTime(heartbeat),
  1592. }
  1593. }
  1594. return &v1.NodeCondition{
  1595. Type: v1.NodeReady,
  1596. Status: v1.ConditionFalse,
  1597. Reason: "KubeletNotReady",
  1598. Message: message,
  1599. LastTransitionTime: metav1.NewTime(transition),
  1600. LastHeartbeatTime: metav1.NewTime(heartbeat),
  1601. }
  1602. }
  1603. func makeMemoryPressureCondition(pressure bool, transition, heartbeat time.Time) *v1.NodeCondition {
  1604. if pressure {
  1605. return &v1.NodeCondition{
  1606. Type: v1.NodeMemoryPressure,
  1607. Status: v1.ConditionTrue,
  1608. Reason: "KubeletHasInsufficientMemory",
  1609. Message: "kubelet has insufficient memory available",
  1610. LastTransitionTime: metav1.NewTime(transition),
  1611. LastHeartbeatTime: metav1.NewTime(heartbeat),
  1612. }
  1613. }
  1614. return &v1.NodeCondition{
  1615. Type: v1.NodeMemoryPressure,
  1616. Status: v1.ConditionFalse,
  1617. Reason: "KubeletHasSufficientMemory",
  1618. Message: "kubelet has sufficient memory available",
  1619. LastTransitionTime: metav1.NewTime(transition),
  1620. LastHeartbeatTime: metav1.NewTime(heartbeat),
  1621. }
  1622. }
  1623. func makePIDPressureCondition(pressure bool, transition, heartbeat time.Time) *v1.NodeCondition {
  1624. if pressure {
  1625. return &v1.NodeCondition{
  1626. Type: v1.NodePIDPressure,
  1627. Status: v1.ConditionTrue,
  1628. Reason: "KubeletHasInsufficientPID",
  1629. Message: "kubelet has insufficient PID available",
  1630. LastTransitionTime: metav1.NewTime(transition),
  1631. LastHeartbeatTime: metav1.NewTime(heartbeat),
  1632. }
  1633. }
  1634. return &v1.NodeCondition{
  1635. Type: v1.NodePIDPressure,
  1636. Status: v1.ConditionFalse,
  1637. Reason: "KubeletHasSufficientPID",
  1638. Message: "kubelet has sufficient PID available",
  1639. LastTransitionTime: metav1.NewTime(transition),
  1640. LastHeartbeatTime: metav1.NewTime(heartbeat),
  1641. }
  1642. }
  1643. func makeDiskPressureCondition(pressure bool, transition, heartbeat time.Time) *v1.NodeCondition {
  1644. if pressure {
  1645. return &v1.NodeCondition{
  1646. Type: v1.NodeDiskPressure,
  1647. Status: v1.ConditionTrue,
  1648. Reason: "KubeletHasDiskPressure",
  1649. Message: "kubelet has disk pressure",
  1650. LastTransitionTime: metav1.NewTime(transition),
  1651. LastHeartbeatTime: metav1.NewTime(heartbeat),
  1652. }
  1653. }
  1654. return &v1.NodeCondition{
  1655. Type: v1.NodeDiskPressure,
  1656. Status: v1.ConditionFalse,
  1657. Reason: "KubeletHasNoDiskPressure",
  1658. Message: "kubelet has no disk pressure",
  1659. LastTransitionTime: metav1.NewTime(transition),
  1660. LastHeartbeatTime: metav1.NewTime(heartbeat),
  1661. }
  1662. }