kubemodel.go 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. package kubemodel
  2. import (
  3. "fmt"
  4. "time"
  5. )
  6. // @bingen:generate[stringtable,streamable]:KubeModelSet
  7. type KubeModelSet struct {
  8. Metadata *Metadata `json:"meta"` // @bingen:field[version=1]
  9. Window Window `json:"window"` // @bingen:field[version=1]
  10. Cluster *Cluster `json:"cluster"` // @bingen:field[version=1]
  11. Namespaces map[string]*Namespace `json:"namespaces"` // @bingen:field[version=1]
  12. ResourceQuotas map[string]*ResourceQuota `json:"resourceQuotas"` // @bingen:field[version=1]
  13. Services map[string]*Service `json:"services"` // @bingen:field[version=2]
  14. Deployments map[string]*Deployment `json:"deployments"` // @bingen:field[version=2]
  15. StatefulSets map[string]*StatefulSet `json:"statefulSets"` // @bingen:field[version=2]
  16. DaemonSets map[string]*DaemonSet `json:"daemonSets"` // @bingen:field[version=2]
  17. Jobs map[string]*Job `json:"jobs"` // @bingen:field[version=2]
  18. CronJobs map[string]*CronJob `json:"cronJobs"` // @bingen:field[version=2]
  19. ReplicaSets map[string]*ReplicaSet `json:"replicaSets"` // @bingen:field[version=2]
  20. Nodes map[string]*Node `json:"nodes"` // @bingen:field[version=2]
  21. PersistentVolumes map[string]*PersistentVolume `json:"persistentVolumes"` // @bingen:field[version=2]
  22. PersistentVolumeClaims map[string]*PersistentVolumeClaim `json:"pvcs"` // @bingen:field[version=2]
  23. Pods map[string]*Pod `json:"pods"` // @bingen:field[version=2]
  24. Containers map[string]*Container `json:"containers"` // @bingen:field[version=2]
  25. DCGMDevices map[string]*DCGMDevice `json:"dcgmDevices"` // @bingen:field[version=2]
  26. idx *kubeModelSetIndexes // @bingen:field[ignore]
  27. }
  28. func NewKubeModelSet(start time.Time, end time.Time) *KubeModelSet {
  29. now := time.Now().UTC()
  30. kms := &KubeModelSet{
  31. Metadata: &Metadata{
  32. CreatedAt: now,
  33. CompletedAt: now, // Will be updated when processing completes
  34. DiagnosticLevel: DefaultDiagnosticLevel,
  35. },
  36. Window: Window{
  37. Start: start,
  38. End: end,
  39. },
  40. Containers: map[string]*Container{},
  41. Deployments: map[string]*Deployment{},
  42. StatefulSets: map[string]*StatefulSet{},
  43. DaemonSets: map[string]*DaemonSet{},
  44. Jobs: map[string]*Job{},
  45. CronJobs: map[string]*CronJob{},
  46. ReplicaSets: map[string]*ReplicaSet{},
  47. Namespaces: map[string]*Namespace{},
  48. Nodes: map[string]*Node{},
  49. DCGMDevices: map[string]*DCGMDevice{},
  50. Pods: map[string]*Pod{},
  51. PersistentVolumeClaims: map[string]*PersistentVolumeClaim{},
  52. ResourceQuotas: map[string]*ResourceQuota{},
  53. Services: map[string]*Service{},
  54. PersistentVolumes: map[string]*PersistentVolume{},
  55. idx: newKubeModelSetIndexes(),
  56. }
  57. return kms
  58. }
  59. // GetNamespaceByName retrieves a namespace by its name using the index
  60. func (kms *KubeModelSet) GetNamespaceByName(name string) (*Namespace, bool) {
  61. if kms.idx == nil {
  62. return nil, false
  63. }
  64. uid, ok := kms.idx.namespaceNameToID[name]
  65. if !ok {
  66. return nil, false
  67. }
  68. ns, ok := kms.Namespaces[uid]
  69. return ns, ok
  70. }
  71. // IsEmpty returns true if the KubeModelSet is nil, has no cluster, or contains no resources
  72. func (kms *KubeModelSet) IsEmpty() bool {
  73. if kms == nil || kms.Cluster == nil {
  74. return true
  75. }
  76. // Check if all resource maps are empty
  77. return len(kms.Containers) == 0 &&
  78. len(kms.Deployments) == 0 &&
  79. len(kms.StatefulSets) == 0 &&
  80. len(kms.DaemonSets) == 0 &&
  81. len(kms.Jobs) == 0 &&
  82. len(kms.CronJobs) == 0 &&
  83. len(kms.ReplicaSets) == 0 &&
  84. len(kms.Namespaces) == 0 &&
  85. len(kms.Nodes) == 0 &&
  86. len(kms.DCGMDevices) == 0 &&
  87. len(kms.Pods) == 0 &&
  88. len(kms.PersistentVolumeClaims) == 0 &&
  89. len(kms.ResourceQuotas) == 0 &&
  90. len(kms.Services) == 0 &&
  91. len(kms.PersistentVolumes) == 0
  92. }
  93. // checkWindow validates that the given start/end times are fully contained within
  94. // the KubeModelSet window. It records and returns an error if they are not.
  95. func checkWindow(window Window, start, end time.Time) error {
  96. if window.Start.After(start) ||
  97. window.Start.After(end) ||
  98. window.End.Before(start) ||
  99. window.End.Before(end) {
  100. return fmt.Errorf(
  101. "start or end time (%s-%s) is outside of the window %s-%s",
  102. start.Format(time.RFC3339),
  103. end.Format(time.RFC3339),
  104. window.Start.Format(time.RFC3339),
  105. window.End.Format(time.RFC3339),
  106. )
  107. }
  108. return nil
  109. }
  110. type kubeModelSetIndexes struct {
  111. namespaceNameToID map[string]string
  112. namespaceByName map[string]*Namespace
  113. }
  114. func newKubeModelSetIndexes() *kubeModelSetIndexes {
  115. return &kubeModelSetIndexes{
  116. namespaceNameToID: make(map[string]string),
  117. namespaceByName: make(map[string]*Namespace),
  118. }
  119. }