| /* | |
| Copyright 2018 The Kubernetes Authors. | |
| Licensed under the Apache License, Version 2.0 (the "License"); | |
| you may not use this file except in compliance with the License. | |
| You may obtain a copy of the License at | |
| http://www.apache.org/licenses/LICENSE-2.0 | |
| Unless required by applicable law or agreed to in writing, software | |
| distributed under the License is distributed on an "AS IS" BASIS, | |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| See the License for the specific language governing permissions and | |
| limitations under the License. | |
| */ | |
| package debugger | |
| import ( | |
| "fmt" | |
| "strings" | |
| "k8s.io/klog/v2" | |
| "k8s.io/api/core/v1" | |
| "k8s.io/kubernetes/pkg/scheduler/framework" | |
| internalcache "k8s.io/kubernetes/pkg/scheduler/internal/cache" | |
| "k8s.io/kubernetes/pkg/scheduler/internal/queue" | |
| ) | |
| // CacheDumper writes some information from the scheduler cache and the scheduling queue to the | |
| // scheduler logs for debugging purposes. | |
| type CacheDumper struct { | |
| cache internalcache.Cache | |
| podQueue queue.SchedulingQueue | |
| } | |
| // DumpAll writes cached nodes and scheduling queue information to the scheduler logs. | |
| func (d *CacheDumper) DumpAll(logger klog.Logger) { | |
| d.dumpNodes(logger) | |
| d.dumpSchedulingQueue(logger) | |
| } | |
| // dumpNodes writes NodeInfo to the scheduler logs. | |
| func (d *CacheDumper) dumpNodes(logger klog.Logger) { | |
| dump := d.cache.Dump() | |
| nodeInfos := make([]string, 0, len(dump.Nodes)) | |
| for name, nodeInfo := range dump.Nodes { | |
| nodeInfos = append(nodeInfos, d.printNodeInfo(name, nodeInfo)) | |
| } | |
| // Extra blank line added between node entries for readability. | |
| logger.Info("Dump of cached NodeInfo", "nodes", strings.Join(nodeInfos, "\n\n")) | |
| } | |
| // dumpSchedulingQueue writes pods in the scheduling queue to the scheduler logs. | |
| func (d *CacheDumper) dumpSchedulingQueue(logger klog.Logger) { | |
| pendingPods, s := d.podQueue.PendingPods() | |
| var podData strings.Builder | |
| for _, p := range pendingPods { | |
| podData.WriteString(printPod(p)) | |
| } | |
| logger.Info("Dump of scheduling queue", "summary", s, "pods", podData.String()) | |
| } | |
| // printNodeInfo writes parts of NodeInfo to a string. | |
| func (d *CacheDumper) printNodeInfo(name string, n *framework.NodeInfo) string { | |
| var nodeData strings.Builder | |
| nodeData.WriteString(fmt.Sprintf("Node name: %s\nDeleted: %t\nRequested Resources: %+v\nAllocatable Resources:%+v\nScheduled Pods(number: %v):\n", | |
| name, n.Node() == nil, n.Requested, n.Allocatable, len(n.Pods))) | |
| // Dumping Pod Info | |
| for _, p := range n.Pods { | |
| nodeData.WriteString(printPod(p.Pod)) | |
| } | |
| // Dumping nominated pods info on the node | |
| nominatedPodInfos := d.podQueue.NominatedPodsForNode(name) | |
| if len(nominatedPodInfos) != 0 { | |
| nodeData.WriteString(fmt.Sprintf("Nominated Pods(number: %v):\n", len(nominatedPodInfos))) | |
| for _, pi := range nominatedPodInfos { | |
| nodeData.WriteString(printPod(pi.Pod)) | |
| } | |
| } | |
| return nodeData.String() | |
| } | |
| // printPod writes parts of a Pod object to a string. | |
| func printPod(p *v1.Pod) string { | |
| return fmt.Sprintf("name: %v, namespace: %v, uid: %v, phase: %v, nominated node: %v\n", p.Name, p.Namespace, p.UID, p.Status.Phase, p.Status.NominatedNodeName) | |
| } |