container.go 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. package kubemodel
  2. import (
  3. "time"
  4. "github.com/opencost/opencost/core/pkg/log"
  5. "github.com/opencost/opencost/core/pkg/model/kubemodel"
  6. "github.com/opencost/opencost/core/pkg/source"
  7. )
  8. // resourceUnitValue converts prometheus resource/unit strings from ResourceResult
  9. // into kubemodel types, applying any necessary unit conversions.
  10. func resourceUnitValue(resource, unit string, value float64) (kubemodel.Resource, kubemodel.Unit, float64) {
  11. switch resource {
  12. case "cpu":
  13. return kubemodel.ResourceCPU, kubemodel.UnitCore, value
  14. case "memory":
  15. return kubemodel.ResourceMemory, kubemodel.UnitByte, value
  16. default:
  17. return kubemodel.Resource(resource), kubemodel.Unit(unit), value
  18. }
  19. }
  20. func (km *KubeModel) computeContainers(kms *kubemodel.KubeModelSet, start, end time.Time) error {
  21. grp := source.NewQueryGroup()
  22. metrics := km.ds.Metrics()
  23. containerUptimeFuture := source.WithGroup(grp, metrics.QueryContainerUptime(start, end))
  24. containerResourceRequestsFuture := source.WithGroup(grp, metrics.QueryContainerResourceRequests(start, end))
  25. containerResourceLimitsFuture := source.WithGroup(grp, metrics.QueryContainerResourceLimits(start, end))
  26. cpuCoresAllocatedFuture := source.WithGroup(grp, metrics.QueryCPUCoresAllocated(start, end))
  27. cpuUsageAvgFuture := source.WithGroup(grp, metrics.QueryCPUUsageAvg(start, end))
  28. cpuUsageMaxFuture := source.WithGroup(grp, metrics.QueryCPUUsageMax(start, end))
  29. ramBytesAllocatedFuture := source.WithGroup(grp, metrics.QueryRAMBytesAllocated(start, end))
  30. ramUsageAvgFuture := source.WithGroup(grp, metrics.QueryRAMUsageAvg(start, end))
  31. ramUsageMaxFuture := source.WithGroup(grp, metrics.QueryRAMUsageMax(start, end))
  32. deviceUsageAvgFuture := source.WithGroup(grp, metrics.QueryDCGMContainerUsageAvg(start, end))
  33. deviceUsageMaxFuture := source.WithGroup(grp, metrics.QueryDCGMContainerUsageMax(start, end))
  34. type containerKey struct {
  35. podUID string
  36. name string
  37. }
  38. containerMap := make(map[containerKey]*kubemodel.Container)
  39. containerUptimeResult, _ := containerUptimeFuture.Await()
  40. for _, res := range containerUptimeResult {
  41. key := containerKey{podUID: res.UID, name: res.Container}
  42. s, e := res.GetStartEnd(start, end, km.ds.Resolution())
  43. containerMap[key] = &kubemodel.Container{
  44. PodUID: res.UID,
  45. Name: res.Container,
  46. ResourceRequests: make(kubemodel.ResourceQuantities),
  47. ResourceLimits: make(kubemodel.ResourceQuantities),
  48. Start: s,
  49. End: e,
  50. }
  51. }
  52. containerResourceRequestsResult, _ := containerResourceRequestsFuture.Await()
  53. for _, res := range containerResourceRequestsResult {
  54. key := containerKey{podUID: res.UID, name: res.Container}
  55. container, ok := containerMap[key]
  56. if !ok {
  57. log.Warnf("container %s/%s has not been initialized to add resource requests", res.UID, res.Container)
  58. continue
  59. }
  60. resource, unit, value := resourceUnitValue(res.Resource, res.Unit, res.Value)
  61. container.ResourceRequests.Set(resource, unit, kubemodel.StatAvg, value)
  62. }
  63. containerResourceLimitsResult, _ := containerResourceLimitsFuture.Await()
  64. for _, res := range containerResourceLimitsResult {
  65. key := containerKey{podUID: res.UID, name: res.Container}
  66. container, ok := containerMap[key]
  67. if !ok {
  68. log.Warnf("container %s/%s has not been initialized to add resource limits", res.UID, res.Container)
  69. continue
  70. }
  71. resource, unit, value := resourceUnitValue(res.Resource, res.Unit, res.Value)
  72. container.ResourceLimits.Set(resource, unit, kubemodel.StatAvg, value)
  73. }
  74. cpuCoresAllocatedResult, _ := cpuCoresAllocatedFuture.Await()
  75. for _, res := range cpuCoresAllocatedResult {
  76. key := containerKey{podUID: res.UID, name: res.Container}
  77. container, ok := containerMap[key]
  78. if !ok {
  79. log.Warnf("container %s/%s has not been initialized to add CPU cores allocated", res.UID, res.Container)
  80. continue
  81. }
  82. if len(res.Data) > 0 {
  83. container.CPUCoreAllocationAvg = res.Data[0].Value
  84. }
  85. }
  86. ramBytesAllocatedResult, _ := ramBytesAllocatedFuture.Await()
  87. for _, res := range ramBytesAllocatedResult {
  88. key := containerKey{podUID: res.UID, name: res.Container}
  89. container, ok := containerMap[key]
  90. if !ok {
  91. log.Warnf("container %s/%s has not been initialized to add RAM bytes allocated", res.UID, res.Container)
  92. continue
  93. }
  94. if len(res.Data) > 0 {
  95. container.RAMBytesAllocationAvg = res.Data[0].Value
  96. }
  97. }
  98. cpuUsageAvgResult, _ := cpuUsageAvgFuture.Await()
  99. for _, res := range cpuUsageAvgResult {
  100. key := containerKey{podUID: res.UID, name: res.Container}
  101. container, ok := containerMap[key]
  102. if !ok {
  103. log.Warnf("container %s/%s has not been initialized to add CPU usage avg", res.UID, res.Container)
  104. continue
  105. }
  106. if len(res.Data) > 0 {
  107. container.CPUCoreUsageAvg = res.Data[0].Value
  108. }
  109. }
  110. cpuUsageMaxResult, _ := cpuUsageMaxFuture.Await()
  111. for _, res := range cpuUsageMaxResult {
  112. key := containerKey{podUID: res.UID, name: res.Container}
  113. container, ok := containerMap[key]
  114. if !ok {
  115. log.Warnf("container %s/%s has not been initialized to add CPU usage max", res.UID, res.Container)
  116. continue
  117. }
  118. if len(res.Data) > 0 {
  119. container.CPUCoreUsageMax = res.Data[0].Value
  120. }
  121. }
  122. ramUsageAvgResult, _ := ramUsageAvgFuture.Await()
  123. for _, res := range ramUsageAvgResult {
  124. key := containerKey{podUID: res.UID, name: res.Container}
  125. container, ok := containerMap[key]
  126. if !ok {
  127. log.Warnf("container %s/%s has not been initialized to add RAM usage avg", res.UID, res.Container)
  128. continue
  129. }
  130. if len(res.Data) > 0 {
  131. container.RAMBytesUsageAvg = res.Data[0].Value
  132. }
  133. }
  134. ramUsageMaxResult, _ := ramUsageMaxFuture.Await()
  135. for _, res := range ramUsageMaxResult {
  136. key := containerKey{podUID: res.UID, name: res.Container}
  137. container, ok := containerMap[key]
  138. if !ok {
  139. log.Warnf("container %s/%s has not been initialized to add RAM usage max", res.UID, res.Container)
  140. continue
  141. }
  142. if len(res.Data) > 0 {
  143. container.RAMBytesUsageMax = res.Data[0].Value
  144. }
  145. }
  146. deviceUsageAvgResult, _ := deviceUsageAvgFuture.Await()
  147. for _, res := range deviceUsageAvgResult {
  148. if res.PodUID == "" || res.Container == "" {
  149. continue
  150. }
  151. key := containerKey{podUID: res.PodUID, name: res.Container}
  152. container, ok := containerMap[key]
  153. if !ok {
  154. log.Warnf("container %s/%s has not been initialized to add device usage avg", res.PodUID, res.Container)
  155. continue
  156. }
  157. if container.DeviceUsages == nil {
  158. container.DeviceUsages = make(map[string]kubemodel.DeviceUsage)
  159. }
  160. usage := container.DeviceUsages[res.UUID]
  161. usage.UsageAvg = res.Value
  162. container.DeviceUsages[res.UUID] = usage
  163. }
  164. deviceUsageMaxResult, _ := deviceUsageMaxFuture.Await()
  165. for _, res := range deviceUsageMaxResult {
  166. if res.PodUID == "" || res.Container == "" {
  167. continue
  168. }
  169. key := containerKey{podUID: res.PodUID, name: res.Container}
  170. container, ok := containerMap[key]
  171. if !ok {
  172. log.Warnf("container %s/%s has not been initialized to add device usage max", res.PodUID, res.Container)
  173. continue
  174. }
  175. if container.DeviceUsages == nil {
  176. container.DeviceUsages = make(map[string]kubemodel.DeviceUsage)
  177. }
  178. usage := container.DeviceUsages[res.UUID]
  179. usage.UsageMax = res.Value
  180. container.DeviceUsages[res.UUID] = usage
  181. }
  182. for _, container := range containerMap {
  183. err := kms.RegisterContainer(container)
  184. if err != nil {
  185. log.Warnf("Failed to register container: %s", err.Error())
  186. }
  187. }
  188. return nil
  189. }