mock.go 31 KB

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