mirror of
https://github.com/kubernetes/kubernetes.git
synced 2026-06-09 08:55:55 -04:00
kubectl describe: migrate to component-helpers resource package and add pod-level resources test (#137394)
* kubectl describe: migrate to component-helpers resource package and add pod-level resources test Refactor describe.go to use k8s.io/component-helpers/resource package for pod resource calculations. This migration enables proper support for pod-level resources feature. Changes: - Import resourcehelper from k8s.io/component-helpers/resource - Replace PodRequestsAndLimits() with separate PodRequests() and PodLimits() calls Add TestDescribeNodeWithPodLevelResources to verify describeNodeResource works correctly when pods have pod-level resources (Spec.Resources) configured. Signed-off-by: KunWuLuan <kunwuluan@gmail.com> * address review feedback: verify computed values in test and deprecate PodRequestsAndLimits --------- Signed-off-by: KunWuLuan <kunwuluan@gmail.com> Co-authored-by: KunWuLuan <kunwuluan@gmail.com>
This commit is contained in:
parent
8873025e93
commit
63080a762b
3 changed files with 105 additions and 6 deletions
|
|
@ -72,6 +72,7 @@ import (
|
|||
"k8s.io/client-go/rest"
|
||||
"k8s.io/client-go/tools/reference"
|
||||
utilcsr "k8s.io/client-go/util/certificate/csr"
|
||||
resourcehelper "k8s.io/component-helpers/resource"
|
||||
"k8s.io/klog/v2"
|
||||
"k8s.io/kubectl/pkg/scheme"
|
||||
"k8s.io/kubectl/pkg/util/certificate"
|
||||
|
|
@ -80,7 +81,7 @@ import (
|
|||
"k8s.io/kubectl/pkg/util/fieldpath"
|
||||
"k8s.io/kubectl/pkg/util/qos"
|
||||
"k8s.io/kubectl/pkg/util/rbac"
|
||||
resourcehelper "k8s.io/kubectl/pkg/util/resource"
|
||||
kubectlresourcehelper "k8s.io/kubectl/pkg/util/resource"
|
||||
storageutil "k8s.io/kubectl/pkg/util/storage"
|
||||
)
|
||||
|
||||
|
|
@ -1997,7 +1998,7 @@ func describeContainerEnvVars(container corev1.Container, resolverFn EnvVarResol
|
|||
}
|
||||
w.Write(LEVEL_3, "%s:\t%s (%s:%s)\n", e.Name, valueFrom, e.ValueFrom.FieldRef.APIVersion, e.ValueFrom.FieldRef.FieldPath)
|
||||
case e.ValueFrom.ResourceFieldRef != nil:
|
||||
valueFrom, err := resourcehelper.ExtractContainerResourceValue(e.ValueFrom.ResourceFieldRef, &container)
|
||||
valueFrom, err := kubectlresourcehelper.ExtractContainerResourceValue(e.ValueFrom.ResourceFieldRef, &container)
|
||||
if err != nil {
|
||||
valueFrom = ""
|
||||
}
|
||||
|
|
@ -3993,7 +3994,8 @@ func describeNodeResource(nodeNonTerminatedPodsList *corev1.PodList, node *corev
|
|||
}
|
||||
|
||||
for _, pod := range nodeNonTerminatedPodsList.Items {
|
||||
req, limit := resourcehelper.PodRequestsAndLimits(&pod)
|
||||
req := resourcehelper.PodRequests(&pod, resourcehelper.PodResourcesOptions{SkipPodLevelResources: false})
|
||||
limit := resourcehelper.PodLimits(&pod, resourcehelper.PodResourcesOptions{SkipPodLevelResources: false})
|
||||
cpuReq, cpuLimit, memoryReq, memoryLimit := req[corev1.ResourceCPU], limit[corev1.ResourceCPU], req[corev1.ResourceMemory], limit[corev1.ResourceMemory]
|
||||
fractionCpuReq := float64(cpuReq.MilliValue()) / float64(allocatable.Cpu().MilliValue()) * 100
|
||||
fractionCpuLimit := float64(cpuLimit.MilliValue()) / float64(allocatable.Cpu().MilliValue()) * 100
|
||||
|
|
@ -4038,9 +4040,9 @@ func describeNodeResource(nodeNonTerminatedPodsList *corev1.PodList, node *corev
|
|||
extResources := make([]string, 0, len(allocatable))
|
||||
hugePageResources := make([]string, 0, len(allocatable))
|
||||
for resource := range allocatable {
|
||||
if resourcehelper.IsHugePageResourceName(resource) {
|
||||
if kubectlresourcehelper.IsHugePageResourceName(resource) {
|
||||
hugePageResources = append(hugePageResources, string(resource))
|
||||
} else if !resourcehelper.IsStandardContainerResourceName(string(resource)) && resource != corev1.ResourcePods {
|
||||
} else if !kubectlresourcehelper.IsStandardContainerResourceName(string(resource)) && resource != corev1.ResourcePods {
|
||||
extResources = append(extResources, string(resource))
|
||||
}
|
||||
}
|
||||
|
|
@ -4069,7 +4071,8 @@ func describeNodeResource(nodeNonTerminatedPodsList *corev1.PodList, node *corev
|
|||
func getPodsTotalRequestsAndLimits(podList *corev1.PodList) (reqs map[corev1.ResourceName]resource.Quantity, limits map[corev1.ResourceName]resource.Quantity) {
|
||||
reqs, limits = map[corev1.ResourceName]resource.Quantity{}, map[corev1.ResourceName]resource.Quantity{}
|
||||
for _, pod := range podList.Items {
|
||||
podReqs, podLimits := resourcehelper.PodRequestsAndLimits(&pod)
|
||||
podReqs := resourcehelper.PodRequests(&pod, resourcehelper.PodResourcesOptions{SkipPodLevelResources: false})
|
||||
podLimits := resourcehelper.PodLimits(&pod, resourcehelper.PodResourcesOptions{SkipPodLevelResources: false})
|
||||
for podReqName, podReqValue := range podReqs {
|
||||
if value, ok := reqs[podReqName]; !ok {
|
||||
reqs[podReqName] = podReqValue.DeepCopy()
|
||||
|
|
|
|||
|
|
@ -6597,6 +6597,98 @@ func TestDescribeNodeWithSidecar(t *testing.T) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestDescribeNodeWithPodLevelResources(t *testing.T) {
|
||||
holderIdentity := "holder"
|
||||
nodeCapacity := getResourceList("8", "24Gi")
|
||||
nodeAllocatable := getResourceList("4", "12Gi")
|
||||
|
||||
fake := fake.NewClientset(
|
||||
&corev1.Node{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "bar",
|
||||
UID: "uid",
|
||||
},
|
||||
Spec: corev1.NodeSpec{
|
||||
Unschedulable: false,
|
||||
},
|
||||
Status: corev1.NodeStatus{
|
||||
Capacity: nodeCapacity,
|
||||
Allocatable: nodeAllocatable,
|
||||
},
|
||||
},
|
||||
&coordinationv1.Lease{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "bar",
|
||||
Namespace: corev1.NamespaceNodeLease,
|
||||
},
|
||||
Spec: coordinationv1.LeaseSpec{
|
||||
HolderIdentity: &holderIdentity,
|
||||
AcquireTime: &metav1.MicroTime{Time: time.Now().Add(-time.Hour)},
|
||||
RenewTime: &metav1.MicroTime{Time: time.Now()},
|
||||
},
|
||||
},
|
||||
&corev1.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "pod-with-pod-level-resources",
|
||||
Namespace: "foo",
|
||||
},
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: "Pod",
|
||||
},
|
||||
Spec: corev1.PodSpec{
|
||||
// Pod-level resources
|
||||
Resources: &corev1.ResourceRequirements{
|
||||
Requests: getResourceList("2", "4Gi"),
|
||||
Limits: getResourceList("4", "8Gi"),
|
||||
},
|
||||
Containers: []corev1.Container{
|
||||
{
|
||||
Name: "container-1",
|
||||
Image: "image:latest",
|
||||
},
|
||||
{
|
||||
Name: "container-2",
|
||||
Image: "image:latest",
|
||||
},
|
||||
},
|
||||
},
|
||||
Status: corev1.PodStatus{
|
||||
Phase: corev1.PodRunning,
|
||||
},
|
||||
},
|
||||
)
|
||||
c := &describeClient{T: t, Namespace: "foo", Interface: fake}
|
||||
d := NodeDescriber{c}
|
||||
out, err := d.Describe("foo", "bar", DescriberSettings{ShowEvents: true})
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
|
||||
// Verify that describeNodeResource works correctly with pod-level resources
|
||||
// Pod-level resources: requests cpu=2, memory=4Gi; limits cpu=4, memory=8Gi
|
||||
// Node allocatable: cpu=4, memory=12Gi
|
||||
// Expected: cpu requests 2 (50%), cpu limits 4 (100%), memory requests 4Gi (33%), memory limits 8Gi (66%)
|
||||
expectedOut := []string{
|
||||
"pod-with-pod-level-resources",
|
||||
// Verify per-pod row shows correct computed values for pod-level resources
|
||||
"pod-with-pod-level-resources 2 (50%) 4 (100%) 4Gi (33%) 8Gi (66%)",
|
||||
// Verify the allocated resources totals correctly account for pod-level resources
|
||||
`Allocated resources:
|
||||
(Total limits may be over 100 percent, i.e., overcommitted.)
|
||||
Resource Requests Limits
|
||||
-------- -------- ------
|
||||
cpu 2 (50%) 4 (100%)
|
||||
memory 4Gi (33%) 8Gi (66%)
|
||||
ephemeral-storage 0 (0%) 0 (0%)`,
|
||||
}
|
||||
for _, expected := range expectedOut {
|
||||
if !strings.Contains(out, expected) {
|
||||
t.Errorf("expected to find %q in output: %q", expected, out)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestDescribeStatefulSet(t *testing.T) {
|
||||
var partition int32 = 2672
|
||||
var replicas int32 = 1
|
||||
|
|
|
|||
|
|
@ -32,6 +32,10 @@ import (
|
|||
// containers of the pod. If pod overhead is non-nil, the pod overhead is added to the
|
||||
// total container resource requests and to the total container limits which have a
|
||||
// non-zero quantity.
|
||||
//
|
||||
// Deprecated: Use k8s.io/component-helpers/resource.PodRequests and
|
||||
// k8s.io/component-helpers/resource.PodLimits instead, which also support
|
||||
// pod-level resources.
|
||||
func PodRequestsAndLimits(pod *corev1.Pod) (reqs, limits corev1.ResourceList) {
|
||||
return podRequests(pod), podLimits(pod)
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue