node.go 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. package kubemodel
  2. import (
  3. "fmt"
  4. "time"
  5. )
  6. // @bingen:generate:Node
  7. // Node represents a Kubernetes node with capacity-based resource tracking.
  8. // All resource measures (CPU, RAM) represent node capacity, not requests or limits.
  9. // This aligns with the principle that cost allocation should be based on provisioned capacity.
  10. type Node struct {
  11. UID string `json:"uid"`
  12. ProviderResourceUID string `json:"providerResourceUid"`
  13. Name string `json:"name"`
  14. Labels map[string]string `json:"labels,omitempty"`
  15. Annotations map[string]string `json:"annotations,omitempty"`
  16. DurationSeconds Measurement `json:"durationSeconds"`
  17. CpuMillicoreSeconds Measurement `json:"cpuMillicoreSeconds"` // Node CPU capacity in millicore-seconds
  18. RAMByteSeconds Measurement `json:"ramByteSeconds"` // Node RAM capacity in Byte-seconds
  19. AttachedVolumes map[string]*NodeVolumeUsage `json:"attachedVolumes,omitempty"`
  20. CpuMillicoreUsageMax Measurement `json:"cpuMillicoreUsageMax"` // Peak CPU usage observed
  21. RAMByteUsageMax Measurement `json:"ramByteUsageMax"` // Peak RAM usage observed
  22. Start time.Time `json:"start,omitempty"` // Node creation/start timestamp
  23. End time.Time `json:"end,omitempty"` // Node deletion/end timestamp (nil if still running)
  24. }
  25. // NodeVolumeUsage tracks storage usage for a disk volume attached to a node.
  26. // Used for cost allocation of cloud storage resources (e.g., AWS EBS volumes).
  27. type NodeVolumeUsage struct {
  28. VolumeUID string `json:"volumeUid"` // "root" for primary disk, or actual volume UID for additional volumes
  29. CapacityBytes Measurement `json:"capacityBytes"` // Total capacity of the volume in bytes
  30. UsageByteSeconds Measurement `json:"usageByteSeconds"` // Cumulative usage (Byte × seconds) over measurement window
  31. VolumeType string `json:"volumeType"` // "root" for primary disk, "persistent" for additional PVs
  32. ProviderID string `json:"providerId"` // Cloud provider volume ID (e.g., "vol-xxxxx" for AWS EBS)
  33. DurationSeconds Measurement `json:"durationSeconds"` // Duration the volume was attached during measurement window in seconds
  34. }
  35. // CpuMillicoreUsageAverage calculates the average CPU usage in millicores over the uptime period.
  36. // Returns 0 if uptime is 0 to avoid division by zero.
  37. func (n *Node) CpuMillicoreUsageAverage() Measurement {
  38. if n.DurationSeconds == 0 {
  39. return 0
  40. }
  41. return n.CpuMillicoreSeconds / n.DurationSeconds
  42. }
  43. // RAMByteUsageAverage calculates the average RAM usage in bytes over the uptime period.
  44. // Returns 0 if uptime is 0 to avoid division by zero.
  45. func (n *Node) RAMByteUsageAverage() Measurement {
  46. if n.DurationSeconds == 0 {
  47. return 0
  48. }
  49. return n.RAMByteSeconds / n.DurationSeconds
  50. }
  51. // TotalVolumeUsageByteSeconds returns the sum of all volume usage Byte-seconds across all attached volumes.
  52. func (n *Node) TotalVolumeUsageByteSeconds() Measurement {
  53. var total Measurement
  54. for _, volume := range n.AttachedVolumes {
  55. total += volume.UsageByteSeconds
  56. }
  57. return total
  58. }
  59. // TotalVolumeCapacityBytes returns the sum of all volume capacities across all attached volumes.
  60. func (n *Node) TotalVolumeCapacityBytes() Measurement {
  61. var total Measurement
  62. for _, volume := range n.AttachedVolumes {
  63. total += volume.CapacityBytes
  64. }
  65. return total
  66. }
  67. // GetVolumeUsageAverage calculates the average storage usage in bytes for a specific volume over the uptime period.
  68. // Returns 0 if uptime is 0 or volume doesn't exist.
  69. func (n *Node) GetVolumeUsageAverage(volumeUID string) Measurement {
  70. volume, exists := n.AttachedVolumes[volumeUID]
  71. if !exists || n.DurationSeconds == 0 {
  72. return 0
  73. }
  74. return volume.UsageByteSeconds / n.DurationSeconds
  75. }
  76. func (kms *KubeModelSet) RegisterNode(uid, name string) error {
  77. if uid == "" {
  78. err := fmt.Errorf("UID is nil for Node '%s'", name)
  79. kms.Error(err)
  80. return err
  81. }
  82. if _, ok := kms.Nodes[uid]; !ok {
  83. if kms.Cluster == nil {
  84. kms.Warnf("RegisterNode(%s, %s): Cluster is nil", uid, name)
  85. }
  86. kms.Nodes[uid] = &Node{
  87. UID: uid,
  88. Name: name,
  89. AttachedVolumes: make(map[string]*NodeVolumeUsage),
  90. }
  91. kms.Metadata.ObjectCount++
  92. }
  93. return nil
  94. }