Ctrl K
ComunidadGuías…

constructor/nodes.go

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
package constructor

import (
	"strconv"
	"strings"

	"github.com/coroot/coroot/db"
	"k8s.io/klog"

	"github.com/coroot/coroot/model"
	"github.com/coroot/coroot/timeseries"
)

func (c *Constructor) initNodesList(w *model.World, metrics map[string][]*model.MetricValues, nodes nodeCache, project *db.Project) {
	nodesBySystemUUID := map[string]*model.Node{}
	for _, m := range metrics["node_info"] {
		name := m.Labels["hostname"]
		id := model.NewNodeIdFromLabels(m)
		if id.MachineID == "" && id.SystemUUID == "" {
			klog.Infoln("invalid `node_info` metric: missing `machine_id` and `system_uuid` labels")
			continue
		}
		w.IntegrationStatus.NodeAgent.Installed = true
		node := nodes[id]
		if node == nil {
			node = model.NewNode(string(project.Id), id)
			w.Nodes = append(w.Nodes, node)
			nodes[node.Id] = node
			nodesBySystemUUID[node.Id.SystemUUID] = node
		}
		node.Name.Update(m.Values, name)
		node.KernelVersion.Update(m.Values, m.Labels["kernel_version"])
	}
	for _, m := range metrics["kube_node_info"] {
		name := m.Labels["node"]
		id := model.NewNodeIdFromLabels(m)
		if id.MachineID == "" && id.SystemUUID == "" {
			klog.Infoln("invalid `kube_node_info` metric: missing `system_uuid` label")
			continue
		}
		node := nodesBySystemUUID[id.SystemUUID]
		if node == nil {
			node = model.NewNode(string(project.Id), id)
			w.Nodes = append(w.Nodes, node)
			nodes[node.Id] = node
			nodesBySystemUUID[node.Id.SystemUUID] = node
		}
		node.K8sName.Update(m.Values, name)
		if node.KernelVersion.Value() == "" {
			node.KernelVersion.Update(m.Values, m.Labels["kernel_version"])
		}
	}
}

func (c *Constructor) loadNodes(w *model.World, metrics map[string][]*model.MetricValues, nodes nodeCache, project *db.Project) {
	c.initNodesList(w, metrics, nodes, project)

	for queryName := range metrics {
		if !strings.HasPrefix(queryName, "node_") {
			continue
		}
		for _, m := range metrics[queryName] {
			node := nodes[model.NewNodeIdFromLabels(m)]
			if node == nil {
				continue
			}
			switch queryName {
			case "node_agent_info":
				node.AgentVersion.Update(m.Values, m.Labels["version"])
			case "node_cpu_cores":
				node.CpuCapacity = merge(node.CpuCapacity, m.Values, timeseries.Any)
			case "node_cpu_usage_percent":
				node.CpuUsagePercent = merge(node.CpuUsagePercent, m.Values, timeseries.Any)
			case "node_cpu_usage_by_mode":
				node.CpuUsageByMode[m.Labels["mode"]] = merge(node.CpuUsageByMode[m.Labels["mode"]], m.Values, timeseries.Any)
			case "node_memory_total_bytes":
				node.MemoryTotalBytes = merge(node.MemoryTotalBytes, m.Values, timeseries.Any)
			case "node_memory_available_bytes":
				node.MemoryAvailableBytes = merge(node.MemoryAvailableBytes, m.Values, timeseries.Any)
			case "node_memory_cached_bytes":
				node.MemoryCachedBytes = merge(node.MemoryCachedBytes, m.Values, timeseries.Any)
			case "node_memory_free_bytes":
				node.MemoryFreeBytes = merge(node.MemoryFreeBytes, m.Values, timeseries.Any)
			case "node_cloud_info":
				provider := strings.ToLower(m.Labels["provider"])
				region := m.Labels["region"]
				az := m.Labels["availability_zone"]
				node.CloudProvider.Update(m.Values, provider)
				node.Region.Update(m.Values, region)
				if _, err := strconv.ParseInt(az, 10, 8); err == nil && provider == model.CloudProviderAzure {
					az = region + "-" + az
				}
				node.AvailabilityZone.Update(m.Values, az)
				node.InstanceType.Update(m.Values, m.Labels["instance_type"])
				node.InstanceLifeCycle.Update(m.Values, m.Labels["instance_life_cycle"])
			case "node_uptime_seconds":
				node.Uptime = merge(node.Uptime, m.Values, timeseries.Any)
			default:
				if strings.HasPrefix(queryName, "node_disk_") {
					nodeDisk(node, queryName, m)
				} else if strings.HasPrefix(queryName, "node_net_") {
					nodeInterface(node, queryName, m)
				} else if strings.HasPrefix(queryName, "node_gpu") {
					nodeGPU(node, queryName, m)
				}
			}
		}
	}
	for _, n := range w.Nodes {
		for _, d := range n.Disks {
			if d.Wait == nil && !d.ReadTime.IsEmpty() && !d.WriteTime.IsEmpty() {
				d.Wait = timeseries.NewAggregate(timeseries.NanSum).Add(d.ReadTime, d.WriteTime).Get()
			}
			switch {
			case d.Await == nil && !d.Wait.IsEmpty(): // node
				d.Await = timeseries.Div(d.Wait, timeseries.NewAggregate(timeseries.NanSum).Add(d.ReadOps, d.WriteOps).Get())
			case d.Wait == nil && !d.Await.IsEmpty(): // rds
				d.Wait = timeseries.Mul(d.Await, timeseries.NewAggregate(timeseries.NanSum).Add(d.ReadOps, d.WriteOps).Get())
			}
		}
	}
	if c.pricing != nil {
		for _, n := range w.Nodes {
			n.Price = c.pricing.GetNodePrice(project.Settings.CustomCloudPricing, n)
			n.DataTransferPrice = c.pricing.GetDataTransferPrice(n)
		}
	}
}

func nodeDisk(node *model.Node, queryName string, m *model.MetricValues) {
	device := m.Labels["device"]
	stat := node.Disks[device]
	if stat == nil {
		stat = &model.DiskStats{}
		node.Disks[device] = stat
	}
	switch queryName {
	case "node_disk_read_time":
		stat.ReadTime = merge(stat.ReadTime, m.Values, timeseries.Any)
	case "node_disk_write_time":
		stat.WriteTime = merge(stat.WriteTime, m.Values, timeseries.Any)
	case "node_disk_reads":
		stat.ReadOps = merge(stat.ReadOps, m.Values, timeseries.Any)
	case "node_disk_writes":
		stat.WriteOps = merge(stat.WriteOps, m.Values, timeseries.Any)
	case "node_disk_read_bytes":
		stat.ReadBytes = merge(stat.ReadBytes, m.Values, timeseries.Any)
	case "node_disk_written_bytes":
		stat.WrittenBytes = merge(stat.WrittenBytes, m.Values, timeseries.Any)
	case "node_disk_io_time":
		stat.IOUtilizationPercent = merge(stat.IOUtilizationPercent, m.Values.Map(func(t timeseries.Time, v float32) float32 {
			return v * 100
		}), timeseries.Any)
	}
}

func nodeInterface(node *model.Node, queryName string, m *model.MetricValues) {
	name := m.Labels["interface"]
	var stat *model.InterfaceStats
	for _, s := range node.NetInterfaces {
		if s.Name == name {
			stat = s
		}
	}
	if stat == nil {
		stat = &model.InterfaceStats{Name: name}
		node.NetInterfaces = append(node.NetInterfaces, stat)
	}
	switch queryName {
	case "node_net_up":
		stat.Up = merge(stat.Up, m.Values, timeseries.Any)
	case "node_net_ip":
		stat.Addresses = append(stat.Addresses, m.Labels["ip"])
	case "node_net_rx_bytes":
		stat.RxBytes = merge(stat.RxBytes, m.Values, timeseries.Any)
	case "node_net_tx_bytes":
		stat.TxBytes = merge(stat.TxBytes, m.Values, timeseries.Any)
	}
}

func nodeGPU(node *model.Node, queryName string, m *model.MetricValues) {
	uuid := m.Labels["gpu_uuid"]
	gpu := node.GPUs[uuid]
	if gpu == nil {
		gpu = &model.GPU{
			UUID:      uuid,
			Instances: map[string]*model.Instance{},
		}
		node.GPUs[uuid] = gpu
	}
	switch queryName {
	case "node_gpu_info":
		gpu.Name.Update(m.Values, m.Labels["name"])
		gpu.DriverVersion.Update(m.Values, m.Labels["driver_version"])
	case "node_gpu_memory_total_bytes":
		gpu.TotalMemory = merge(gpu.TotalMemory, m.Values, timeseries.Any)
	case "node_gpu_memory_used_bytes":
		gpu.UsedMemory = merge(gpu.UsedMemory, m.Values, timeseries.Any)
	case "node_gpu_memory_utilization_percent_avg":
		gpu.MemoryUsageAverage = merge(gpu.MemoryUsageAverage, m.Values, timeseries.Any)
	case "node_gpu_memory_utilization_percent_peak":
		gpu.MemoryUsagePeak = merge(gpu.MemoryUsagePeak, m.Values, timeseries.Any)
	case "node_gpu_temperature_celsius":
		gpu.Temperature = merge(gpu.Temperature, m.Values, timeseries.Any)
	case "node_gpu_power_usage_watts":
		gpu.PowerWatts = merge(gpu.PowerWatts, m.Values, timeseries.Any)
	case "node_gpu_utilization_percent_avg":
		gpu.UsageAverage = merge(gpu.UsageAverage, m.Values, timeseries.Any)
	case "node_gpu_utilization_percent_peak":
		gpu.UsagePeak = merge(gpu.UsagePeak, m.Values, timeseries.Any)
	}
}