mirror of
https://gitee.com/XM-GO/PandaX.git
synced 2026-04-23 10:58:35 +08:00
296 lines
9.6 KiB
Go
296 lines
9.6 KiB
Go
package node
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"pandax/apps/devops/services/k8s/event"
|
|
"pandax/base/global"
|
|
|
|
"pandax/apps/devops/entity/k8s"
|
|
k8scommon "pandax/apps/devops/services/k8s/common"
|
|
//"github.com/gin-gonic/gin"
|
|
v1 "k8s.io/api/core/v1"
|
|
"k8s.io/apimachinery/pkg/api/resource"
|
|
metaV1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
"k8s.io/apimachinery/pkg/fields"
|
|
"k8s.io/client-go/kubernetes"
|
|
)
|
|
|
|
// NodeAllocatedResources describes node allocated resources.
|
|
type NodeAllocatedResources struct {
|
|
// CPURequests is number of allocated milicores.
|
|
CPURequests int64 `json:"cpuRequests"`
|
|
|
|
// CPURequestsFraction is a fraction of CPU, that is allocated.
|
|
CPURequestsFraction float64 `json:"cpuRequestsFraction"`
|
|
|
|
// CPULimits is defined CPU limit.
|
|
CPULimits int64 `json:"cpuLimits"`
|
|
|
|
// CPULimitsFraction is a fraction of defined CPU limit, can be over 100%, i.e.
|
|
// overcommitted.
|
|
CPULimitsFraction float64 `json:"cpuLimitsFraction"`
|
|
|
|
// CPUCapacity is specified node CPU capacity in milicores.
|
|
CPUCapacity int64 `json:"cpuCapacity"`
|
|
|
|
// MemoryRequests is a fraction of memory, that is allocated.
|
|
MemoryRequests int64 `json:"memoryRequests"`
|
|
|
|
// MemoryRequestsFraction is a fraction of memory, that is allocated.
|
|
MemoryRequestsFraction float64 `json:"memoryRequestsFraction"`
|
|
|
|
// MemoryLimits is defined memory limit.
|
|
MemoryLimits int64 `json:"memoryLimits"`
|
|
|
|
// MemoryLimitsFraction is a fraction of defined memory limit, can be over 100%, i.e.
|
|
// overcommitted.
|
|
MemoryLimitsFraction float64 `json:"memoryLimitsFraction"`
|
|
|
|
// MemoryCapacity is specified node memory capacity in bytes.
|
|
MemoryCapacity int64 `json:"memoryCapacity"`
|
|
|
|
// AllocatedPods in number of currently allocated pods on the node.
|
|
AllocatedPods int `json:"allocatedPods"`
|
|
|
|
// PodCapacity is maximum number of pods, that can be allocated on the node.
|
|
PodCapacity int64 `json:"podCapacity"`
|
|
|
|
// PodFraction is a fraction of pods, that can be allocated on given node.
|
|
PodFraction float64 `json:"podFraction"`
|
|
}
|
|
|
|
// NodeDetail is a presentation layer view of Kubernetes Node resource. This means it is Node plus
|
|
// additional augmented data we can get from other sources.
|
|
type NodeDetail struct {
|
|
// Extends list item structure.
|
|
Node `json:",inline"`
|
|
|
|
// NodePhase is the current lifecycle phase of the node.
|
|
Phase v1.NodePhase `json:"phase"`
|
|
|
|
// PodCIDR represents the pod IP range assigned to the node.
|
|
PodCIDR string `json:"podCIDR"`
|
|
|
|
// ID of the node assigned by the cloud provider.
|
|
ProviderID string `json:"providerID"`
|
|
|
|
// Unschedulable controls node schedulability of new pods. By default node is schedulable.
|
|
Unschedulable bool `json:"unschedulable"`
|
|
|
|
// Set of ids/uuids to uniquely identify the node.
|
|
NodeInfo v1.NodeSystemInfo `json:"nodeInfo"`
|
|
|
|
//// Conditions is an array of current node conditions.
|
|
Conditions []k8scommon.Condition `json:"conditions"`
|
|
|
|
// Container images of the node.
|
|
ContainerImages []string `json:"containerImages"`
|
|
|
|
// PodListComponent contains information about pods belonging to this node.
|
|
PodList v1.PodList `json:"podList"`
|
|
|
|
// Events is list of events associated to the node.
|
|
EventList v1.EventList `json:"eventList"`
|
|
|
|
// Taints
|
|
Taints []v1.Taint `json:"taints,omitempty"`
|
|
|
|
// Addresses is a list of addresses reachable to the node. Queried from cloud provider, if available.
|
|
Addresses []v1.NodeAddress `json:"addresses,omitempty"`
|
|
|
|
Ready v1.ConditionStatus `json:"ready"`
|
|
NodeIP k8s.NodeIP `json:"nodeIP"`
|
|
UID k8s.UID `json:"uid"`
|
|
}
|
|
|
|
func GetNodeDetail(client *kubernetes.Clientset, name string) (*NodeDetail, error) {
|
|
/*
|
|
获取节点详细信息
|
|
*/
|
|
global.Log.Info(fmt.Sprintf("Getting details of %s node", name))
|
|
|
|
node, err := client.CoreV1().Nodes().Get(context.TODO(), name, metaV1.GetOptions{})
|
|
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
pods, err := getNodePods(client, *node)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
eventList, err := event.GetNodeEvents(client, node.Name)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
allocatedResources, err := getNodeAllocatedResources(*node, pods)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
nodeDetails := toNodeDetail(*node, pods, eventList, NodeAllocatedResources(allocatedResources))
|
|
return &nodeDetails, nil
|
|
}
|
|
|
|
func getNodePods(client *kubernetes.Clientset, node v1.Node) (*v1.PodList, error) {
|
|
fieldSelector, err := fields.ParseSelector("spec.nodeName=" + node.Name +
|
|
",status.phase!=" + string(v1.PodSucceeded) +
|
|
",status.phase!=" + string(v1.PodFailed))
|
|
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return client.CoreV1().Pods(v1.NamespaceAll).List(context.TODO(), metaV1.ListOptions{
|
|
FieldSelector: fieldSelector.String(),
|
|
})
|
|
}
|
|
|
|
func getNodeAllocatedResources(node v1.Node, podList *v1.PodList) (k8s.NodeAllocatedResources, error) {
|
|
reqs, limits := map[v1.ResourceName]resource.Quantity{}, map[v1.ResourceName]resource.Quantity{}
|
|
|
|
for _, pod := range podList.Items {
|
|
podReqs, podLimits, err := PodRequestsAndLimits(&pod)
|
|
if err != nil {
|
|
return k8s.NodeAllocatedResources{}, err
|
|
}
|
|
for podReqName, podReqValue := range podReqs {
|
|
if value, ok := reqs[podReqName]; !ok {
|
|
reqs[podReqName] = podReqValue.DeepCopy()
|
|
} else {
|
|
value.Add(podReqValue)
|
|
reqs[podReqName] = value
|
|
}
|
|
}
|
|
for podLimitName, podLimitValue := range podLimits {
|
|
if value, ok := limits[podLimitName]; !ok {
|
|
limits[podLimitName] = podLimitValue.DeepCopy()
|
|
} else {
|
|
value.Add(podLimitValue)
|
|
limits[podLimitName] = value
|
|
}
|
|
}
|
|
}
|
|
|
|
cpuRequests, cpuLimits, memoryRequests, memoryLimits := reqs[v1.ResourceCPU], limits[v1.ResourceCPU], reqs[v1.ResourceMemory], limits[v1.ResourceMemory]
|
|
|
|
var cpuRequestsFraction, cpuLimitsFraction float64 = 0, 0
|
|
if capacity := float64(node.Status.Allocatable.Cpu().MilliValue()); capacity > 0 {
|
|
cpuRequestsFraction = float64(cpuRequests.MilliValue()) / capacity * 100
|
|
cpuLimitsFraction = float64(cpuLimits.MilliValue()) / capacity * 100
|
|
}
|
|
|
|
var memoryRequestsFraction, memoryLimitsFraction float64 = 0, 0
|
|
if capacity := float64(node.Status.Allocatable.Memory().MilliValue()); capacity > 0 {
|
|
memoryRequestsFraction = float64(memoryRequests.MilliValue()) / capacity * 100
|
|
memoryLimitsFraction = float64(memoryLimits.MilliValue()) / capacity * 100
|
|
}
|
|
|
|
var podFraction float64 = 0
|
|
var podCapacity int64 = node.Status.Capacity.Pods().Value()
|
|
if podCapacity > 0 {
|
|
podFraction = float64(len(podList.Items)) / float64(podCapacity) * 100
|
|
}
|
|
|
|
return k8s.NodeAllocatedResources{
|
|
CPURequests: cpuRequests.MilliValue(),
|
|
CPURequestsFraction: cpuRequestsFraction,
|
|
CPULimits: cpuLimits.MilliValue(),
|
|
CPULimitsFraction: cpuLimitsFraction,
|
|
CPUCapacity: node.Status.Allocatable.Cpu().MilliValue(),
|
|
MemoryRequests: memoryRequests.Value(),
|
|
MemoryRequestsFraction: memoryRequestsFraction,
|
|
MemoryLimits: memoryLimits.Value(),
|
|
MemoryLimitsFraction: memoryLimitsFraction,
|
|
MemoryCapacity: node.Status.Allocatable.Memory().Value(),
|
|
AllocatedPods: len(podList.Items),
|
|
PodCapacity: podCapacity,
|
|
PodFraction: podFraction,
|
|
}, nil
|
|
}
|
|
|
|
// PodRequestsAndLimits returns a dictionary of all defined resources summed up for all
|
|
// 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.
|
|
func PodRequestsAndLimits(pod *v1.Pod) (reqs, limits v1.ResourceList, err error) {
|
|
reqs, limits = v1.ResourceList{}, v1.ResourceList{}
|
|
for _, container := range pod.Spec.Containers {
|
|
addResourceList(reqs, container.Resources.Requests)
|
|
addResourceList(limits, container.Resources.Limits)
|
|
}
|
|
// Init containers define the minimum of any resource
|
|
for _, container := range pod.Spec.InitContainers {
|
|
maxResourceList(reqs, container.Resources.Requests)
|
|
maxResourceList(limits, container.Resources.Limits)
|
|
}
|
|
|
|
// Add overhead for running a pod to the sum of requests and to non-zero limits:
|
|
if pod.Spec.Overhead != nil {
|
|
addResourceList(reqs, pod.Spec.Overhead)
|
|
|
|
for name, quantity := range pod.Spec.Overhead {
|
|
if value, ok := limits[name]; ok && !value.IsZero() {
|
|
value.Add(quantity)
|
|
limits[name] = value
|
|
}
|
|
}
|
|
}
|
|
return
|
|
}
|
|
|
|
// addResourceList adds the resources in newList to list
|
|
func addResourceList(list, new v1.ResourceList) {
|
|
for name, quantity := range new {
|
|
if value, ok := list[name]; !ok {
|
|
list[name] = quantity.DeepCopy()
|
|
} else {
|
|
value.Add(quantity)
|
|
list[name] = value
|
|
}
|
|
}
|
|
}
|
|
|
|
// maxResourceList sets list to the greater of list/newList for every resource
|
|
// either list
|
|
func maxResourceList(list, new v1.ResourceList) {
|
|
for name, quantity := range new {
|
|
if value, ok := list[name]; !ok {
|
|
list[name] = quantity.DeepCopy()
|
|
continue
|
|
} else {
|
|
if quantity.Cmp(value) > 0 {
|
|
list[name] = quantity.DeepCopy()
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func toNodeDetail(node v1.Node, pods *v1.PodList, eventList *v1.EventList, allocatedResources NodeAllocatedResources) NodeDetail {
|
|
return NodeDetail{
|
|
Node: Node{
|
|
ObjectMeta: k8s.NewObjectMeta(node.ObjectMeta),
|
|
TypeMeta: k8s.NewTypeMeta("node"),
|
|
AllocatedResources: k8s.NodeAllocatedResources(allocatedResources),
|
|
},
|
|
|
|
Phase: node.Status.Phase,
|
|
ProviderID: node.Spec.ProviderID,
|
|
PodCIDR: node.Spec.PodCIDR,
|
|
Unschedulable: node.Spec.Unschedulable,
|
|
NodeInfo: node.Status.NodeInfo,
|
|
Conditions: getNodeConditions(node),
|
|
ContainerImages: getContainerImages(node),
|
|
PodList: *pods,
|
|
EventList: *eventList,
|
|
Taints: node.Spec.Taints,
|
|
Addresses: node.Status.Addresses,
|
|
Ready: getNodeConditionStatus(node, v1.NodeReady),
|
|
NodeIP: k8s.NodeIP(getNodeIP(node)),
|
|
UID: k8s.UID(node.UID),
|
|
}
|
|
}
|