mock.go 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806
  1. package kubecost
  2. import (
  3. "fmt"
  4. "strconv"
  5. "time"
  6. )
  7. const gb = 1024 * 1024 * 1024
  8. const day = 24 * time.Hour
  9. var disk = PVKey{
  10. Cluster: "cluster1",
  11. Name: "pv1",
  12. }
  13. // NewMockUnitAllocation creates an *Allocation with all of its float64 values set to 1 and generic properties if not provided in arg
  14. func NewMockUnitAllocation(name string, start time.Time, resolution time.Duration, props *AllocationProperties) *Allocation {
  15. if name == "" {
  16. name = "cluster1/namespace1/pod1/container1"
  17. }
  18. properties := &AllocationProperties{}
  19. if props == nil {
  20. properties.Cluster = "cluster1"
  21. properties.Node = "node1"
  22. properties.Namespace = "namespace1"
  23. properties.ControllerKind = "deployment"
  24. properties.Controller = "deployment1"
  25. properties.Pod = "pod1"
  26. properties.Container = "container1"
  27. } else {
  28. properties = props
  29. }
  30. end := start.Add(resolution)
  31. alloc := &Allocation{
  32. Name: name,
  33. Properties: properties,
  34. Window: NewWindow(&start, &end).Clone(),
  35. Start: start,
  36. End: end,
  37. CPUCoreHours: 1,
  38. CPUCost: 1,
  39. CPUCoreRequestAverage: 1,
  40. CPUCoreUsageAverage: 1,
  41. GPUHours: 1,
  42. GPUCost: 1,
  43. NetworkCost: 1,
  44. LoadBalancerCost: 1,
  45. PVs: PVAllocations{
  46. disk: {
  47. ByteHours: 1,
  48. Cost: 1,
  49. },
  50. },
  51. RAMByteHours: 1,
  52. RAMCost: 1,
  53. RAMBytesRequestAverage: 1,
  54. RAMBytesUsageAverage: 1,
  55. RawAllocationOnly: &RawAllocationOnlyData{
  56. CPUCoreUsageMax: 1,
  57. RAMBytesUsageMax: 1,
  58. },
  59. ProportionalAssetResourceCosts: nil,
  60. }
  61. // If idle allocation, remove non-idle costs, but maintain total cost
  62. if alloc.IsIdle() {
  63. alloc.PVs = nil
  64. alloc.NetworkCost = 0.0
  65. alloc.LoadBalancerCost = 0.0
  66. alloc.CPUCoreHours += 1.0
  67. alloc.CPUCost += 1.0
  68. alloc.RAMByteHours += 1.0
  69. alloc.RAMCost += 1.0
  70. }
  71. return alloc
  72. }
  73. // GenerateMockAllocationSetClusterIdle creates generic allocation set which includes an idle set broken down by cluster
  74. func GenerateMockAllocationSetClusterIdle(start time.Time) *AllocationSet {
  75. // Cluster Idle allocations
  76. a1i := NewMockUnitAllocation(fmt.Sprintf("cluster1/%s", IdleSuffix), start, day, &AllocationProperties{
  77. Cluster: "cluster1",
  78. })
  79. a1i.CPUCost = 5.0
  80. a1i.RAMCost = 15.0
  81. a1i.GPUCost = 0.0
  82. a2i := NewMockUnitAllocation(fmt.Sprintf("cluster2/%s", IdleSuffix), start, day, &AllocationProperties{
  83. Cluster: "cluster2",
  84. })
  85. a2i.CPUCost = 5.0
  86. a2i.RAMCost = 5.0
  87. a2i.GPUCost = 0.0
  88. as := GenerateMockAllocationSet(start)
  89. as.Insert(a1i)
  90. as.Insert(a2i)
  91. return as
  92. }
  93. // GenerateMockAllocationSetNodeIdle creates generic allocation set which includes an idle set broken down by node
  94. func GenerateMockAllocationSetNodeIdle(start time.Time) *AllocationSet {
  95. // Node Idle allocations
  96. a11i := NewMockUnitAllocation(fmt.Sprintf("c1nodes/%s", IdleSuffix), start, day, &AllocationProperties{
  97. Cluster: "cluster1",
  98. Node: "c1nodes",
  99. ProviderID: "c1nodes",
  100. })
  101. a11i.CPUCost = 5.0
  102. a11i.RAMCost = 15.0
  103. a11i.GPUCost = 0.0
  104. a21i := NewMockUnitAllocation(fmt.Sprintf("node1/%s", IdleSuffix), start, day, &AllocationProperties{
  105. Cluster: "cluster2",
  106. Node: "node1",
  107. ProviderID: "node1",
  108. })
  109. a21i.CPUCost = 1.666667
  110. a21i.RAMCost = 1.666667
  111. a21i.GPUCost = 0.0
  112. a22i := NewMockUnitAllocation(fmt.Sprintf("node2/%s", IdleSuffix), start, day, &AllocationProperties{
  113. Cluster: "cluster2",
  114. Node: "node2",
  115. ProviderID: "node2",
  116. })
  117. a22i.CPUCost = 1.666667
  118. a22i.RAMCost = 1.666667
  119. a22i.GPUCost = 0.0
  120. a23i := NewMockUnitAllocation(fmt.Sprintf("node3/%s", IdleSuffix), start, day, &AllocationProperties{
  121. Cluster: "cluster2",
  122. Node: "node3",
  123. ProviderID: "node3",
  124. Namespace: "",
  125. })
  126. a23i.CPUCost = 1.666667
  127. a23i.RAMCost = 1.666667
  128. a23i.GPUCost = 0.0
  129. as := GenerateMockAllocationSet(start)
  130. as.Insert(a11i)
  131. as.Insert(a21i)
  132. as.Insert(a22i)
  133. as.Insert(a23i)
  134. return as
  135. }
  136. // GenerateMockAllocationSet creates generic allocation set without idle allocations
  137. func GenerateMockAllocationSet(start time.Time) *AllocationSet {
  138. // Active allocations
  139. a1111 := NewMockUnitAllocation("cluster1/namespace1/pod1/container1", start, day, &AllocationProperties{
  140. Cluster: "cluster1",
  141. Namespace: "namespace1",
  142. Pod: "pod1",
  143. Container: "container1",
  144. ProviderID: "c1nodes",
  145. Node: "c1nodes",
  146. })
  147. a1111.RAMCost = 11.00
  148. a11abc2 := NewMockUnitAllocation("cluster1/namespace1/pod-abc/container2", start, day, &AllocationProperties{
  149. Cluster: "cluster1",
  150. Namespace: "namespace1",
  151. Pod: "pod-abc",
  152. Container: "container2",
  153. ProviderID: "c1nodes",
  154. Node: "c1nodes",
  155. })
  156. a11def3 := NewMockUnitAllocation("cluster1/namespace1/pod-def/container3", start, day, &AllocationProperties{
  157. Cluster: "cluster1",
  158. Namespace: "namespace1",
  159. Pod: "pod-def",
  160. Container: "container3",
  161. ProviderID: "c1nodes",
  162. Node: "c1nodes",
  163. })
  164. a12ghi4 := NewMockUnitAllocation("cluster1/namespace2/pod-ghi/container4", start, day, &AllocationProperties{
  165. Cluster: "cluster1",
  166. Namespace: "namespace2",
  167. Pod: "pod-ghi",
  168. Container: "container4",
  169. ProviderID: "c1nodes",
  170. Node: "c1nodes",
  171. })
  172. a12ghi5 := NewMockUnitAllocation("cluster1/namespace2/pod-ghi/container5", start, day, &AllocationProperties{
  173. Cluster: "cluster1",
  174. Namespace: "namespace2",
  175. Pod: "pod-ghi",
  176. Container: "container5",
  177. ProviderID: "c1nodes",
  178. Node: "c1nodes",
  179. })
  180. a12jkl6 := NewMockUnitAllocation("cluster1/namespace2/pod-jkl/container6", start, day, &AllocationProperties{
  181. Cluster: "cluster1",
  182. Namespace: "namespace2",
  183. Pod: "pod-jkl",
  184. Container: "container6",
  185. ProviderID: "c1nodes",
  186. Node: "c1nodes",
  187. })
  188. a22mno4 := NewMockUnitAllocation("cluster2/namespace2/pod-mno/container4", start, day, &AllocationProperties{
  189. Cluster: "cluster2",
  190. Namespace: "namespace2",
  191. Pod: "pod-mno",
  192. Container: "container4",
  193. ProviderID: "node1",
  194. Node: "node1",
  195. })
  196. a22mno5 := NewMockUnitAllocation("cluster2/namespace2/pod-mno/container5", start, day, &AllocationProperties{
  197. Cluster: "cluster2",
  198. Namespace: "namespace2",
  199. Pod: "pod-mno",
  200. Container: "container5",
  201. ProviderID: "node1",
  202. Node: "node1",
  203. })
  204. a22pqr6 := NewMockUnitAllocation("cluster2/namespace2/pod-pqr/container6", start, day, &AllocationProperties{
  205. Cluster: "cluster2",
  206. Namespace: "namespace2",
  207. Pod: "pod-pqr",
  208. Container: "container6",
  209. ProviderID: "node2",
  210. Node: "node2",
  211. })
  212. a23stu7 := NewMockUnitAllocation("cluster2/namespace3/pod-stu/container7", start, day, &AllocationProperties{
  213. Cluster: "cluster2",
  214. Namespace: "namespace3",
  215. Pod: "pod-stu",
  216. Container: "container7",
  217. ProviderID: "node2",
  218. Node: "node2",
  219. })
  220. a23vwx8 := NewMockUnitAllocation("cluster2/namespace3/pod-vwx/container8", start, day, &AllocationProperties{
  221. Cluster: "cluster2",
  222. Namespace: "namespace3",
  223. Pod: "pod-vwx",
  224. Container: "container8",
  225. ProviderID: "node3",
  226. Node: "node3",
  227. })
  228. a23vwx9 := NewMockUnitAllocation("cluster2/namespace3/pod-vwx/container9", start, day, &AllocationProperties{
  229. Cluster: "cluster2",
  230. Namespace: "namespace3",
  231. Pod: "pod-vwx",
  232. Container: "container9",
  233. ProviderID: "node3",
  234. Node: "node3",
  235. })
  236. // Controllers
  237. a11abc2.Properties.ControllerKind = "deployment"
  238. a11abc2.Properties.Controller = "deployment1"
  239. a11def3.Properties.ControllerKind = "deployment"
  240. a11def3.Properties.Controller = "deployment1"
  241. a12ghi4.Properties.ControllerKind = "deployment"
  242. a12ghi4.Properties.Controller = "deployment2"
  243. a12ghi5.Properties.ControllerKind = "deployment"
  244. a12ghi5.Properties.Controller = "deployment2"
  245. a22mno4.Properties.ControllerKind = "deployment"
  246. a22mno4.Properties.Controller = "deployment2"
  247. a22mno5.Properties.ControllerKind = "deployment"
  248. a22mno5.Properties.Controller = "deployment2"
  249. a23stu7.Properties.ControllerKind = "deployment"
  250. a23stu7.Properties.Controller = "deployment3"
  251. a12jkl6.Properties.ControllerKind = "daemonset"
  252. a12jkl6.Properties.Controller = "daemonset1"
  253. a22pqr6.Properties.ControllerKind = "daemonset"
  254. a22pqr6.Properties.Controller = "daemonset1"
  255. a23vwx8.Properties.ControllerKind = "statefulset"
  256. a23vwx8.Properties.Controller = "statefulset1"
  257. a23vwx9.Properties.ControllerKind = "statefulset"
  258. a23vwx9.Properties.Controller = "statefulset1"
  259. // Labels
  260. a1111.Properties.Labels = map[string]string{"app": "app1", "env": "env1"}
  261. a12ghi4.Properties.Labels = map[string]string{"app": "app2", "env": "env2"}
  262. a12ghi5.Properties.Labels = map[string]string{"app": "app2", "env": "env2"}
  263. a22mno4.Properties.Labels = map[string]string{"app": "app2"}
  264. a22mno5.Properties.Labels = map[string]string{"app": "app2"}
  265. //Annotations
  266. a23stu7.Properties.Annotations = map[string]string{"team": "team1"}
  267. a23vwx8.Properties.Annotations = map[string]string{"team": "team2"}
  268. a23vwx9.Properties.Annotations = map[string]string{"team": "team1"}
  269. // Services
  270. a12jkl6.Properties.Services = []string{"service1"}
  271. a22pqr6.Properties.Services = []string{"service1"}
  272. return NewAllocationSet(start, start.Add(day),
  273. // cluster 1, namespace1
  274. a1111, a11abc2, a11def3,
  275. // cluster 1, namespace 2
  276. a12ghi4, a12ghi5, a12jkl6,
  277. // cluster 2, namespace 2
  278. a22mno4, a22mno5, a22pqr6,
  279. // cluster 2, namespace 3
  280. a23stu7, a23vwx8, a23vwx9,
  281. )
  282. }
  283. // GenerateMockAllocationSetWithAssetProperties with no idle and connections to Assets in properties
  284. func GenerateMockAllocationSetWithAssetProperties(start time.Time) *AllocationSet {
  285. as := GenerateMockAllocationSet(start)
  286. disk1 := PVKey{
  287. Cluster: "cluster2",
  288. Name: "disk1",
  289. }
  290. disk2 := PVKey{
  291. Cluster: "cluster2",
  292. Name: "disk2",
  293. }
  294. for _, a := range as.Allocations {
  295. // add reconcilable pvs to pod-mno
  296. if a.Properties.Pod == "pod-mno" {
  297. a.PVs = a.PVs.Add(PVAllocations{
  298. disk1: {
  299. Cost: 2.5,
  300. ByteHours: 2.5 * gb,
  301. },
  302. disk2: {
  303. Cost: 5,
  304. ByteHours: 5 * gb,
  305. },
  306. })
  307. }
  308. // add loadBalancer service to allocations
  309. if a.Name == "cluster2/namespace2/pod-mno/container4" {
  310. a.Properties.Services = append(a.Properties.Services, "loadBalancer1")
  311. }
  312. if a.Name == "cluster2/namespace2/pod-mno/container5" {
  313. a.Properties.Services = append(a.Properties.Services, "loadBalancer2")
  314. }
  315. if a.Name == "cluster2/namespace2/pod-pqr/container6" {
  316. a.Properties.Services = append(a.Properties.Services, "loadBalancer1")
  317. a.Properties.Services = append(a.Properties.Services, "loadBalancer2")
  318. }
  319. }
  320. return as
  321. }
  322. // GenerateMockAssetSets creates generic AssetSets
  323. func GenerateMockAssetSets(start, end time.Time) []*AssetSet {
  324. var assetSets []*AssetSet
  325. // Create an AssetSet representing cluster costs for two clusters (cluster1
  326. // and cluster2). Include Nodes and Disks for both, even though only
  327. // Nodes will be counted. Whereas in practice, Assets should be aggregated
  328. // by type, here we will provide multiple Nodes for one of the clusters to
  329. // make sure the function still holds.
  330. // NOTE: we're re-using GenerateMockAllocationSet so this has to line up with
  331. // the allocated node costs from that function. See table above.
  332. // | Hierarchy | Cost | CPU | RAM | GPU | Adjustment |
  333. // +-----------------------------------------+------+------+------+------+------------+
  334. // cluster1:
  335. // nodes 100.00 55.00 44.00 11.00 -10.00
  336. // +-----------------------------------------+------+------+------+------+------------+
  337. // cluster1 subtotal (adjusted) 100.00 50.00 40.00 10.00 0.00
  338. // +-----------------------------------------+------+------+------+------+------------+
  339. // cluster1 allocated 48.00 6.00 16.00 6.00 0.00
  340. // +-----------------------------------------+------+------+------+------+------------+
  341. // cluster1 idle 72.00 44.00 24.00 4.00 0.00
  342. // +-----------------------------------------+------+------+------+------+------------+
  343. // cluster2:
  344. // node1 35.00 20.00 15.00 0.00 0.00
  345. // node2 35.00 20.00 15.00 0.00 0.00
  346. // node3 30.00 10.00 10.00 10.00 0.00
  347. // (disks should not matter for idle)
  348. // +-----------------------------------------+------+------+------+------+------------+
  349. // cluster2 subtotal 100.00 50.00 40.00 10.00 0.00
  350. // +-----------------------------------------+------+------+------+------+------------+
  351. // cluster2 allocated 28.00 6.00 6.00 6.00 0.00
  352. // +-----------------------------------------+------+------+------+------+------------+
  353. // cluster2 idle 82.00 44.00 34.00 4.00 0.00
  354. // +-----------------------------------------+------+------+------+------+------------+
  355. cluster1Nodes := NewNode("c1nodes", "cluster1", "c1nodes", start, end, NewWindow(&start, &end))
  356. cluster1Nodes.CPUCost = 55.0
  357. cluster1Nodes.RAMCost = 44.0
  358. cluster1Nodes.GPUCost = 11.0
  359. cluster1Nodes.Adjustment = -10.00
  360. cluster1Nodes.CPUCoreHours = 8
  361. cluster1Nodes.RAMByteHours = 6
  362. cluster1Nodes.GPUHours = 24
  363. cluster2Node1 := NewNode("node1", "cluster2", "node1", start, end, NewWindow(&start, &end))
  364. cluster2Node1.CPUCost = 20.0
  365. cluster2Node1.RAMCost = 15.0
  366. cluster2Node1.GPUCost = 0.0
  367. cluster2Node1.CPUCoreHours = 4
  368. cluster2Node1.RAMByteHours = 3
  369. cluster2Node1.GPUHours = 0
  370. cluster2Node2 := NewNode("node2", "cluster2", "node2", start, end, NewWindow(&start, &end))
  371. cluster2Node2.CPUCost = 20.0
  372. cluster2Node2.RAMCost = 15.0
  373. cluster2Node2.GPUCost = 0.0
  374. cluster2Node2.CPUCoreHours = 3
  375. cluster2Node2.RAMByteHours = 2
  376. cluster2Node2.GPUHours = 0
  377. cluster2Node3 := NewNode("node3", "cluster2", "node3", start, end, NewWindow(&start, &end))
  378. cluster2Node3.CPUCost = 10.0
  379. cluster2Node3.RAMCost = 10.0
  380. cluster2Node3.GPUCost = 10.0
  381. cluster2Node3.CPUCoreHours = 2
  382. cluster2Node3.RAMByteHours = 2
  383. cluster2Node3.GPUHours = 24
  384. // Add PVs
  385. cluster2Disk1 := NewDisk("disk1", "cluster2", "disk1", start, end, NewWindow(&start, &end))
  386. cluster2Disk1.Cost = 5.0
  387. cluster2Disk1.Adjustment = 1.0
  388. cluster2Disk1.ByteHours = 5 * gb
  389. cluster2Disk2 := NewDisk("disk2", "cluster2", "disk2", start, end, NewWindow(&start, &end))
  390. cluster2Disk2.Cost = 10.0
  391. cluster2Disk2.Adjustment = 3.0
  392. cluster2Disk2.ByteHours = 10 * gb
  393. cluster2Node1Disk := NewDisk("node1", "cluster2", "node1", start, end, NewWindow(&start, &end))
  394. cluster2Node1Disk.Cost = 1.0
  395. cluster2Node1Disk.ByteHours = 5 * gb
  396. // Add Attached Disks
  397. cluster2Node2Disk := NewDisk("node2", "cluster2", "node2", start, end, NewWindow(&start, &end))
  398. cluster2Node2Disk.Cost = 2.0
  399. cluster2Node2Disk.ByteHours = 5 * gb
  400. cluster2Node3Disk := NewDisk("node3", "cluster2", "node3", start, end, NewWindow(&start, &end))
  401. cluster2Node3Disk.Cost = 3.0
  402. cluster2Node3Disk.ByteHours = 5 * gb
  403. // Add Cluster Management
  404. cluster1ClusterManagement := NewClusterManagement("", "cluster1", NewWindow(&start, &end))
  405. cluster1ClusterManagement.Cost = 2.0
  406. cluster2ClusterManagement := NewClusterManagement("", "cluster2", NewWindow(&start, &end))
  407. cluster2ClusterManagement.Cost = 2.0
  408. // Add Networks
  409. c1Network := NewNetwork("", "cluster1", "c1nodes", start, end, NewWindow(&start, &end))
  410. c1Network.Cost = 3.0
  411. node1Network := NewNetwork("node1", "cluster2", "node1", start, end, NewWindow(&start, &end))
  412. node1Network.Cost = 4.0
  413. node2Network := NewNetwork("node2", "cluster2", "node2", start, end, NewWindow(&start, &end))
  414. node2Network.Cost = 5.0
  415. node3Network := NewNetwork("node3", "cluster2", "node3", start, end, NewWindow(&start, &end))
  416. node3Network.Cost = 2.0
  417. // Add LoadBalancers
  418. cluster2LoadBalancer1 := NewLoadBalancer("namespace2/loadBalancer1", "cluster2", "lb1", start, end, NewWindow(&start, &end))
  419. cluster2LoadBalancer1.Cost = 10.0
  420. cluster2LoadBalancer2 := NewLoadBalancer("namespace2/loadBalancer2", "cluster2", "lb2", start, end, NewWindow(&start, &end))
  421. cluster2LoadBalancer2.Cost = 15.0
  422. assetSet1 := NewAssetSet(start, end, cluster1Nodes, cluster2Node1, cluster2Node2, cluster2Node3, cluster2Disk1,
  423. cluster2Disk2, cluster2Node1Disk, cluster2Node2Disk, cluster2Node3Disk, cluster1ClusterManagement,
  424. cluster2ClusterManagement, c1Network, node1Network, node2Network, node3Network, cluster2LoadBalancer1, cluster2LoadBalancer2)
  425. assetSets = append(assetSets, assetSet1)
  426. // NOTE: we're re-using GenerateMockAllocationSet so this has to line up with
  427. // the allocated node costs from that function. See table above.
  428. // | Hierarchy | Cost | CPU | RAM | GPU | Adjustment |
  429. // +-----------------------------------------+------+------+------+------+------------+
  430. // cluster1:
  431. // nodes 100.00 5.00 4.00 1.00 90.00
  432. // +-----------------------------------------+------+------+------+------+------------+
  433. // cluster1 subtotal (adjusted) 100.00 50.00 40.00 10.00 0.00
  434. // +-----------------------------------------+------+------+------+------+------------+
  435. // cluster1 allocated 48.00 6.00 16.00 6.00 0.00
  436. // +-----------------------------------------+------+------+------+------+------------+
  437. // cluster1 idle 72.00 44.00 24.00 4.00 0.00
  438. // +-----------------------------------------+------+------+------+------+------------+
  439. // cluster2:
  440. // node1 35.00 20.00 15.00 0.00 0.00
  441. // node2 35.00 20.00 15.00 0.00 0.00
  442. // node3 30.00 10.00 10.00 10.00 0.00
  443. // (disks should not matter for idle)
  444. // +-----------------------------------------+------+------+------+------+------------+
  445. // cluster2 subtotal 100.00 50.00 40.00 10.00 0.00
  446. // +-----------------------------------------+------+------+------+------+------------+
  447. // cluster2 allocated 28.00 6.00 6.00 6.00 0.00
  448. // +-----------------------------------------+------+------+------+------+------------+
  449. // cluster2 idle 82.00 44.00 34.00 4.00 0.00
  450. // +-----------------------------------------+------+------+------+------+------------+
  451. cluster1Nodes = NewNode("", "cluster1", "c1nodes", start, end, NewWindow(&start, &end))
  452. cluster1Nodes.CPUCost = 5.0
  453. cluster1Nodes.RAMCost = 4.0
  454. cluster1Nodes.GPUCost = 1.0
  455. cluster1Nodes.Adjustment = 90.00
  456. cluster1Nodes.CPUCoreHours = 8
  457. cluster1Nodes.RAMByteHours = 6
  458. cluster1Nodes.GPUHours = 24
  459. cluster2Node1 = NewNode("node1", "cluster2", "node1", start, end, NewWindow(&start, &end))
  460. cluster2Node1.CPUCost = 20.0
  461. cluster2Node1.RAMCost = 15.0
  462. cluster2Node1.GPUCost = 0.0
  463. cluster2Node1.CPUCoreHours = 4
  464. cluster2Node1.RAMByteHours = 3
  465. cluster2Node1.GPUHours = 0
  466. cluster2Node2 = NewNode("node2", "cluster2", "node2", start, end, NewWindow(&start, &end))
  467. cluster2Node2.CPUCost = 20.0
  468. cluster2Node2.RAMCost = 15.0
  469. cluster2Node2.GPUCost = 0.0
  470. cluster2Node2.CPUCoreHours = 3
  471. cluster2Node2.RAMByteHours = 2
  472. cluster2Node2.GPUHours = 0
  473. cluster2Node3 = NewNode("node3", "cluster2", "node3", start, end, NewWindow(&start, &end))
  474. cluster2Node3.CPUCost = 10.0
  475. cluster2Node3.RAMCost = 10.0
  476. cluster2Node3.GPUCost = 10.0
  477. cluster2Node3.CPUCoreHours = 2
  478. cluster2Node3.RAMByteHours = 2
  479. cluster2Node3.GPUHours = 24
  480. // Add PVs
  481. cluster2Disk1 = NewDisk("disk1", "cluster2", "disk1", start, end, NewWindow(&start, &end))
  482. cluster2Disk1.Cost = 5.0
  483. cluster2Disk1.Adjustment = 1.0
  484. cluster2Disk1.ByteHours = 5 * gb
  485. cluster2Disk2 = NewDisk("disk2", "cluster2", "disk2", start, end, NewWindow(&start, &end))
  486. cluster2Disk2.Cost = 12.0
  487. cluster2Disk2.Adjustment = 4.0
  488. cluster2Disk2.ByteHours = 20 * gb
  489. assetSet2 := NewAssetSet(start, end, cluster1Nodes, cluster2Node1, cluster2Node2, cluster2Node3, cluster2Disk1,
  490. cluster2Disk2, cluster2Node1Disk, cluster2Node2Disk, cluster2Node3Disk, cluster1ClusterManagement,
  491. cluster2ClusterManagement, c1Network, node1Network, node2Network, node3Network, cluster2LoadBalancer1, cluster2LoadBalancer2)
  492. assetSets = append(assetSets, assetSet2)
  493. return assetSets
  494. }
  495. // GenerateMockAssetSet generates the following topology:
  496. //
  497. // | Asset | Cost | Adj |
  498. // +------------------------------+------+------+
  499. //
  500. // cluster1:
  501. // node1: 6.00 1.00
  502. // node2: 4.00 1.50
  503. // node3: 7.00 -0.50
  504. // disk1: 2.50 0.00
  505. // disk2: 1.50 0.00
  506. // clusterManagement1: 3.00 0.00
  507. //
  508. // +------------------------------+------+------+
  509. //
  510. // cluster1 subtotal 24.00 2.00
  511. //
  512. // +------------------------------+------+------+
  513. //
  514. // cluster2:
  515. // node4: 12.00 -1.00
  516. // disk3: 2.50 0.00
  517. // disk4: 1.50 0.00
  518. // clusterManagement2: 0.00 0.00
  519. //
  520. // +------------------------------+------+------+
  521. //
  522. // cluster2 subtotal 16.00 -1.00
  523. //
  524. // +------------------------------+------+------+
  525. //
  526. // cluster3:
  527. // node5: 17.00 2.00
  528. //
  529. // +------------------------------+------+------+
  530. //
  531. // cluster3 subtotal 17.00 2.00
  532. //
  533. // +------------------------------+------+------+
  534. //
  535. // total 57.00 3.00
  536. //
  537. // +------------------------------+------+------+
  538. func GenerateMockAssetSet(start time.Time, duration time.Duration) *AssetSet {
  539. end := start.Add(duration)
  540. window := NewWindow(&start, &end)
  541. hours := window.Duration().Hours()
  542. node1 := NewNode("node1", "cluster1", "gcp-node1", *window.Clone().start, *window.Clone().end, window.Clone())
  543. node1.CPUCost = 4.0
  544. node1.RAMCost = 4.0
  545. node1.GPUCost = 2.0
  546. node1.Discount = 0.5
  547. node1.CPUCoreHours = 2.0 * hours
  548. node1.RAMByteHours = 4.0 * gb * hours
  549. node1.GPUHours = 1.0 * hours
  550. node1.SetAdjustment(1.0)
  551. node1.SetLabels(map[string]string{"test": "test"})
  552. node2 := NewNode("node2", "cluster1", "gcp-node2", *window.Clone().start, *window.Clone().end, window.Clone())
  553. node2.CPUCost = 4.0
  554. node2.RAMCost = 4.0
  555. node2.GPUCost = 0.0
  556. node2.Discount = 0.5
  557. node2.CPUCoreHours = 2.0 * hours
  558. node2.RAMByteHours = 4.0 * gb * hours
  559. node2.GPUHours = 0.0 * hours
  560. node2.SetAdjustment(1.5)
  561. node3 := NewNode("node3", "cluster1", "gcp-node3", *window.Clone().start, *window.Clone().end, window.Clone())
  562. node3.CPUCost = 4.0
  563. node3.RAMCost = 4.0
  564. node3.GPUCost = 3.0
  565. node3.Discount = 0.5
  566. node3.CPUCoreHours = 2.0 * hours
  567. node3.RAMByteHours = 4.0 * gb * hours
  568. node3.GPUHours = 2.0 * hours
  569. node3.SetAdjustment(-0.5)
  570. node4 := NewNode("node4", "cluster2", "gcp-node4", *window.Clone().start, *window.Clone().end, window.Clone())
  571. node4.CPUCost = 10.0
  572. node4.RAMCost = 6.0
  573. node4.GPUCost = 0.0
  574. node4.Discount = 0.25
  575. node4.CPUCoreHours = 4.0 * hours
  576. node4.RAMByteHours = 12.0 * gb * hours
  577. node4.GPUHours = 0.0 * hours
  578. node4.SetAdjustment(-1.0)
  579. node5 := NewNode("node5", "cluster3", "aws-node5", *window.Clone().start, *window.Clone().end, window.Clone())
  580. node5.CPUCost = 10.0
  581. node5.RAMCost = 7.0
  582. node5.GPUCost = 0.0
  583. node5.Discount = 0.0
  584. node5.CPUCoreHours = 8.0 * hours
  585. node5.RAMByteHours = 24.0 * gb * hours
  586. node5.GPUHours = 0.0 * hours
  587. node5.SetAdjustment(2.0)
  588. disk1 := NewDisk("disk1", "cluster1", "gcp-disk1", *window.Clone().start, *window.Clone().end, window.Clone())
  589. disk1.Cost = 2.5
  590. disk1.ByteHours = 100 * gb * hours
  591. disk2 := NewDisk("disk2", "cluster1", "gcp-disk2", *window.Clone().start, *window.Clone().end, window.Clone())
  592. disk2.Cost = 1.5
  593. disk2.ByteHours = 60 * gb * hours
  594. disk3 := NewDisk("disk3", "cluster2", "gcp-disk3", *window.Clone().start, *window.Clone().end, window.Clone())
  595. disk3.Cost = 2.5
  596. disk3.ByteHours = 100 * gb * hours
  597. disk4 := NewDisk("disk4", "cluster2", "gcp-disk4", *window.Clone().start, *window.Clone().end, window.Clone())
  598. disk4.Cost = 1.5
  599. disk4.ByteHours = 100 * gb * hours
  600. cm1 := NewClusterManagement(GCPProvider, "cluster1", window.Clone())
  601. cm1.Cost = 3.0
  602. cm2 := NewClusterManagement(GCPProvider, "cluster2", window.Clone())
  603. cm2.Cost = 0.0
  604. return NewAssetSet(
  605. start, end,
  606. // cluster 1
  607. node1, node2, node3, disk1, disk2, cm1,
  608. // cluster 2
  609. node4, disk3, disk4, cm2,
  610. // cluster 3
  611. node5,
  612. )
  613. }
  614. func GenerateKubecostNodeAndPID(mockProviderIDInt int, provider string, mockClusterID int, setEndTime time.Time) (*Node, string) {
  615. providerID := "PID" + strconv.FormatInt(int64(mockProviderIDInt), 10)
  616. return &Node{
  617. Properties: &AssetProperties{
  618. Provider: provider,
  619. ProviderID: providerID,
  620. Cluster: "cluster" + strconv.FormatInt(int64(mockClusterID), 10),
  621. },
  622. End: setEndTime,
  623. }, providerID
  624. }
  625. func GenerateAWSMockCCIAndPID(mockProviderIDInt int, mockCloudIDInt int, labelKey string, resourceCategory string) (*CloudCostItem, string) {
  626. return &CloudCostItem{
  627. Properties: CloudCostItemProperties{
  628. ProviderID: "PID" + strconv.FormatInt(int64(mockProviderIDInt), 10),
  629. Provider: AWSProvider,
  630. Category: resourceCategory,
  631. Labels: map[string]string{
  632. labelKey: "cluster" + strconv.FormatInt(int64(mockCloudIDInt), 10),
  633. },
  634. },
  635. }, "cluster" + strconv.FormatInt(int64(mockCloudIDInt), 10)
  636. }
  637. func GenerateAlibabaMockCCIAndPID(mockProviderIDInt int, mockCloudIDInt int, labelKey string, resourceCategory string) (*CloudCostItem, string) {
  638. return &CloudCostItem{
  639. Properties: CloudCostItemProperties{
  640. ProviderID: "PID" + strconv.FormatInt(int64(mockProviderIDInt), 10),
  641. Provider: AlibabaProvider,
  642. Category: resourceCategory,
  643. Labels: map[string]string{
  644. labelKey: "cluster" + strconv.FormatInt(int64(mockCloudIDInt), 10),
  645. },
  646. },
  647. }, "cluster" + strconv.FormatInt(int64(mockCloudIDInt), 10)
  648. }
  649. func GenerateGCPMockCCIAndPID(mockProviderIDInt int, mockCloudIDInt int, labelKey string, resourceCategory string) (*CloudCostItem, string) {
  650. return &CloudCostItem{
  651. Properties: CloudCostItemProperties{
  652. ProviderID: "PID" + strconv.FormatInt(int64(mockProviderIDInt), 10),
  653. Provider: GCPProvider,
  654. Category: resourceCategory,
  655. },
  656. }, ""
  657. }
  658. // NewMockUnitSummaryAllocation creates an *SummaryAllocation with all of its float64 values set to 1 and generic properties if not provided in arg
  659. func NewMockUnitSummaryAllocation(name string, start time.Time, resolution time.Duration, props *AllocationProperties) *SummaryAllocation {
  660. if name == "" {
  661. name = "cluster1/namespace1/pod1/container1"
  662. }
  663. properties := &AllocationProperties{}
  664. if props == nil {
  665. properties.Cluster = "cluster1"
  666. properties.Node = "node1"
  667. properties.Namespace = "namespace1"
  668. properties.ControllerKind = "deployment"
  669. properties.Controller = "deployment1"
  670. properties.Pod = "pod1"
  671. properties.Container = "container1"
  672. } else {
  673. properties = props
  674. }
  675. end := start.Add(resolution)
  676. alloc := &SummaryAllocation{
  677. Name: name,
  678. Properties: properties,
  679. Start: start,
  680. End: end,
  681. CPUCost: 1,
  682. CPUCoreRequestAverage: 1,
  683. CPUCoreUsageAverage: 1,
  684. GPUCost: 1,
  685. NetworkCost: 1,
  686. LoadBalancerCost: 1,
  687. RAMCost: 1,
  688. RAMBytesRequestAverage: 1,
  689. RAMBytesUsageAverage: 1,
  690. }
  691. // If idle allocation, remove non-idle costs, but maintain total cost
  692. if alloc.IsIdle() {
  693. alloc.NetworkCost = 0.0
  694. alloc.LoadBalancerCost = 0.0
  695. alloc.CPUCost += 1.0
  696. alloc.RAMCost += 1.0
  697. }
  698. return alloc
  699. }
  700. // NewMockUnitSummaryAllocationSet creates an *SummaryAllocationSet
  701. func NewMockUnitSummaryAllocationSet(start time.Time, resolution time.Duration) *SummaryAllocationSet {
  702. end := start.Add(resolution)
  703. sas := &SummaryAllocationSet{
  704. Window: NewWindow(&start, &end),
  705. }
  706. return sas
  707. }