mirror of
https://gitee.com/XM-GO/PandaX.git
synced 2026-04-23 10:58:35 +08:00
【修改】k8s 配置
This commit is contained in:
272
apps/devops/services/k8s/node/node.go
Normal file
272
apps/devops/services/k8s/node/node.go
Normal file
@@ -0,0 +1,272 @@
|
||||
package node
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"pandax/base/global"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
"pandax/apps/devops/entity/k8s"
|
||||
"pandax/apps/devops/services/k8s/dataselect"
|
||||
"pandax/apps/devops/services/k8s/evict"
|
||||
"pandax/apps/devops/services/k8s/parser"
|
||||
"time"
|
||||
)
|
||||
|
||||
// NodeList 包含集群中的节点列表.
|
||||
type NodeList struct {
|
||||
ListMeta k8s.ListMeta `json:"listMeta"`
|
||||
Nodes []Node `json:"nodes"`
|
||||
}
|
||||
|
||||
// Node is a presentation layer view of Kubernetes nodes. This means it is node plus additional
|
||||
// augmented data we can get from other sources.
|
||||
type Node struct {
|
||||
ObjectMeta k8s.ObjectMeta `json:"objectMeta"`
|
||||
TypeMeta k8s.TypeMeta `json:"typeMeta"`
|
||||
Ready v1.ConditionStatus `json:"ready"`
|
||||
Unschedulable k8s.Unschedulable `json:"unschedulable"`
|
||||
NodeIP k8s.NodeIP `json:"nodeIP"`
|
||||
AllocatedResources k8s.NodeAllocatedResources `json:"allocatedResources"`
|
||||
NodeInfo v1.NodeSystemInfo `json:"nodeInfo"`
|
||||
//RuntimeType string `json:"runtimeType"`
|
||||
}
|
||||
|
||||
func GetNodeList(client *kubernetes.Clientset, dsQuery *gin.Context) (*NodeList, error) {
|
||||
/*
|
||||
获取所有Node节点信息
|
||||
*/
|
||||
|
||||
nodes, err := client.CoreV1().Nodes().List(context.TODO(), metav1.ListOptions{})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("get nodes from cluster failed: %v", err)
|
||||
}
|
||||
|
||||
return toNodeList(client, nodes.Items, dsQuery), nil
|
||||
}
|
||||
|
||||
func toNodeList(client *kubernetes.Clientset, nodes []v1.Node, dsQuery *gin.Context) *NodeList {
|
||||
|
||||
nodeList := &NodeList{
|
||||
Nodes: make([]Node, 0), // make初始化node信息
|
||||
ListMeta: k8s.ListMeta{TotalItems: len(nodes)}, // 计算node数量
|
||||
}
|
||||
// 解析前端传递的参数, filterBy=name,1.1&itemsPerPage=10&name=&namespace=default&page=1&sortBy=d,creationTimestamp
|
||||
// sortBy=d 倒序, sortBy=a 正序, 排序按照a-z
|
||||
dataSelect := parser.ParseDataSelectPathParameter(dsQuery)
|
||||
// 过滤
|
||||
nodeCells, filteredTotal := dataselect.GenericDataSelectWithFilter(toCells(nodes), dataSelect)
|
||||
nodes = fromCells(nodeCells)
|
||||
// 更新node数量, filteredTotal过滤后的数量
|
||||
nodeList.ListMeta = k8s.ListMeta{TotalItems: filteredTotal}
|
||||
|
||||
for _, node := range nodes {
|
||||
// 根据Node名称去获取节点上面的pod,过滤时排除pod为 Succeeded, Failed 返回pods
|
||||
pods, err := getNodePods(client, node)
|
||||
if err != nil {
|
||||
global.Log.Error(fmt.Sprintf("Couldn't get pods of %s node: %s\n", node.Name, err))
|
||||
}
|
||||
|
||||
// 调用toNode方法获取 node节点的计算资源
|
||||
nodeList.Nodes = append(nodeList.Nodes, toNode(node, pods, getNodeRole(node)))
|
||||
}
|
||||
|
||||
return nodeList
|
||||
}
|
||||
|
||||
func toNode(node v1.Node, pods *v1.PodList, role string) Node {
|
||||
// 获取cpu和内存的reqs, limits使用
|
||||
allocatedResources, err := getNodeAllocatedResources(node, pods)
|
||||
if err != nil {
|
||||
global.Log.Error(fmt.Sprintf("Couldn't get allocated resources of %s node: %s\n", node.Name, err))
|
||||
}
|
||||
|
||||
return Node{
|
||||
ObjectMeta: k8s.NewObjectMeta(node.ObjectMeta),
|
||||
TypeMeta: k8s.NewTypeMeta(k8s.ResourceKind(role)),
|
||||
Ready: getNodeConditionStatus(node, v1.NodeReady),
|
||||
NodeIP: k8s.NodeIP(getNodeIP(node)),
|
||||
Unschedulable: k8s.Unschedulable(node.Spec.Unschedulable),
|
||||
AllocatedResources: allocatedResources,
|
||||
NodeInfo: node.Status.NodeInfo,
|
||||
}
|
||||
}
|
||||
|
||||
func getNodeConditionStatus(node v1.Node, conditionType v1.NodeConditionType) v1.ConditionStatus {
|
||||
for _, condition := range node.Status.Conditions {
|
||||
if condition.Type == conditionType {
|
||||
return condition.Status
|
||||
}
|
||||
}
|
||||
return v1.ConditionUnknown
|
||||
}
|
||||
|
||||
func getNodeIP(node v1.Node) string {
|
||||
for _, addr := range node.Status.Addresses {
|
||||
if addr.Type == v1.NodeInternalIP {
|
||||
return addr.Address
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func getNodeRole(node v1.Node) string {
|
||||
var role string
|
||||
if _, ok := node.ObjectMeta.Labels["node-role.kubernetes.io/master"]; ok {
|
||||
role = "Master"
|
||||
} else {
|
||||
role = "Worker"
|
||||
}
|
||||
return role
|
||||
}
|
||||
|
||||
func GetNodeResource(client *kubernetes.Clientset) (namespaces int, deployments int, pods int) {
|
||||
/*
|
||||
获取集群 namespace数量 deployment数量 pod数量 container数量
|
||||
*/
|
||||
namespace, err := client.CoreV1().Namespaces().List(context.TODO(), metav1.ListOptions{})
|
||||
namespaces = len(namespace.Items)
|
||||
if err != nil {
|
||||
global.Log.Error("list namespace err")
|
||||
}
|
||||
for _, v := range namespace.Items {
|
||||
deployment, err := client.AppsV1().Deployments(v.Name).List(context.TODO(), metav1.ListOptions{})
|
||||
deployments += len(deployment.Items)
|
||||
if err != nil {
|
||||
global.Log.Error("get deployment err")
|
||||
}
|
||||
pod, err := client.CoreV1().Pods(v.Name).List(context.TODO(), metav1.ListOptions{})
|
||||
if err != nil {
|
||||
global.Log.Error("get pod err")
|
||||
}
|
||||
pods += len(pod.Items)
|
||||
}
|
||||
|
||||
return namespaces, deployments, pods
|
||||
}
|
||||
|
||||
func NodeUnschdulable(client *kubernetes.Clientset, nodeName string, unschdulable bool) (bool, error) {
|
||||
/*
|
||||
设置节点是否可调度
|
||||
*/
|
||||
global.Log.Info(fmt.Sprintf("设置Node节点:%v 不可调度: %v", nodeName, unschdulable))
|
||||
node, err := client.CoreV1().Nodes().Get(context.TODO(), nodeName, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
global.Log.Error(fmt.Sprintf("get node err: %v", err.Error()))
|
||||
return false, err
|
||||
}
|
||||
node.Spec.Unschedulable = unschdulable
|
||||
|
||||
_, err2 := client.CoreV1().Nodes().Update(context.TODO(), node, metav1.UpdateOptions{})
|
||||
|
||||
if err2 != nil {
|
||||
global.Log.Error(fmt.Sprintf("设置节点调度失败:%v", err2.Error()))
|
||||
return false, err2
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func CordonNode(client *kubernetes.Clientset, nodeName string) (bool, error) {
|
||||
/*
|
||||
排空节点
|
||||
选择排空节点(同时设置为不可调度),在后续进行应用部署时,则Pod不会再调度到该节点,并且该节点上由DaemonSet控制的Pod不会被排空。
|
||||
kubectl drain cn-beijing.i-2ze19qyi8votgjz12345 --grace-period=120 --ignore-daemonsets=true
|
||||
*/
|
||||
_, err := NodeUnschdulable(client, nodeName, true)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
err = evict.EvictsNodePods(client, nodeName)
|
||||
if err != nil {
|
||||
global.Log.Error(fmt.Sprintf("排空节点出现异常: %v", err.Error()))
|
||||
return false, err
|
||||
}
|
||||
return true, nil
|
||||
|
||||
}
|
||||
|
||||
func RemoveNode(client *kubernetes.Clientset, nodeName string) (bool, error) {
|
||||
startTime := time.Now()
|
||||
global.Log.Info(fmt.Sprintf("移除Node节点:%v, 异步任务已开始", nodeName))
|
||||
_, err := NodeUnschdulable(client, nodeName, true)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
err = evict.EvictsNodePods(client, nodeName)
|
||||
if err != nil {
|
||||
global.Log.Error(fmt.Sprintf("排空节点出现异常: %v", err.Error()))
|
||||
return false, err
|
||||
}
|
||||
err2 := client.CoreV1().Nodes().Delete(context.TODO(), nodeName, metav1.DeleteOptions{})
|
||||
if err2 != nil {
|
||||
return false, err2
|
||||
}
|
||||
global.Log.Info(fmt.Sprintf("已将节点:%v从集群中移除, 异步任务已完成,任务耗时:%v", nodeName, time.Since(startTime)))
|
||||
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func CollectionNodeUnschedule(client *kubernetes.Clientset, nodeName []string) error {
|
||||
/*
|
||||
批量设置Node节点不可调度
|
||||
{"node_name": ["k8s-master", "k8s-node"]}
|
||||
*/
|
||||
if len(nodeName) <= 0 {
|
||||
return errors.New("节点名称不能为空")
|
||||
}
|
||||
global.Log.Info(fmt.Sprintf("批量设置Node节点:%v 不可调度:true", nodeName))
|
||||
for _, v := range nodeName {
|
||||
node, err := client.CoreV1().Nodes().Get(context.TODO(), v, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
global.Log.Error(fmt.Sprintf("get node err: %v", err.Error()))
|
||||
return err
|
||||
}
|
||||
node.Spec.Unschedulable = true
|
||||
|
||||
_, err2 := client.CoreV1().Nodes().Update(context.TODO(), node, metav1.UpdateOptions{})
|
||||
|
||||
if err2 != nil {
|
||||
global.Log.Error(fmt.Sprintf("设置节点调度失败:%v", err2.Error()))
|
||||
return err
|
||||
}
|
||||
}
|
||||
global.Log.Info(fmt.Sprintf("已将所有Node节点:%v 设置为不可调度", nodeName))
|
||||
return nil
|
||||
}
|
||||
|
||||
func CollectionCordonNode(client *kubernetes.Clientset, nodeName []string) error {
|
||||
/*
|
||||
批量排空Node节点, 不允许调度
|
||||
{"node_name": ["k8s-master", "k8s-node"]}
|
||||
*/
|
||||
|
||||
if len(nodeName) <= 0 {
|
||||
return errors.New("节点名称不能为空")
|
||||
}
|
||||
global.Log.Info(fmt.Sprintf("开始排空节点, 设置Node节点:%v 不可调度:true", nodeName))
|
||||
for _, v := range nodeName {
|
||||
node, err := client.CoreV1().Nodes().Get(context.TODO(), v, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
global.Log.Error(fmt.Sprintf("get node err: %v", err.Error()))
|
||||
return err
|
||||
}
|
||||
node.Spec.Unschedulable = true
|
||||
|
||||
_, err2 := client.CoreV1().Nodes().Update(context.TODO(), node, metav1.UpdateOptions{})
|
||||
|
||||
if err2 != nil {
|
||||
global.Log.Error(fmt.Sprintf("设置节点调度失败:%v", err2.Error()))
|
||||
return err
|
||||
}
|
||||
_, cordonErr := CordonNode(client, v)
|
||||
if cordonErr != nil {
|
||||
return cordonErr
|
||||
}
|
||||
}
|
||||
global.Log.Info(fmt.Sprintf("已将所有Node节点:%v 设置为不可调度", nodeName))
|
||||
return nil
|
||||
}
|
||||
68
apps/devops/services/k8s/node/node_common.go
Normal file
68
apps/devops/services/k8s/node/node_common.go
Normal file
@@ -0,0 +1,68 @@
|
||||
package node
|
||||
|
||||
import (
|
||||
v1 "k8s.io/api/core/v1"
|
||||
metaV1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"pandax/apps/devops/services/k8s/common"
|
||||
"pandax/apps/devops/services/k8s/dataselect"
|
||||
)
|
||||
|
||||
type NodeCell v1.Node
|
||||
|
||||
func (self NodeCell) GetProperty(name dataselect.PropertyName) dataselect.ComparableValue {
|
||||
switch name {
|
||||
case dataselect.NameProperty:
|
||||
return dataselect.StdComparableString(self.ObjectMeta.Name)
|
||||
case dataselect.CreationTimestampProperty:
|
||||
return dataselect.StdComparableTime(self.ObjectMeta.CreationTimestamp.Time)
|
||||
case dataselect.NamespaceProperty:
|
||||
return dataselect.StdComparableString(self.ObjectMeta.Namespace)
|
||||
default:
|
||||
// if name is not supported then just return a constant dummy value, sort will have no effect.
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func toCells(std []v1.Node) []dataselect.DataCell {
|
||||
cells := make([]dataselect.DataCell, len(std))
|
||||
|
||||
for i := range std {
|
||||
cells[i] = NodeCell(std[i])
|
||||
|
||||
}
|
||||
return cells
|
||||
}
|
||||
|
||||
func fromCells(cells []dataselect.DataCell) []v1.Node {
|
||||
std := make([]v1.Node, len(cells))
|
||||
for i := range std {
|
||||
std[i] = v1.Node(cells[i].(NodeCell))
|
||||
}
|
||||
return std
|
||||
}
|
||||
|
||||
func getNodeConditions(node v1.Node) []common.Condition {
|
||||
var conditions []common.Condition
|
||||
for _, condition := range node.Status.Conditions {
|
||||
conditions = append(conditions, common.Condition{
|
||||
Type: string(condition.Type),
|
||||
Status: metaV1.ConditionStatus(condition.Status),
|
||||
LastProbeTime: condition.LastHeartbeatTime,
|
||||
LastTransitionTime: condition.LastTransitionTime,
|
||||
Reason: condition.Reason,
|
||||
Message: condition.Message,
|
||||
})
|
||||
}
|
||||
return conditions
|
||||
}
|
||||
|
||||
//getContainerImages returns container image strings from the given node.
|
||||
func getContainerImages(node v1.Node) []string {
|
||||
var containerImages []string
|
||||
for _, image := range node.Status.Images {
|
||||
for _, name := range image.Names {
|
||||
containerImages = append(containerImages, name)
|
||||
}
|
||||
}
|
||||
return containerImages
|
||||
}
|
||||
294
apps/devops/services/k8s/node/node_detail.go
Normal file
294
apps/devops/services/k8s/node/node_detail.go
Normal file
@@ -0,0 +1,294 @@
|
||||
package node
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"pandax/apps/devops/services/k8s/event"
|
||||
|
||||
"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),
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user