allocation_types.go 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
  1. package costmodel
  2. import (
  3. "fmt"
  4. "time"
  5. "github.com/opencost/opencost/pkg/kubecost"
  6. )
  7. // pod describes a running pod's start and end time within a Window and
  8. // all the Allocations (i.e. containers) contained within it.
  9. type pod struct {
  10. Window kubecost.Window
  11. Start time.Time
  12. End time.Time
  13. Key podKey
  14. Node string
  15. Allocations map[string]*kubecost.Allocation
  16. }
  17. func (p *pod) equal(that *pod) bool {
  18. if p == nil {
  19. return that == nil
  20. }
  21. if !p.Window.Equal(that.Window) {
  22. return false
  23. }
  24. if !p.Start.Equal(that.Start) {
  25. return false
  26. }
  27. if !p.End.Equal(that.End) {
  28. return false
  29. }
  30. if p.Key != that.Key {
  31. return false
  32. }
  33. if p.Key != that.Key {
  34. return false
  35. }
  36. if len(p.Allocations) != len(that.Allocations) {
  37. return false
  38. }
  39. for container, thisAlloc := range p.Allocations {
  40. thatAlloc, ok := that.Allocations[container]
  41. if !ok || !thisAlloc.Equal(thatAlloc) {
  42. return false
  43. }
  44. }
  45. return true
  46. }
  47. // appendContainer adds an entry for the given container name to the pod.
  48. func (p *pod) appendContainer(container string) {
  49. name := fmt.Sprintf("%s/%s/%s/%s", p.Key.Cluster, p.Key.Namespace, p.Key.Pod, container)
  50. alloc := &kubecost.Allocation{
  51. Name: name,
  52. Properties: &kubecost.AllocationProperties{},
  53. Window: p.Window.Clone(),
  54. Start: p.Start,
  55. End: p.End,
  56. }
  57. alloc.Properties.Container = container
  58. alloc.Properties.Pod = p.Key.Pod
  59. alloc.Properties.Namespace = p.Key.Namespace
  60. alloc.Properties.Cluster = p.Key.Cluster
  61. p.Allocations[container] = alloc
  62. }
  63. // pvc describes a PersistentVolumeClaim
  64. // TODO:CLEANUP move to pkg/kubecost?
  65. // TODO:CLEANUP add PersistentVolumeClaims field to type Allocation?
  66. type pvc struct {
  67. Bytes float64 `json:"bytes"`
  68. Name string `json:"name"`
  69. Cluster string `json:"cluster"`
  70. Namespace string `json:"namespace"`
  71. Volume *pv `json:"persistentVolume"`
  72. Mounted bool `json:"mounted"`
  73. Start time.Time `json:"start"`
  74. End time.Time `json:"end"`
  75. }
  76. // Cost computes the cumulative cost of the pvc
  77. func (p *pvc) Cost() float64 {
  78. if p == nil || p.Volume == nil {
  79. return 0.0
  80. }
  81. gib := p.Bytes / 1024 / 1024 / 1024
  82. hrs := p.minutes() / 60.0
  83. return p.Volume.CostPerGiBHour * gib * hrs
  84. }
  85. // Minutes computes the number of minutes over which the pvc is defined
  86. func (p *pvc) minutes() float64 {
  87. if p == nil {
  88. return 0.0
  89. }
  90. return p.End.Sub(p.Start).Minutes()
  91. }
  92. // String returns a string representation of the pvc
  93. func (p *pvc) String() string {
  94. if p == nil {
  95. return "<nil>"
  96. }
  97. return fmt.Sprintf("%s/%s/%s{Bytes:%.2f, Cost:%.6f, Start,End:%s}", p.Cluster, p.Namespace, p.Name, p.Bytes, p.Cost(), kubecost.NewWindow(&p.Start, &p.End))
  98. }
  99. // Key returns the pvcKey for the calling pvc
  100. func (p *pvc) key() pvcKey {
  101. return newPVCKey(p.Cluster, p.Namespace, p.Name)
  102. }
  103. // pv describes a PersistentVolume
  104. type pv struct {
  105. Start time.Time `json:"start"`
  106. End time.Time `json:"end"`
  107. Bytes float64 `json:"bytes"`
  108. CostPerGiBHour float64 `json:"costPerGiBHour"`
  109. Cluster string `json:"cluster"`
  110. Name string `json:"name"`
  111. StorageClass string `json:"storageClass"`
  112. ProviderID string `json:"providerID"`
  113. }
  114. func (p *pv) clone() *pv {
  115. if p == nil {
  116. return nil
  117. }
  118. return &pv{
  119. Start: p.Start,
  120. End: p.End,
  121. Bytes: p.Bytes,
  122. CostPerGiBHour: p.CostPerGiBHour,
  123. Cluster: p.Cluster,
  124. Name: p.Name,
  125. StorageClass: p.StorageClass,
  126. }
  127. }
  128. func (p *pv) equal(that *pv) bool {
  129. if p == nil {
  130. return that == nil
  131. }
  132. if !p.Start.Equal(that.Start) {
  133. return false
  134. }
  135. if !p.End.Equal(that.End) {
  136. return false
  137. }
  138. if p.Bytes != that.Bytes {
  139. return false
  140. }
  141. if p.CostPerGiBHour != that.CostPerGiBHour {
  142. return false
  143. }
  144. if p.Cluster != that.Cluster {
  145. return false
  146. }
  147. if p.Name != that.Name {
  148. return false
  149. }
  150. if p.StorageClass != that.StorageClass {
  151. return false
  152. }
  153. return true
  154. }
  155. // String returns a string representation of the pv
  156. func (p *pv) String() string {
  157. if p == nil {
  158. return "<nil>"
  159. }
  160. return fmt.Sprintf("%s/%s{Bytes:%.2f, Cost/GiB*Hr:%.6f, StorageClass:%s, ProviderID: %s}", p.Cluster, p.Name, p.Bytes, p.CostPerGiBHour, p.StorageClass, p.ProviderID)
  161. }
  162. func (p *pv) minutes() float64 {
  163. if p == nil {
  164. return 0.0
  165. }
  166. return p.End.Sub(p.Start).Minutes()
  167. }
  168. // key returns the pvKey for the calling pvc
  169. func (p *pv) key() pvKey {
  170. return newPVKey(p.Cluster, p.Name)
  171. }
  172. // lbCost describes the start and end time of a Load Balancer along with cost
  173. type lbCost struct {
  174. TotalCost float64
  175. Start time.Time
  176. End time.Time
  177. Private bool
  178. Ip string
  179. }