assets.go 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. package costmodel
  2. import (
  3. "fmt"
  4. "time"
  5. "github.com/opencost/opencost/core/pkg/log"
  6. "github.com/opencost/opencost/core/pkg/opencost"
  7. )
  8. func (cm *CostModel) ComputeAssets(start, end time.Time) (*opencost.AssetSet, error) {
  9. assetSet := opencost.NewAssetSet(start, end)
  10. nodeMap, err := cm.ClusterNodes(start, end)
  11. if err != nil {
  12. return nil, fmt.Errorf("error computing node assets for %s: %w", opencost.NewClosedWindow(start, end), err)
  13. }
  14. lbMap, err := cm.ClusterLoadBalancers(start, end)
  15. if err != nil {
  16. return nil, fmt.Errorf("error computing load balancer assets for %s: %w", opencost.NewClosedWindow(start, end), err)
  17. }
  18. diskMap, err := cm.ClusterDisks(start, end)
  19. if err != nil {
  20. return nil, fmt.Errorf("error computing disk assets for %s: %w", opencost.NewClosedWindow(start, end), err)
  21. }
  22. for _, d := range diskMap {
  23. s := d.Start
  24. if s.Before(start) || s.After(end) {
  25. log.Debugf("CostModel.ComputeAssets: disk '%s' start outside window: %s not in [%s, %s]", d.Name, s.Format("2006-01-02T15:04:05"), start.Format("2006-01-02T15:04:05"), end.Format("2006-01-02T15:04:05"))
  26. s = start
  27. }
  28. e := d.End
  29. if e.Before(start) || e.After(end) {
  30. log.Debugf("CostModel.ComputeAssets: disk '%s' end outside window: %s not in [%s, %s]", d.Name, e.Format("2006-01-02T15:04:05"), start.Format("2006-01-02T15:04:05"), end.Format("2006-01-02T15:04:05"))
  31. e = end
  32. }
  33. hours := e.Sub(s).Hours()
  34. disk := opencost.NewDisk(d.Name, d.Cluster, d.ProviderID, s, e, opencost.NewWindow(&start, &end))
  35. cm.PropertiesFromCluster(disk.Properties)
  36. disk.Cost = d.Cost
  37. disk.ByteHours = d.Bytes * hours
  38. if d.BytesUsedAvgPtr != nil {
  39. byteHours := *d.BytesUsedAvgPtr * hours
  40. disk.ByteHoursUsed = &byteHours
  41. }
  42. if d.BytesUsedMaxPtr != nil {
  43. usageMax := *d.BytesUsedMaxPtr
  44. disk.ByteUsageMax = &usageMax
  45. }
  46. if d.Local {
  47. disk.Local = 1.0
  48. }
  49. disk.Breakdown = &opencost.Breakdown{
  50. Idle: d.Breakdown.Idle,
  51. System: d.Breakdown.System,
  52. User: d.Breakdown.User,
  53. Other: d.Breakdown.Other,
  54. }
  55. disk.StorageClass = d.StorageClass
  56. disk.VolumeName = d.VolumeName
  57. disk.ClaimName = d.ClaimName
  58. disk.ClaimNamespace = d.ClaimNamespace
  59. assetSet.Insert(disk, nil)
  60. }
  61. for _, lb := range lbMap {
  62. s := lb.Start
  63. if s.Before(start) || s.After(end) {
  64. log.Debugf("CostModel.ComputeAssets: load balancer '%s' start outside window: %s not in [%s, %s]", lb.Name, s.Format("2006-01-02T15:04:05"), start.Format("2006-01-02T15:04:05"), end.Format("2006-01-02T15:04:05"))
  65. s = start
  66. }
  67. e := lb.End
  68. if e.Before(start) || e.After(end) {
  69. log.Debugf("CostModel.ComputeAssets: load balancer '%s' end outside window: %s not in [%s, %s]", lb.Name, e.Format("2006-01-02T15:04:05"), start.Format("2006-01-02T15:04:05"), end.Format("2006-01-02T15:04:05"))
  70. e = end
  71. }
  72. loadBalancer := opencost.NewLoadBalancer(lb.Name, lb.Cluster, lb.ProviderID, s, e, opencost.NewWindow(&start, &end), lb.Private, lb.Ip)
  73. cm.PropertiesFromCluster(loadBalancer.Properties)
  74. loadBalancer.Cost = lb.Cost
  75. assetSet.Insert(loadBalancer, nil)
  76. }
  77. for _, n := range nodeMap {
  78. // check label, to see if node from fargate, if so ignore.
  79. if n.Labels != nil {
  80. if value, ok := n.Labels["label_eks_amazonaws_com_compute_type"]; ok && value == "fargate" {
  81. continue
  82. }
  83. }
  84. s := n.Start
  85. if s.Before(start) || s.After(end) {
  86. log.Debugf("CostModel.ComputeAssets: node '%s' start outside window: %s not in [%s, %s]", n.Name, s.Format("2006-01-02T15:04:05"), start.Format("2006-01-02T15:04:05"), end.Format("2006-01-02T15:04:05"))
  87. s = start
  88. }
  89. e := n.End
  90. if e.Before(start) || e.After(end) {
  91. log.Debugf("CostModel.ComputeAssets: node '%s' end outside window: %s not in [%s, %s]", n.Name, e.Format("2006-01-02T15:04:05"), start.Format("2006-01-02T15:04:05"), end.Format("2006-01-02T15:04:05"))
  92. e = end
  93. }
  94. hours := e.Sub(s).Hours()
  95. node := opencost.NewNode(n.Name, n.Cluster, n.ProviderID, s, e, opencost.NewWindow(&start, &end))
  96. cm.PropertiesFromCluster(node.Properties)
  97. node.NodeType = n.NodeType
  98. node.CPUCoreHours = n.CPUCores * hours
  99. node.RAMByteHours = n.RAMBytes * hours
  100. node.GPUHours = n.GPUCount * hours
  101. node.CPUBreakdown = &opencost.Breakdown{
  102. Idle: n.CPUBreakdown.Idle,
  103. System: n.CPUBreakdown.System,
  104. User: n.CPUBreakdown.User,
  105. Other: n.CPUBreakdown.Other,
  106. }
  107. node.RAMBreakdown = &opencost.Breakdown{
  108. Idle: n.RAMBreakdown.Idle,
  109. System: n.RAMBreakdown.System,
  110. User: n.RAMBreakdown.User,
  111. Other: n.RAMBreakdown.Other,
  112. }
  113. node.CPUCost = n.CPUCost
  114. node.GPUCost = n.GPUCost
  115. node.GPUCount = n.GPUCount
  116. node.RAMCost = n.RAMCost
  117. if n.Overhead != nil {
  118. node.Overhead = &opencost.NodeOverhead{
  119. RamOverheadFraction: n.Overhead.RamOverheadFraction,
  120. CpuOverheadFraction: n.Overhead.CpuOverheadFraction,
  121. OverheadCostFraction: ((n.Overhead.CpuOverheadFraction * n.CPUCost) +
  122. (n.Overhead.RamOverheadFraction * n.RAMCost)) / node.TotalCost(),
  123. }
  124. } else {
  125. node.Overhead = &opencost.NodeOverhead{}
  126. }
  127. node.Discount = n.Discount
  128. if n.Preemptible {
  129. node.Preemptible = 1.0
  130. }
  131. node.SetLabels(opencost.AssetLabels(n.Labels))
  132. assetSet.Insert(node, nil)
  133. }
  134. return assetSet, nil
  135. }
  136. func (cm *CostModel) ClusterDisks(start, end time.Time) (map[DiskIdentifier]*Disk, error) {
  137. return ClusterDisks(cm.PrometheusClient, cm.Provider, start, end)
  138. }
  139. func (cm *CostModel) ClusterLoadBalancers(start, end time.Time) (map[LoadBalancerIdentifier]*LoadBalancer, error) {
  140. return ClusterLoadBalancers(cm.PrometheusClient, start, end)
  141. }
  142. func (cm *CostModel) ClusterNodes(start, end time.Time) (map[NodeIdentifier]*Node, error) {
  143. return ClusterNodes(cm.Provider, cm.PrometheusClient, start, end)
  144. }
  145. // propertiesFromCluster populates static cluster properties to individual asset properties
  146. func (cm *CostModel) PropertiesFromCluster(props *opencost.AssetProperties) {
  147. // If properties does not have cluster value, do nothing
  148. if props.Cluster == "" {
  149. return
  150. }
  151. clusterMap := cm.ClusterMap.AsMap()
  152. ci, ok := clusterMap[props.Cluster]
  153. if !ok {
  154. log.Debugf("CostMode.PropertiesFromCluster: cluster '%s' was not found in ClusterMap", props.Cluster)
  155. return
  156. }
  157. props.Project = ci.Project
  158. props.Account = ci.Account
  159. props.Provider = ci.Provider
  160. }