merge.go 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627
  1. package kubemodel
  2. import (
  3. "fmt"
  4. "maps"
  5. "math"
  6. "slices"
  7. )
  8. func Merge(kms1, kms2 *KubeModelSet) (*KubeModelSet, error) {
  9. if kms1 == nil && kms2 == nil {
  10. return nil, fmt.Errorf("both KubeModelSets are nil")
  11. }
  12. if kms1 == nil {
  13. return kms2, nil
  14. }
  15. if kms2 == nil {
  16. return kms1, nil
  17. }
  18. if kms1.Cluster != nil && kms2.Cluster != nil && kms1.Cluster.UID != kms2.Cluster.UID {
  19. return nil, fmt.Errorf(
  20. "cannot merge KubeModelSets from different clusters: %s vs %s",
  21. kms1.Cluster.UID, kms2.Cluster.UID)
  22. }
  23. windowStart := kms1.Window.Start
  24. if kms2.Window.Start.Before(windowStart) {
  25. windowStart = kms2.Window.Start
  26. }
  27. windowEnd := kms1.Window.End
  28. if kms2.Window.End.After(windowEnd) {
  29. windowEnd = kms2.Window.End
  30. }
  31. merged := NewKubeModelSet(windowStart, windowEnd)
  32. if kms1.Metadata != nil && kms2.Metadata != nil {
  33. if kms2.Metadata.CreatedAt.Before(kms1.Metadata.CreatedAt) {
  34. merged.Metadata.CreatedAt = kms2.Metadata.CreatedAt
  35. } else {
  36. merged.Metadata.CreatedAt = kms1.Metadata.CreatedAt
  37. }
  38. if kms2.Metadata.CompletedAt.After(kms1.Metadata.CompletedAt) {
  39. merged.Metadata.CompletedAt = kms2.Metadata.CompletedAt
  40. } else {
  41. merged.Metadata.CompletedAt = kms1.Metadata.CompletedAt
  42. }
  43. merged.Metadata.ObjectCount = kms1.Metadata.ObjectCount + kms2.Metadata.ObjectCount
  44. merged.Metadata.Diagnostics = append(
  45. append([]Diagnostic{}, kms1.Metadata.Diagnostics...),
  46. kms2.Metadata.Diagnostics...,
  47. )
  48. } else if kms1.Metadata != nil {
  49. merged.Metadata.CreatedAt = kms1.Metadata.CreatedAt
  50. merged.Metadata.CompletedAt = kms1.Metadata.CompletedAt
  51. merged.Metadata.ObjectCount = kms1.Metadata.ObjectCount
  52. merged.Metadata.Diagnostics = append([]Diagnostic{}, kms1.Metadata.Diagnostics...)
  53. } else if kms2.Metadata != nil {
  54. merged.Metadata.CreatedAt = kms2.Metadata.CreatedAt
  55. merged.Metadata.CompletedAt = kms2.Metadata.CompletedAt
  56. merged.Metadata.ObjectCount = kms2.Metadata.ObjectCount
  57. merged.Metadata.Diagnostics = append([]Diagnostic{}, kms2.Metadata.Diagnostics...)
  58. }
  59. merged.Cluster = kms1.Cluster
  60. if merged.Cluster == nil {
  61. merged.Cluster = kms2.Cluster
  62. }
  63. mergeNamespaces(merged, kms1, kms2)
  64. mergeResourceQuotas(merged, kms1, kms2)
  65. mergeNodes(merged, kms1, kms2)
  66. mergePods(merged, kms1, kms2)
  67. mergeContainers(merged, kms1, kms2)
  68. mergeOwners(merged, kms1, kms2)
  69. mergeServices(merged, kms1, kms2)
  70. mergeVolumes(merged, kms1, kms2)
  71. mergePVCs(merged, kms1, kms2)
  72. mergeDevices(merged, kms1, kms2)
  73. mergeDeviceUsages(merged, kms1, kms2)
  74. return merged, nil
  75. }
  76. func mergeNamespaces(merged, kms1, kms2 *KubeModelSet) {
  77. for uid, ns := range kms1.Namespaces {
  78. merged.Namespaces[uid] = copyNamespace(ns)
  79. merged.idx.namespaceNameToID[ns.Name] = ns.UID
  80. merged.Metadata.ObjectCount++
  81. }
  82. for uid, ns2 := range kms2.Namespaces {
  83. if ns1, exists := merged.Namespaces[uid]; exists {
  84. // Merge Start/End timestamps for existing namespace
  85. if ns2.Start.Before(ns1.Start) {
  86. ns1.Start = ns2.Start
  87. }
  88. if ns2.End.After(ns1.End) {
  89. ns1.End = ns2.End
  90. }
  91. } else {
  92. merged.Namespaces[uid] = copyNamespace(ns2)
  93. merged.idx.namespaceNameToID[ns2.Name] = ns2.UID
  94. merged.Metadata.ObjectCount++
  95. }
  96. }
  97. }
  98. func mergeResourceQuotas(merged, kms1, kms2 *KubeModelSet) {
  99. for uid, rq := range kms1.ResourceQuotas {
  100. merged.ResourceQuotas[uid] = copyResourceQuota(rq)
  101. merged.Metadata.ObjectCount++
  102. }
  103. for uid, rq2 := range kms2.ResourceQuotas {
  104. if rq1, exists := merged.ResourceQuotas[uid]; exists {
  105. // Merge Start/End timestamps for existing resource quota
  106. if rq2.Start.Before(rq1.Start) {
  107. rq1.Start = rq2.Start
  108. }
  109. if rq2.End.After(rq1.End) {
  110. rq1.End = rq2.End
  111. }
  112. } else {
  113. merged.ResourceQuotas[uid] = copyResourceQuota(rq2)
  114. merged.Metadata.ObjectCount++
  115. }
  116. }
  117. }
  118. func mergeNodes(merged, kms1, kms2 *KubeModelSet) {
  119. for uid, node := range kms1.Nodes {
  120. merged.Nodes[uid] = copyNode(node)
  121. merged.Metadata.ObjectCount++
  122. }
  123. for uid, node2 := range kms2.Nodes {
  124. if node1, exists := merged.Nodes[uid]; exists {
  125. node1.CpuMillicoreSeconds += node2.CpuMillicoreSeconds
  126. node1.RAMByteSeconds += node2.RAMByteSeconds
  127. node1.CpuMillicoreUsageMax = max(node1.CpuMillicoreUsageMax, node2.CpuMillicoreUsageMax)
  128. node1.RAMByteUsageMax = max(node1.RAMByteUsageMax, node2.RAMByteUsageMax)
  129. node1.DurationSeconds += node2.DurationSeconds
  130. if node2.Start.Before(node1.Start) {
  131. node1.Start = node2.Start
  132. }
  133. if node2.End.After(node1.End) {
  134. node1.End = node2.End
  135. }
  136. for volumeUID, volume2 := range node2.AttachedVolumes {
  137. if volume1, exists := node1.AttachedVolumes[volumeUID]; exists {
  138. volume1.UsageByteSeconds += volume2.UsageByteSeconds
  139. volume1.DurationSeconds += volume2.DurationSeconds
  140. if volume2.CapacityBytes > volume1.CapacityBytes {
  141. volume1.CapacityBytes = volume2.CapacityBytes
  142. }
  143. } else {
  144. node1.AttachedVolumes[volumeUID] = &NodeVolumeUsage{
  145. VolumeUID: volume2.VolumeUID,
  146. CapacityBytes: volume2.CapacityBytes,
  147. UsageByteSeconds: volume2.UsageByteSeconds,
  148. VolumeType: volume2.VolumeType,
  149. ProviderID: volume2.ProviderID,
  150. DurationSeconds: volume2.DurationSeconds,
  151. }
  152. }
  153. }
  154. } else {
  155. merged.Nodes[uid] = copyNode(node2)
  156. merged.Metadata.ObjectCount++
  157. }
  158. }
  159. }
  160. func mergePods(merged, kms1, kms2 *KubeModelSet) {
  161. for uid, pod := range kms1.Pods {
  162. merged.Pods[uid] = copyPod(pod)
  163. merged.Metadata.ObjectCount++
  164. }
  165. for uid, pod2 := range kms2.Pods {
  166. if pod1, exists := merged.Pods[uid]; exists {
  167. pod1.NetworkReceiveBytes += pod2.NetworkReceiveBytes
  168. pod1.NetworkTransferBytes += pod2.NetworkTransferBytes
  169. pod1.DurationSeconds += pod2.DurationSeconds
  170. if pod2.Start.Before(pod1.Start) {
  171. pod1.Start = pod2.Start
  172. }
  173. if pod2.End.After(pod1.End) {
  174. pod1.End = pod2.End
  175. }
  176. } else {
  177. merged.Pods[uid] = copyPod(pod2)
  178. merged.Metadata.ObjectCount++
  179. }
  180. }
  181. }
  182. func mergeContainers(merged, kms1, kms2 *KubeModelSet) {
  183. for uid, container := range kms1.Containers {
  184. merged.Containers[uid] = copyContainer(container)
  185. merged.Metadata.ObjectCount++
  186. }
  187. for uid, container2 := range kms2.Containers {
  188. if container1, exists := merged.Containers[uid]; exists {
  189. container1.CpuMillicoreSeconds += container2.CpuMillicoreSeconds
  190. container1.RAMByteSeconds += container2.RAMByteSeconds
  191. container1.CpuMillicoreUsageMax = max(container1.CpuMillicoreUsageMax, container2.CpuMillicoreUsageMax)
  192. container1.RAMByteUsageMax = max(container1.RAMByteUsageMax, container2.RAMByteUsageMax)
  193. for volumeUID, ByteSeconds := range container2.VolumeStorageByteSeconds {
  194. container1.VolumeStorageByteSeconds[volumeUID] += ByteSeconds
  195. }
  196. for volumeUID, usageMax := range container2.VolumeStorageByteUsageMax {
  197. if currentMax, exists := container1.VolumeStorageByteUsageMax[volumeUID]; exists {
  198. container1.VolumeStorageByteUsageMax[volumeUID] = max(currentMax, usageMax)
  199. } else {
  200. container1.VolumeStorageByteUsageMax[volumeUID] = usageMax
  201. }
  202. }
  203. container1.CpuMillicoreRequestSeconds += container2.CpuMillicoreRequestSeconds
  204. container1.RAMByteSecondRequest += container2.RAMByteSecondRequest
  205. container1.CpuMillicoreLimitSeconds += container2.CpuMillicoreLimitSeconds
  206. container1.RAMByteSecondsLimit += container2.RAMByteSecondsLimit
  207. container1.DurationSeconds += container2.DurationSeconds
  208. // Merge Start/End timestamps
  209. if container2.Start.Before(container1.Start) {
  210. container1.Start = container2.Start
  211. }
  212. if container2.End.After(container1.End) {
  213. container1.End = container2.End
  214. }
  215. } else {
  216. merged.Containers[uid] = copyContainer(container2)
  217. merged.Metadata.ObjectCount++
  218. }
  219. }
  220. }
  221. func mergeOwners(merged, kms1, kms2 *KubeModelSet) {
  222. for uid, owner := range kms1.Owners {
  223. merged.Owners[uid] = copyOwner(owner)
  224. merged.Metadata.ObjectCount++
  225. }
  226. for uid, owner2 := range kms2.Owners {
  227. if owner1, exists := merged.Owners[uid]; exists {
  228. if owner2.Start.Before(owner1.Start) {
  229. owner1.Start = owner2.Start
  230. }
  231. if owner2.End.After(owner1.End) {
  232. owner1.End = owner2.End
  233. }
  234. } else {
  235. merged.Owners[uid] = copyOwner(owner2)
  236. merged.Metadata.ObjectCount++
  237. }
  238. }
  239. }
  240. func mergeServices(merged, kms1, kms2 *KubeModelSet) {
  241. for uid, svc := range kms1.Services {
  242. merged.Services[uid] = copyService(svc)
  243. merged.Metadata.ObjectCount++
  244. }
  245. for uid, svc2 := range kms2.Services {
  246. if svc1, exists := merged.Services[uid]; exists {
  247. svc1.NetworkTransferBytes += svc2.NetworkTransferBytes
  248. svc1.NetworkReceiveBytes += svc2.NetworkReceiveBytes
  249. svc1.DurationSeconds += svc2.DurationSeconds
  250. if svc2.Start.Before(svc1.Start) {
  251. svc1.Start = svc2.Start
  252. }
  253. if svc2.End.After(svc1.End) {
  254. svc1.End = svc2.End
  255. }
  256. } else {
  257. merged.Services[uid] = copyService(svc2)
  258. merged.Metadata.ObjectCount++
  259. }
  260. }
  261. }
  262. func mergeVolumes(merged, kms1, kms2 *KubeModelSet) {
  263. for uid, vol := range kms1.Volumes {
  264. merged.Volumes[uid] = copyVolume(vol)
  265. merged.Metadata.ObjectCount++
  266. }
  267. for uid, vol2 := range kms2.Volumes {
  268. if vol1, exists := merged.Volumes[uid]; exists {
  269. if vol2.Start.Before(vol1.Start) {
  270. vol1.Start = vol2.Start
  271. }
  272. if vol2.End.After(vol1.End) {
  273. vol1.End = vol2.End
  274. }
  275. vol1.DurationSeconds += vol2.DurationSeconds
  276. } else {
  277. merged.Volumes[uid] = copyVolume(vol2)
  278. merged.Metadata.ObjectCount++
  279. }
  280. }
  281. }
  282. func mergePVCs(merged, kms1, kms2 *KubeModelSet) {
  283. for uid, pvc := range kms1.PersistentVolumeClaims {
  284. merged.PersistentVolumeClaims[uid] = copyPVC(pvc)
  285. merged.Metadata.ObjectCount++
  286. }
  287. for uid, pvc2 := range kms2.PersistentVolumeClaims {
  288. if pvc1, exists := merged.PersistentVolumeClaims[uid]; exists {
  289. pvc1.StorageByteSeconds += pvc2.StorageByteSeconds
  290. pvc1.ActualUsedByteSeconds += pvc2.ActualUsedByteSeconds
  291. pvc1.DurationSeconds += pvc2.DurationSeconds
  292. if pvc2.Start.Before(pvc1.Start) {
  293. pvc1.Start = pvc2.Start
  294. }
  295. if pvc2.End.After(pvc1.End) {
  296. pvc1.End = pvc2.End
  297. }
  298. if pvc2.BoundAt.After(pvc1.BoundAt) {
  299. pvc1.BoundAt = pvc2.BoundAt
  300. }
  301. } else {
  302. merged.PersistentVolumeClaims[uid] = copyPVC(pvc2)
  303. merged.Metadata.ObjectCount++
  304. }
  305. }
  306. }
  307. func mergeDevices(merged, kms1, kms2 *KubeModelSet) {
  308. for uid, dev := range kms1.Devices {
  309. merged.Devices[uid] = copyDevice(dev)
  310. merged.Metadata.ObjectCount++
  311. }
  312. for uid, dev2 := range kms2.Devices {
  313. if dev1, exists := merged.Devices[uid]; exists {
  314. dev1.UsageSeconds += dev2.UsageSeconds
  315. dev1.MemoryByteSeconds += dev2.MemoryByteSeconds
  316. dev1.PowerWattSeconds += dev2.PowerWattSeconds
  317. dev1.PowerWattMax = math.Max(dev1.PowerWattMax, dev2.PowerWattMax)
  318. dev1.DurationSeconds += dev2.DurationSeconds
  319. if dev2.Start.Before(dev1.Start) {
  320. dev1.Start = dev2.Start
  321. }
  322. if dev2.End.After(dev1.End) {
  323. dev1.End = dev2.End
  324. }
  325. } else {
  326. merged.Devices[uid] = copyDevice(dev2)
  327. merged.Metadata.ObjectCount++
  328. }
  329. }
  330. }
  331. func mergeDeviceUsages(merged, kms1, kms2 *KubeModelSet) {
  332. for uid, usage := range kms1.DeviceUsages {
  333. merged.DeviceUsages[uid] = copyDeviceUsage(usage)
  334. merged.Metadata.ObjectCount++
  335. }
  336. for uid, usage2 := range kms2.DeviceUsages {
  337. if usage1, exists := merged.DeviceUsages[uid]; exists {
  338. usage1.UsageSeconds += usage2.UsageSeconds
  339. usage1.MemoryByteSecondsUsed += usage2.MemoryByteSecondsUsed
  340. usage1.UsagePercentageMax = math.Max(usage1.UsagePercentageMax, usage2.UsagePercentageMax)
  341. usage1.DurationSeconds += usage2.DurationSeconds
  342. // Merge Start/End timestamps
  343. if usage2.Start.Before(usage1.Start) {
  344. usage1.Start = usage2.Start
  345. }
  346. if usage2.End.After(usage1.End) {
  347. usage1.End = usage2.End
  348. }
  349. } else {
  350. merged.DeviceUsages[uid] = copyDeviceUsage(usage2)
  351. merged.Metadata.ObjectCount++
  352. }
  353. }
  354. }
  355. func copyNamespace(ns *Namespace) *Namespace {
  356. return &Namespace{
  357. ClusterUID: ns.ClusterUID,
  358. UID: ns.UID,
  359. Name: ns.Name,
  360. Labels: maps.Clone(ns.Labels),
  361. Annotations: maps.Clone(ns.Annotations),
  362. Start: ns.Start,
  363. End: ns.End,
  364. }
  365. }
  366. func copyResourceQuota(rq *ResourceQuota) *ResourceQuota {
  367. copied := &ResourceQuota{
  368. UID: rq.UID,
  369. Name: rq.Name,
  370. NamespaceUID: rq.NamespaceUID,
  371. Start: rq.Start,
  372. End: rq.End,
  373. }
  374. if rq.Spec != nil {
  375. copied.Spec = &ResourceQuotaSpec{}
  376. if rq.Spec.Hard != nil {
  377. copied.Spec.Hard = &ResourceQuotaSpecHard{
  378. Requests: copyResourceQuantities(rq.Spec.Hard.Requests),
  379. Limits: copyResourceQuantities(rq.Spec.Hard.Limits),
  380. }
  381. }
  382. }
  383. if rq.Status != nil {
  384. copied.Status = &ResourceQuotaStatus{}
  385. if rq.Status.Used != nil {
  386. copied.Status.Used = &ResourceQuotaStatusUsed{
  387. Requests: copyResourceQuantities(rq.Status.Used.Requests),
  388. Limits: copyResourceQuantities(rq.Status.Used.Limits),
  389. }
  390. }
  391. }
  392. return copied
  393. }
  394. func copyResourceQuantities(rq ResourceQuantities) ResourceQuantities {
  395. if rq == nil {
  396. return nil
  397. }
  398. copied := make(ResourceQuantities, len(rq))
  399. for k, v := range rq {
  400. copied[k] = v
  401. }
  402. return copied
  403. }
  404. func copyNode(node *Node) *Node {
  405. copied := &Node{
  406. UID: node.UID,
  407. Name: node.Name,
  408. ProviderResourceUID: node.ProviderResourceUID,
  409. Labels: maps.Clone(node.Labels),
  410. Annotations: maps.Clone(node.Annotations),
  411. CpuMillicoreSeconds: node.CpuMillicoreSeconds,
  412. RAMByteSeconds: node.RAMByteSeconds,
  413. CpuMillicoreUsageMax: node.CpuMillicoreUsageMax,
  414. RAMByteUsageMax: node.RAMByteUsageMax,
  415. DurationSeconds: node.DurationSeconds,
  416. AttachedVolumes: make(map[string]*NodeVolumeUsage),
  417. Start: node.Start,
  418. End: node.End,
  419. }
  420. for volumeUID, volume := range node.AttachedVolumes {
  421. copied.AttachedVolumes[volumeUID] = &NodeVolumeUsage{
  422. VolumeUID: volume.VolumeUID,
  423. CapacityBytes: volume.CapacityBytes,
  424. UsageByteSeconds: volume.UsageByteSeconds,
  425. VolumeType: volume.VolumeType,
  426. ProviderID: volume.ProviderID,
  427. DurationSeconds: volume.DurationSeconds,
  428. }
  429. }
  430. return copied
  431. }
  432. func copyPod(pod *Pod) *Pod {
  433. return &Pod{
  434. UID: pod.UID,
  435. Name: pod.Name,
  436. NamespaceUID: pod.NamespaceUID,
  437. OwnerUID: pod.OwnerUID,
  438. NodeUID: pod.NodeUID,
  439. Labels: maps.Clone(pod.Labels),
  440. Annotations: maps.Clone(pod.Annotations),
  441. NetworkReceiveBytes: pod.NetworkReceiveBytes,
  442. NetworkTransferBytes: pod.NetworkTransferBytes,
  443. DurationSeconds: pod.DurationSeconds,
  444. Start: pod.Start,
  445. End: pod.End,
  446. }
  447. }
  448. func copyContainer(container *Container) *Container {
  449. return &Container{
  450. PodUID: container.PodUID,
  451. Name: container.Name,
  452. CpuMillicoreSeconds: container.CpuMillicoreSeconds,
  453. RAMByteSeconds: container.RAMByteSeconds,
  454. CpuMillicoreUsageMax: container.CpuMillicoreUsageMax,
  455. RAMByteUsageMax: container.RAMByteUsageMax,
  456. VolumeStorageByteSeconds: maps.Clone(container.VolumeStorageByteSeconds),
  457. VolumeStorageByteUsageMax: maps.Clone(container.VolumeStorageByteUsageMax),
  458. DurationSeconds: container.DurationSeconds,
  459. CpuMillicoreRequestSeconds: container.CpuMillicoreRequestSeconds,
  460. RAMByteSecondRequest: container.RAMByteSecondRequest,
  461. CpuMillicoreLimitSeconds: container.CpuMillicoreLimitSeconds,
  462. RAMByteSecondsLimit: container.RAMByteSecondsLimit,
  463. Start: container.Start,
  464. End: container.End,
  465. }
  466. }
  467. func copyOwner(owner *Owner) *Owner {
  468. return &Owner{
  469. UID: owner.UID,
  470. Name: owner.Name,
  471. NamespaceUID: owner.NamespaceUID,
  472. Kind: owner.Kind,
  473. Labels: maps.Clone(owner.Labels),
  474. Annotations: maps.Clone(owner.Annotations),
  475. Start: owner.Start,
  476. End: owner.End,
  477. }
  478. }
  479. func copyService(svc *Service) *Service {
  480. return &Service{
  481. UID: svc.UID,
  482. NamespaceUID: svc.NamespaceUID,
  483. Name: svc.Name,
  484. Type: svc.Type,
  485. Hostname: svc.Hostname,
  486. Labels: maps.Clone(svc.Labels),
  487. Annotations: maps.Clone(svc.Annotations),
  488. NetworkTransferBytes: svc.NetworkTransferBytes,
  489. NetworkReceiveBytes: svc.NetworkReceiveBytes,
  490. DurationSeconds: svc.DurationSeconds,
  491. Selector: maps.Clone(svc.Selector),
  492. Ports: slices.Clone(svc.Ports),
  493. Start: svc.Start,
  494. End: svc.End,
  495. }
  496. }
  497. func copyVolume(vol *PersistentVolume) *PersistentVolume {
  498. return &PersistentVolume{
  499. UID: vol.UID,
  500. ClusterUID: vol.ClusterUID,
  501. Name: vol.Name,
  502. Namespace: vol.Namespace,
  503. Labels: maps.Clone(vol.Labels),
  504. Annotations: maps.Clone(vol.Annotations),
  505. StorageClass: vol.StorageClass,
  506. SizeBytes: vol.SizeBytes,
  507. Type: vol.Type,
  508. CSIDriver: vol.CSIDriver,
  509. ProviderVolumeID: vol.ProviderVolumeID,
  510. AccessModes: slices.Clone(vol.AccessModes),
  511. ReclaimPolicy: vol.ReclaimPolicy,
  512. Region: vol.Region,
  513. Zone: vol.Zone,
  514. Start: vol.Start,
  515. End: vol.End,
  516. DurationSeconds: vol.DurationSeconds,
  517. NodeAffinity: vol.NodeAffinity,
  518. ProvisionedIOPS: vol.ProvisionedIOPS,
  519. ProvisionedThroughput: vol.ProvisionedThroughput,
  520. PerformanceMode: vol.PerformanceMode,
  521. }
  522. }
  523. func copyPVC(pvc *PersistentVolumeClaim) *PersistentVolumeClaim {
  524. copied := &PersistentVolumeClaim{
  525. UID: pvc.UID,
  526. NamespaceUID: pvc.NamespaceUID,
  527. Name: pvc.Name,
  528. Labels: maps.Clone(pvc.Labels),
  529. Annotations: maps.Clone(pvc.Annotations),
  530. StorageClass: pvc.StorageClass,
  531. StorageByteSeconds: pvc.StorageByteSeconds,
  532. RequestedBytes: pvc.RequestedBytes,
  533. Size: pvc.Size,
  534. VolumeName: pvc.VolumeName,
  535. AccessModes: slices.Clone(pvc.AccessModes),
  536. Start: pvc.Start,
  537. End: pvc.End,
  538. BoundAt: pvc.BoundAt,
  539. DurationSeconds: pvc.DurationSeconds,
  540. ActualUsedByteSeconds: pvc.ActualUsedByteSeconds,
  541. }
  542. if pvc.VolumeUID != nil {
  543. volumeUID := *pvc.VolumeUID
  544. copied.VolumeUID = &volumeUID
  545. }
  546. if pvc.PodUID != nil {
  547. podUID := *pvc.PodUID
  548. copied.PodUID = &podUID
  549. }
  550. return copied
  551. }
  552. func copyDevice(dev *Device) *Device {
  553. return &Device{
  554. UID: dev.UID,
  555. Type: dev.Type,
  556. NodeUID: dev.NodeUID,
  557. DeviceNumber: dev.DeviceNumber,
  558. ModelName: dev.ModelName,
  559. IsShared: dev.IsShared,
  560. SharePercentage: dev.SharePercentage,
  561. UsageSeconds: dev.UsageSeconds,
  562. MemoryByteSeconds: dev.MemoryByteSeconds,
  563. PowerWattSeconds: dev.PowerWattSeconds,
  564. PowerWattMax: dev.PowerWattMax,
  565. DurationSeconds: dev.DurationSeconds,
  566. Start: dev.Start,
  567. End: dev.End,
  568. }
  569. }
  570. func copyDeviceUsage(usage *DeviceUsage) *DeviceUsage {
  571. return &DeviceUsage{
  572. ContainerUID: usage.ContainerUID,
  573. DeviceUID: usage.DeviceUID,
  574. UsageSeconds: usage.UsageSeconds,
  575. UsagePercentageMax: usage.UsagePercentageMax,
  576. MemoryByteSecondsUsed: usage.MemoryByteSecondsUsed,
  577. DeviceType: usage.DeviceType,
  578. DurationSeconds: usage.DurationSeconds,
  579. Start: usage.Start,
  580. End: usage.End,
  581. }
  582. }