1
16
17 package nodestatus
18
19 import (
20 "context"
21 "fmt"
22 "math"
23 "net"
24 goruntime "runtime"
25 "strings"
26 "time"
27
28 cadvisorapiv1 "github.com/google/cadvisor/info/v1"
29
30 v1 "k8s.io/api/core/v1"
31 "k8s.io/apimachinery/pkg/api/resource"
32 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
33 "k8s.io/apimachinery/pkg/util/errors"
34 utilnet "k8s.io/apimachinery/pkg/util/net"
35 utilfeature "k8s.io/apiserver/pkg/util/feature"
36 cloudprovider "k8s.io/cloud-provider"
37 cloudproviderapi "k8s.io/cloud-provider/api"
38 cloudprovidernodeutil "k8s.io/cloud-provider/node/helpers"
39 "k8s.io/component-base/version"
40 v1helper "k8s.io/kubernetes/pkg/apis/core/v1/helper"
41 "k8s.io/kubernetes/pkg/features"
42 "k8s.io/kubernetes/pkg/kubelet/cadvisor"
43 "k8s.io/kubernetes/pkg/kubelet/cm"
44 kubecontainer "k8s.io/kubernetes/pkg/kubelet/container"
45 "k8s.io/kubernetes/pkg/kubelet/events"
46 "k8s.io/kubernetes/pkg/volume"
47 netutils "k8s.io/utils/net"
48
49 "k8s.io/klog/v2"
50 )
51
52 const (
53
54
55 MaxNamesPerImageInNodeStatus = 5
56 )
57
58
59
60 type Setter func(ctx context.Context, node *v1.Node) error
61
62
63 func NodeAddress(nodeIPs []net.IP,
64 validateNodeIPFunc func(net.IP) error,
65 hostname string,
66 hostnameOverridden bool,
67 externalCloudProvider bool,
68 cloud cloudprovider.Interface,
69 nodeAddressesFunc func() ([]v1.NodeAddress, error),
70 ) Setter {
71 var nodeIP, secondaryNodeIP net.IP
72 if len(nodeIPs) > 0 {
73 nodeIP = nodeIPs[0]
74 }
75 preferIPv4 := nodeIP == nil || nodeIP.To4() != nil
76 isPreferredIPFamily := func(ip net.IP) bool { return (ip.To4() != nil) == preferIPv4 }
77 nodeIPSpecified := nodeIP != nil && !nodeIP.IsUnspecified()
78
79 if len(nodeIPs) > 1 {
80 secondaryNodeIP = nodeIPs[1]
81 }
82 secondaryNodeIPSpecified := secondaryNodeIP != nil && !secondaryNodeIP.IsUnspecified()
83
84 return func(ctx context.Context, node *v1.Node) error {
85 if nodeIPSpecified {
86 if err := validateNodeIPFunc(nodeIP); err != nil {
87 return fmt.Errorf("failed to validate nodeIP: %v", err)
88 }
89 klog.V(4).InfoS("Using node IP", "IP", nodeIP.String())
90 }
91 if secondaryNodeIPSpecified {
92 if err := validateNodeIPFunc(secondaryNodeIP); err != nil {
93 return fmt.Errorf("failed to validate secondaryNodeIP: %v", err)
94 }
95 klog.V(4).InfoS("Using secondary node IP", "IP", secondaryNodeIP.String())
96 }
97
98 if (externalCloudProvider || cloud != nil) && nodeIPSpecified {
99
100
101
102
103
104
105
106
107
108
109
110
111 if node.ObjectMeta.Annotations == nil {
112 node.ObjectMeta.Annotations = make(map[string]string)
113 }
114 annotation := nodeIP.String()
115 if secondaryNodeIPSpecified {
116 annotation += "," + secondaryNodeIP.String()
117 }
118 node.ObjectMeta.Annotations[cloudproviderapi.AnnotationAlphaProvidedIPAddr] = annotation
119 } else if node.ObjectMeta.Annotations != nil {
120
121
122 delete(node.ObjectMeta.Annotations, cloudproviderapi.AnnotationAlphaProvidedIPAddr)
123 }
124
125 if externalCloudProvider {
126
127
128
129
130 if len(node.Status.Addresses) > 0 {
131 return nil
132 }
133
134
135
136
137
138 if !nodeIPSpecified {
139 return nil
140 }
141 }
142 if cloud != nil {
143 cloudNodeAddresses, err := nodeAddressesFunc()
144 if err != nil {
145 return err
146 }
147
148 nodeAddresses, err := cloudprovidernodeutil.GetNodeAddressesFromNodeIPLegacy(nodeIP, cloudNodeAddresses)
149 if err != nil {
150 return err
151 }
152
153 switch {
154 case len(cloudNodeAddresses) == 0:
155
156 nodeAddresses = append(nodeAddresses, v1.NodeAddress{Type: v1.NodeHostName, Address: hostname})
157
158 case !hasAddressType(cloudNodeAddresses, v1.NodeHostName) && hasAddressValue(cloudNodeAddresses, hostname):
159
160
161
162 nodeAddresses = append(nodeAddresses, v1.NodeAddress{Type: v1.NodeHostName, Address: hostname})
163
164 case hostnameOverridden:
165
166
167
168 var existingHostnameAddress *v1.NodeAddress
169 for i := range nodeAddresses {
170 if nodeAddresses[i].Type == v1.NodeHostName {
171 existingHostnameAddress = &nodeAddresses[i]
172 break
173 }
174 }
175
176 if existingHostnameAddress == nil {
177
178 klog.InfoS("Adding overridden hostname to cloudprovider-reported addresses", "hostname", hostname)
179 nodeAddresses = append(nodeAddresses, v1.NodeAddress{Type: v1.NodeHostName, Address: hostname})
180 } else if existingHostnameAddress.Address != hostname {
181
182 klog.InfoS("Replacing cloudprovider-reported hostname with overridden hostname", "cloudProviderHostname", existingHostnameAddress.Address, "overriddenHostname", hostname)
183 existingHostnameAddress.Address = hostname
184 }
185 }
186 node.Status.Addresses = nodeAddresses
187 } else if nodeIPSpecified && secondaryNodeIPSpecified {
188 node.Status.Addresses = []v1.NodeAddress{
189 {Type: v1.NodeInternalIP, Address: nodeIP.String()},
190 {Type: v1.NodeInternalIP, Address: secondaryNodeIP.String()},
191 {Type: v1.NodeHostName, Address: hostname},
192 }
193 } else {
194 var ipAddr net.IP
195 var err error
196
197
198
199
200
201
202
203
204 if nodeIPSpecified {
205 ipAddr = nodeIP
206 } else if addr := netutils.ParseIPSloppy(hostname); addr != nil {
207 ipAddr = addr
208 } else {
209 var addrs []net.IP
210 addrs, _ = net.LookupIP(node.Name)
211 for _, addr := range addrs {
212 if err = validateNodeIPFunc(addr); err == nil {
213 if isPreferredIPFamily(addr) {
214 ipAddr = addr
215 break
216 } else if ipAddr == nil {
217 ipAddr = addr
218 }
219 }
220 }
221
222 if ipAddr == nil {
223 ipAddr, err = utilnet.ResolveBindAddress(nodeIP)
224 }
225 }
226
227 if ipAddr == nil {
228
229 return fmt.Errorf("can't get ip address of node %s. error: %v", node.Name, err)
230 }
231 node.Status.Addresses = []v1.NodeAddress{
232 {Type: v1.NodeInternalIP, Address: ipAddr.String()},
233 {Type: v1.NodeHostName, Address: hostname},
234 }
235 }
236 return nil
237 }
238 }
239
240 func hasAddressType(addresses []v1.NodeAddress, addressType v1.NodeAddressType) bool {
241 for _, address := range addresses {
242 if address.Type == addressType {
243 return true
244 }
245 }
246 return false
247 }
248 func hasAddressValue(addresses []v1.NodeAddress, addressValue string) bool {
249 for _, address := range addresses {
250 if address.Address == addressValue {
251 return true
252 }
253 }
254 return false
255 }
256
257
258 func MachineInfo(nodeName string,
259 maxPods int,
260 podsPerCore int,
261 machineInfoFunc func() (*cadvisorapiv1.MachineInfo, error),
262 capacityFunc func(localStorageCapacityIsolation bool) v1.ResourceList,
263 devicePluginResourceCapacityFunc func() (v1.ResourceList, v1.ResourceList, []string),
264 nodeAllocatableReservationFunc func() v1.ResourceList,
265 recordEventFunc func(eventType, event, message string),
266 localStorageCapacityIsolation bool,
267 ) Setter {
268 return func(ctx context.Context, node *v1.Node) error {
269
270
271 if node.Status.Capacity == nil {
272 node.Status.Capacity = v1.ResourceList{}
273 }
274
275 var devicePluginAllocatable v1.ResourceList
276 var devicePluginCapacity v1.ResourceList
277 var removedDevicePlugins []string
278
279
280
281 info, err := machineInfoFunc()
282 if err != nil {
283
284
285 node.Status.Capacity[v1.ResourceCPU] = *resource.NewMilliQuantity(0, resource.DecimalSI)
286 node.Status.Capacity[v1.ResourceMemory] = resource.MustParse("0Gi")
287 node.Status.Capacity[v1.ResourcePods] = *resource.NewQuantity(int64(maxPods), resource.DecimalSI)
288 klog.ErrorS(err, "Error getting machine info")
289 } else {
290 node.Status.NodeInfo.MachineID = info.MachineID
291 node.Status.NodeInfo.SystemUUID = info.SystemUUID
292
293 for rName, rCap := range cadvisor.CapacityFromMachineInfo(info) {
294 node.Status.Capacity[rName] = rCap
295 }
296
297 if podsPerCore > 0 {
298 node.Status.Capacity[v1.ResourcePods] = *resource.NewQuantity(
299 int64(math.Min(float64(info.NumCores*podsPerCore), float64(maxPods))), resource.DecimalSI)
300 } else {
301 node.Status.Capacity[v1.ResourcePods] = *resource.NewQuantity(
302 int64(maxPods), resource.DecimalSI)
303 }
304
305 if node.Status.NodeInfo.BootID != "" &&
306 node.Status.NodeInfo.BootID != info.BootID {
307
308
309 recordEventFunc(v1.EventTypeWarning, events.NodeRebooted,
310 fmt.Sprintf("Node %s has been rebooted, boot id: %s", nodeName, info.BootID))
311 }
312 node.Status.NodeInfo.BootID = info.BootID
313
314
315
316 initialCapacity := capacityFunc(localStorageCapacityIsolation)
317 if initialCapacity != nil {
318 if v, exists := initialCapacity[v1.ResourceEphemeralStorage]; exists {
319 node.Status.Capacity[v1.ResourceEphemeralStorage] = v
320 }
321 }
322
323
324 devicePluginCapacity, devicePluginAllocatable, removedDevicePlugins = devicePluginResourceCapacityFunc()
325 for k, v := range devicePluginCapacity {
326 if old, ok := node.Status.Capacity[k]; !ok || old.Value() != v.Value() {
327 klog.V(2).InfoS("Updated capacity for device plugin", "plugin", k, "capacity", v.Value())
328 }
329 node.Status.Capacity[k] = v
330 }
331
332 for _, removedResource := range removedDevicePlugins {
333 klog.V(2).InfoS("Set capacity for removed resource to 0 on device removal", "device", removedResource)
334
335
336
337
338
339
340
341
342 node.Status.Capacity[v1.ResourceName(removedResource)] = *resource.NewQuantity(int64(0), resource.DecimalSI)
343 }
344 }
345
346
347 if node.Status.Allocatable == nil {
348 node.Status.Allocatable = make(v1.ResourceList)
349 }
350
351
352 for k := range node.Status.Allocatable {
353 _, found := node.Status.Capacity[k]
354 if !found && v1helper.IsExtendedResourceName(k) {
355 delete(node.Status.Allocatable, k)
356 }
357 }
358 allocatableReservation := nodeAllocatableReservationFunc()
359 for k, v := range node.Status.Capacity {
360 value := v.DeepCopy()
361 if res, exists := allocatableReservation[k]; exists {
362 value.Sub(res)
363 }
364 if value.Sign() < 0 {
365
366 value.Set(0)
367 }
368 node.Status.Allocatable[k] = value
369 }
370
371 for k, v := range devicePluginAllocatable {
372 if old, ok := node.Status.Allocatable[k]; !ok || old.Value() != v.Value() {
373 klog.V(2).InfoS("Updated allocatable", "device", k, "allocatable", v.Value())
374 }
375 node.Status.Allocatable[k] = v
376 }
377
378 for k, v := range node.Status.Capacity {
379 if v1helper.IsHugePageResourceName(k) {
380 allocatableMemory := node.Status.Allocatable[v1.ResourceMemory]
381 value := v.DeepCopy()
382 allocatableMemory.Sub(value)
383 if allocatableMemory.Sign() < 0 {
384
385 allocatableMemory.Set(0)
386 }
387 node.Status.Allocatable[v1.ResourceMemory] = allocatableMemory
388 }
389 }
390 return nil
391 }
392 }
393
394
395 func VersionInfo(versionInfoFunc func() (*cadvisorapiv1.VersionInfo, error),
396 runtimeTypeFunc func() string,
397 runtimeVersionFunc func(ctx context.Context) (kubecontainer.Version, error),
398 ) Setter {
399 return func(ctx context.Context, node *v1.Node) error {
400 verinfo, err := versionInfoFunc()
401 if err != nil {
402 return fmt.Errorf("error getting version info: %v", err)
403 }
404
405 node.Status.NodeInfo.KernelVersion = verinfo.KernelVersion
406 node.Status.NodeInfo.OSImage = verinfo.ContainerOsVersion
407
408 runtimeVersion := "Unknown"
409 if runtimeVer, err := runtimeVersionFunc(ctx); err == nil {
410 runtimeVersion = runtimeVer.String()
411 }
412 node.Status.NodeInfo.ContainerRuntimeVersion = fmt.Sprintf("%s://%s", runtimeTypeFunc(), runtimeVersion)
413
414 node.Status.NodeInfo.KubeletVersion = version.Get().String()
415
416 if utilfeature.DefaultFeatureGate.Enabled(features.DisableNodeKubeProxyVersion) {
417
418 node.Status.NodeInfo.KubeProxyVersion = ""
419 } else {
420 node.Status.NodeInfo.KubeProxyVersion = version.Get().String()
421 }
422
423 return nil
424 }
425 }
426
427
428 func DaemonEndpoints(daemonEndpoints *v1.NodeDaemonEndpoints) Setter {
429 return func(ctx context.Context, node *v1.Node) error {
430 node.Status.DaemonEndpoints = *daemonEndpoints
431 return nil
432 }
433 }
434
435
436
437
438 func Images(nodeStatusMaxImages int32,
439 imageListFunc func() ([]kubecontainer.Image, error),
440 ) Setter {
441 return func(ctx context.Context, node *v1.Node) error {
442
443 var imagesOnNode []v1.ContainerImage
444 containerImages, err := imageListFunc()
445 if err != nil {
446 node.Status.Images = imagesOnNode
447 return fmt.Errorf("error getting image list: %v", err)
448 }
449
450 if int(nodeStatusMaxImages) > -1 &&
451 int(nodeStatusMaxImages) < len(containerImages) {
452 containerImages = containerImages[0:nodeStatusMaxImages]
453 }
454
455 for _, image := range containerImages {
456
457 names := append([]string{}, image.RepoDigests...)
458 names = append(names, image.RepoTags...)
459
460 if len(names) > MaxNamesPerImageInNodeStatus {
461 names = names[0:MaxNamesPerImageInNodeStatus]
462 }
463 imagesOnNode = append(imagesOnNode, v1.ContainerImage{
464 Names: names,
465 SizeBytes: image.Size,
466 })
467 }
468
469 node.Status.Images = imagesOnNode
470 return nil
471 }
472 }
473
474
475 func GoRuntime() Setter {
476 return func(ctx context.Context, node *v1.Node) error {
477 node.Status.NodeInfo.OperatingSystem = goruntime.GOOS
478 node.Status.NodeInfo.Architecture = goruntime.GOARCH
479 return nil
480 }
481 }
482
483
484 func RuntimeHandlers(fn func() []kubecontainer.RuntimeHandler) Setter {
485 return func(ctx context.Context, node *v1.Node) error {
486 if !utilfeature.DefaultFeatureGate.Enabled(features.RecursiveReadOnlyMounts) {
487 return nil
488 }
489 handlers := fn()
490 node.Status.RuntimeHandlers = make([]v1.NodeRuntimeHandler, len(handlers))
491 for i, h := range handlers {
492 node.Status.RuntimeHandlers[i] = v1.NodeRuntimeHandler{
493 Name: h.Name,
494 Features: &v1.NodeRuntimeHandlerFeatures{
495 RecursiveReadOnlyMounts: &h.SupportsRecursiveReadOnlyMounts,
496 },
497 }
498 }
499 return nil
500 }
501 }
502
503
504 func ReadyCondition(
505 nowFunc func() time.Time,
506 runtimeErrorsFunc func() error,
507 networkErrorsFunc func() error,
508 storageErrorsFunc func() error,
509 cmStatusFunc func() cm.Status,
510 nodeShutdownManagerErrorsFunc func() error,
511 recordEventFunc func(eventType, event string),
512 localStorageCapacityIsolation bool,
513 ) Setter {
514 return func(ctx context.Context, node *v1.Node) error {
515
516
517
518 currentTime := metav1.NewTime(nowFunc())
519 newNodeReadyCondition := v1.NodeCondition{
520 Type: v1.NodeReady,
521 Status: v1.ConditionTrue,
522 Reason: "KubeletReady",
523 Message: "kubelet is posting ready status",
524 LastHeartbeatTime: currentTime,
525 }
526 errs := []error{runtimeErrorsFunc(), networkErrorsFunc(), storageErrorsFunc(), nodeShutdownManagerErrorsFunc()}
527 requiredCapacities := []v1.ResourceName{v1.ResourceCPU, v1.ResourceMemory, v1.ResourcePods}
528 if localStorageCapacityIsolation {
529 requiredCapacities = append(requiredCapacities, v1.ResourceEphemeralStorage)
530 }
531 missingCapacities := []string{}
532 for _, resource := range requiredCapacities {
533 if _, found := node.Status.Capacity[resource]; !found {
534 missingCapacities = append(missingCapacities, string(resource))
535 }
536 }
537 if len(missingCapacities) > 0 {
538 errs = append(errs, fmt.Errorf("missing node capacity for resources: %s", strings.Join(missingCapacities, ", ")))
539 }
540 if aggregatedErr := errors.NewAggregate(errs); aggregatedErr != nil {
541 newNodeReadyCondition = v1.NodeCondition{
542 Type: v1.NodeReady,
543 Status: v1.ConditionFalse,
544 Reason: "KubeletNotReady",
545 Message: aggregatedErr.Error(),
546 LastHeartbeatTime: currentTime,
547 }
548 }
549
550
551 status := cmStatusFunc()
552 if status.SoftRequirements != nil {
553 newNodeReadyCondition.Message = fmt.Sprintf("%s. WARNING: %s", newNodeReadyCondition.Message, status.SoftRequirements.Error())
554 }
555
556 readyConditionUpdated := false
557 needToRecordEvent := false
558 for i := range node.Status.Conditions {
559 if node.Status.Conditions[i].Type == v1.NodeReady {
560 if node.Status.Conditions[i].Status == newNodeReadyCondition.Status {
561 newNodeReadyCondition.LastTransitionTime = node.Status.Conditions[i].LastTransitionTime
562 } else {
563 newNodeReadyCondition.LastTransitionTime = currentTime
564 needToRecordEvent = true
565 }
566 node.Status.Conditions[i] = newNodeReadyCondition
567 readyConditionUpdated = true
568 break
569 }
570 }
571 if !readyConditionUpdated {
572 newNodeReadyCondition.LastTransitionTime = currentTime
573 node.Status.Conditions = append(node.Status.Conditions, newNodeReadyCondition)
574 }
575 if needToRecordEvent {
576 if newNodeReadyCondition.Status == v1.ConditionTrue {
577 recordEventFunc(v1.EventTypeNormal, events.NodeReady)
578 } else {
579 recordEventFunc(v1.EventTypeNormal, events.NodeNotReady)
580 klog.InfoS("Node became not ready", "node", klog.KObj(node), "condition", newNodeReadyCondition)
581 }
582 }
583 return nil
584 }
585 }
586
587
588 func MemoryPressureCondition(nowFunc func() time.Time,
589 pressureFunc func() bool,
590 recordEventFunc func(eventType, event string),
591 ) Setter {
592 return func(ctx context.Context, node *v1.Node) error {
593 currentTime := metav1.NewTime(nowFunc())
594 var condition *v1.NodeCondition
595
596
597 for i := range node.Status.Conditions {
598 if node.Status.Conditions[i].Type == v1.NodeMemoryPressure {
599 condition = &node.Status.Conditions[i]
600 }
601 }
602
603 newCondition := false
604
605 if condition == nil {
606 condition = &v1.NodeCondition{
607 Type: v1.NodeMemoryPressure,
608 Status: v1.ConditionUnknown,
609 }
610
611
612
613 newCondition = true
614 }
615
616
617 condition.LastHeartbeatTime = currentTime
618
619
620
621
622
623
624
625 if pressureFunc() {
626 if condition.Status != v1.ConditionTrue {
627 condition.Status = v1.ConditionTrue
628 condition.Reason = "KubeletHasInsufficientMemory"
629 condition.Message = "kubelet has insufficient memory available"
630 condition.LastTransitionTime = currentTime
631 recordEventFunc(v1.EventTypeNormal, "NodeHasInsufficientMemory")
632 }
633 } else if condition.Status != v1.ConditionFalse {
634 condition.Status = v1.ConditionFalse
635 condition.Reason = "KubeletHasSufficientMemory"
636 condition.Message = "kubelet has sufficient memory available"
637 condition.LastTransitionTime = currentTime
638 recordEventFunc(v1.EventTypeNormal, "NodeHasSufficientMemory")
639 }
640
641 if newCondition {
642 node.Status.Conditions = append(node.Status.Conditions, *condition)
643 }
644 return nil
645 }
646 }
647
648
649 func PIDPressureCondition(nowFunc func() time.Time,
650 pressureFunc func() bool,
651 recordEventFunc func(eventType, event string),
652 ) Setter {
653 return func(ctx context.Context, node *v1.Node) error {
654 currentTime := metav1.NewTime(nowFunc())
655 var condition *v1.NodeCondition
656
657
658 for i := range node.Status.Conditions {
659 if node.Status.Conditions[i].Type == v1.NodePIDPressure {
660 condition = &node.Status.Conditions[i]
661 }
662 }
663
664 newCondition := false
665
666 if condition == nil {
667 condition = &v1.NodeCondition{
668 Type: v1.NodePIDPressure,
669 Status: v1.ConditionUnknown,
670 }
671
672
673
674 newCondition = true
675 }
676
677
678 condition.LastHeartbeatTime = currentTime
679
680
681
682
683
684
685
686 if pressureFunc() {
687 if condition.Status != v1.ConditionTrue {
688 condition.Status = v1.ConditionTrue
689 condition.Reason = "KubeletHasInsufficientPID"
690 condition.Message = "kubelet has insufficient PID available"
691 condition.LastTransitionTime = currentTime
692 recordEventFunc(v1.EventTypeNormal, "NodeHasInsufficientPID")
693 }
694 } else if condition.Status != v1.ConditionFalse {
695 condition.Status = v1.ConditionFalse
696 condition.Reason = "KubeletHasSufficientPID"
697 condition.Message = "kubelet has sufficient PID available"
698 condition.LastTransitionTime = currentTime
699 recordEventFunc(v1.EventTypeNormal, "NodeHasSufficientPID")
700 }
701
702 if newCondition {
703 node.Status.Conditions = append(node.Status.Conditions, *condition)
704 }
705 return nil
706 }
707 }
708
709
710 func DiskPressureCondition(nowFunc func() time.Time,
711 pressureFunc func() bool,
712 recordEventFunc func(eventType, event string),
713 ) Setter {
714 return func(ctx context.Context, node *v1.Node) error {
715 currentTime := metav1.NewTime(nowFunc())
716 var condition *v1.NodeCondition
717
718
719 for i := range node.Status.Conditions {
720 if node.Status.Conditions[i].Type == v1.NodeDiskPressure {
721 condition = &node.Status.Conditions[i]
722 }
723 }
724
725 newCondition := false
726
727 if condition == nil {
728 condition = &v1.NodeCondition{
729 Type: v1.NodeDiskPressure,
730 Status: v1.ConditionUnknown,
731 }
732
733
734
735 newCondition = true
736 }
737
738
739 condition.LastHeartbeatTime = currentTime
740
741
742
743
744
745
746
747 if pressureFunc() {
748 if condition.Status != v1.ConditionTrue {
749 condition.Status = v1.ConditionTrue
750 condition.Reason = "KubeletHasDiskPressure"
751 condition.Message = "kubelet has disk pressure"
752 condition.LastTransitionTime = currentTime
753 recordEventFunc(v1.EventTypeNormal, "NodeHasDiskPressure")
754 }
755 } else if condition.Status != v1.ConditionFalse {
756 condition.Status = v1.ConditionFalse
757 condition.Reason = "KubeletHasNoDiskPressure"
758 condition.Message = "kubelet has no disk pressure"
759 condition.LastTransitionTime = currentTime
760 recordEventFunc(v1.EventTypeNormal, "NodeHasNoDiskPressure")
761 }
762
763 if newCondition {
764 node.Status.Conditions = append(node.Status.Conditions, *condition)
765 }
766 return nil
767 }
768 }
769
770
771 func VolumesInUse(syncedFunc func() bool,
772 volumesInUseFunc func() []v1.UniqueVolumeName,
773 ) Setter {
774 return func(ctx context.Context, node *v1.Node) error {
775
776 if syncedFunc() {
777 node.Status.VolumesInUse = volumesInUseFunc()
778 }
779 return nil
780 }
781 }
782
783
784 func VolumeLimits(volumePluginListFunc func() []volume.VolumePluginWithAttachLimits,
785 ) Setter {
786 return func(ctx context.Context, node *v1.Node) error {
787 if node.Status.Capacity == nil {
788 node.Status.Capacity = v1.ResourceList{}
789 }
790 if node.Status.Allocatable == nil {
791 node.Status.Allocatable = v1.ResourceList{}
792 }
793
794 pluginWithLimits := volumePluginListFunc()
795 for _, volumePlugin := range pluginWithLimits {
796 attachLimits, err := volumePlugin.GetVolumeLimits()
797 if err != nil {
798 klog.V(4).InfoS("Skipping volume limits for volume plugin", "plugin", volumePlugin.GetPluginName())
799 continue
800 }
801 for limitKey, value := range attachLimits {
802 node.Status.Capacity[v1.ResourceName(limitKey)] = *resource.NewQuantity(value, resource.DecimalSI)
803 node.Status.Allocatable[v1.ResourceName(limitKey)] = *resource.NewQuantity(value, resource.DecimalSI)
804 }
805 }
806 return nil
807 }
808 }
809
View as plain text