clustercache_test.go 64 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356
  1. package scrape
  2. import (
  3. "reflect"
  4. "testing"
  5. "time"
  6. "github.com/opencost/opencost/core/pkg/clustercache"
  7. "github.com/opencost/opencost/core/pkg/source"
  8. "github.com/opencost/opencost/modules/collector-source/pkg/metric"
  9. "github.com/opencost/opencost/modules/collector-source/pkg/util"
  10. v1 "k8s.io/api/core/v1"
  11. "k8s.io/apimachinery/pkg/api/resource"
  12. metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
  13. "k8s.io/apimachinery/pkg/types"
  14. )
  15. var Start1Str = "2025-01-01T00:00:00Z00:00"
  16. func Test_kubernetesScraper_scrapeNodes(t *testing.T) {
  17. start1, _ := time.Parse(time.RFC3339, Start1Str)
  18. type scrape struct {
  19. Nodes []*clustercache.Node
  20. Timestamp time.Time
  21. }
  22. tests := []struct {
  23. name string
  24. scrapes []scrape
  25. expected []metric.Update
  26. }{
  27. {
  28. name: "simple",
  29. scrapes: []scrape{
  30. {
  31. Nodes: []*clustercache.Node{
  32. {
  33. Name: "node1",
  34. UID: "uuid1",
  35. SpecProviderID: "i-1",
  36. Status: v1.NodeStatus{
  37. Capacity: v1.ResourceList{
  38. v1.ResourceCPU: resource.MustParse("2"),
  39. v1.ResourceMemory: resource.MustParse("2048"),
  40. },
  41. Allocatable: v1.ResourceList{
  42. v1.ResourceCPU: resource.MustParse("1"),
  43. v1.ResourceMemory: resource.MustParse("1024"),
  44. },
  45. },
  46. Labels: map[string]string{
  47. "test1": "blah",
  48. "test2": "blah2",
  49. },
  50. },
  51. },
  52. Timestamp: start1,
  53. },
  54. },
  55. expected: []metric.Update{
  56. {
  57. Name: metric.NodeInfo,
  58. Labels: map[string]string{
  59. source.NodeLabel: "node1",
  60. source.ProviderIDLabel: "i-1",
  61. source.UIDLabel: "uuid1",
  62. },
  63. Value: 0,
  64. AdditionalInfo: map[string]string{
  65. source.NodeLabel: "node1",
  66. source.ProviderIDLabel: "i-1",
  67. source.UIDLabel: "uuid1",
  68. },
  69. },
  70. {
  71. Name: metric.NodeResourceCapacities,
  72. Labels: map[string]string{
  73. source.NodeLabel: "node1",
  74. source.ProviderIDLabel: "i-1",
  75. source.UIDLabel: "uuid1",
  76. source.ResourceLabel: "cpu",
  77. source.UnitLabel: "core",
  78. },
  79. Value: 2.0,
  80. AdditionalInfo: nil,
  81. },
  82. {
  83. Name: metric.NodeResourceCapacities,
  84. Labels: map[string]string{
  85. source.NodeLabel: "node1",
  86. source.ProviderIDLabel: "i-1",
  87. source.UIDLabel: "uuid1",
  88. source.ResourceLabel: "memory",
  89. source.UnitLabel: "byte",
  90. },
  91. Value: 2048.0,
  92. AdditionalInfo: nil,
  93. },
  94. {
  95. Name: metric.KubeNodeStatusCapacityCPUCores,
  96. Labels: map[string]string{
  97. source.NodeLabel: "node1",
  98. source.ProviderIDLabel: "i-1",
  99. source.UIDLabel: "uuid1",
  100. },
  101. Value: 2.0,
  102. AdditionalInfo: nil,
  103. },
  104. {
  105. Name: metric.KubeNodeStatusCapacityMemoryBytes,
  106. Labels: map[string]string{
  107. source.NodeLabel: "node1",
  108. source.ProviderIDLabel: "i-1",
  109. source.UIDLabel: "uuid1",
  110. },
  111. Value: 2048.0,
  112. AdditionalInfo: nil,
  113. },
  114. {
  115. Name: metric.NodeResourcesAllocatable,
  116. Labels: map[string]string{
  117. source.NodeLabel: "node1",
  118. source.ProviderIDLabel: "i-1",
  119. source.UIDLabel: "uuid1",
  120. source.ResourceLabel: "cpu",
  121. source.UnitLabel: "core",
  122. },
  123. Value: 1.0,
  124. AdditionalInfo: nil,
  125. },
  126. {
  127. Name: metric.NodeResourcesAllocatable,
  128. Labels: map[string]string{
  129. source.NodeLabel: "node1",
  130. source.ProviderIDLabel: "i-1",
  131. source.UIDLabel: "uuid1",
  132. source.ResourceLabel: "memory",
  133. source.UnitLabel: "byte",
  134. },
  135. Value: 1024.0,
  136. AdditionalInfo: nil,
  137. },
  138. {
  139. Name: metric.KubeNodeStatusAllocatableCPUCores,
  140. Labels: map[string]string{
  141. source.NodeLabel: "node1",
  142. source.ProviderIDLabel: "i-1",
  143. source.UIDLabel: "uuid1",
  144. },
  145. Value: 1.0,
  146. AdditionalInfo: nil,
  147. },
  148. {
  149. Name: metric.KubeNodeStatusAllocatableMemoryBytes,
  150. Labels: map[string]string{
  151. source.NodeLabel: "node1",
  152. source.ProviderIDLabel: "i-1",
  153. source.UIDLabel: "uuid1",
  154. },
  155. Value: 1024.0,
  156. AdditionalInfo: nil,
  157. },
  158. {
  159. Name: metric.KubeNodeLabels,
  160. Labels: map[string]string{
  161. source.NodeLabel: "node1",
  162. source.ProviderIDLabel: "i-1",
  163. source.UIDLabel: "uuid1",
  164. },
  165. Value: 0,
  166. AdditionalInfo: map[string]string{
  167. "label_test1": "blah",
  168. "label_test2": "blah2",
  169. },
  170. },
  171. },
  172. },
  173. }
  174. for _, tt := range tests {
  175. t.Run(tt.name, func(t *testing.T) {
  176. ks := &ClusterCacheScraper{}
  177. var scrapeResults []metric.Update
  178. for _, s := range tt.scrapes {
  179. res := ks.scrapeNodes(s.Nodes)
  180. scrapeResults = append(scrapeResults, res...)
  181. }
  182. if len(scrapeResults) != len(tt.expected) {
  183. t.Errorf("Expected result length of %d, got %d", len(tt.expected), len(scrapeResults))
  184. }
  185. for i, expected := range tt.expected {
  186. got := scrapeResults[i]
  187. if !reflect.DeepEqual(expected, got) {
  188. t.Errorf("Result did not match expected at index %d: got %v, want %v", i, got, expected)
  189. }
  190. }
  191. })
  192. }
  193. }
  194. func Test_kubernetesScraper_scrapeDeployments(t *testing.T) {
  195. start1, _ := time.Parse(time.RFC3339, Start1Str)
  196. type scrape struct {
  197. Deployments []*clustercache.Deployment
  198. Timestamp time.Time
  199. }
  200. tests := []struct {
  201. name string
  202. scrapes []scrape
  203. expected []metric.Update
  204. }{
  205. {
  206. name: "simple",
  207. scrapes: []scrape{
  208. {
  209. Deployments: []*clustercache.Deployment{
  210. {
  211. Name: "deployment1",
  212. Namespace: "namespace1",
  213. UID: "uuid1",
  214. MatchLabels: map[string]string{
  215. "test1": "blah",
  216. "test2": "blah2",
  217. },
  218. },
  219. },
  220. Timestamp: start1,
  221. },
  222. },
  223. // deploymentInfo map is shared across all 4 metrics and has namespace
  224. // added to it before DeploymentMatchLabels is appended, so all 4 metrics
  225. // reflect the final state: {uid, namespace_uid, deployment, namespace}.
  226. expected: []metric.Update{
  227. {
  228. Name: metric.DeploymentInfo,
  229. Labels: map[string]string{
  230. source.UIDLabel: "uuid1",
  231. source.NamespaceUIDLabel: "ns-uuid1",
  232. source.DeploymentLabel: "deployment1",
  233. source.NamespaceLabel: "namespace1",
  234. },
  235. Value: 0,
  236. AdditionalInfo: map[string]string{
  237. source.UIDLabel: "uuid1",
  238. source.NamespaceUIDLabel: "ns-uuid1",
  239. source.DeploymentLabel: "deployment1",
  240. source.NamespaceLabel: "namespace1",
  241. },
  242. },
  243. {
  244. Name: metric.DeploymentLabels,
  245. Labels: map[string]string{
  246. source.UIDLabel: "uuid1",
  247. source.NamespaceUIDLabel: "ns-uuid1",
  248. source.DeploymentLabel: "deployment1",
  249. source.NamespaceLabel: "namespace1",
  250. },
  251. Value: 0,
  252. AdditionalInfo: map[string]string{},
  253. },
  254. {
  255. Name: metric.DeploymentAnnotations,
  256. Labels: map[string]string{
  257. source.UIDLabel: "uuid1",
  258. source.NamespaceUIDLabel: "ns-uuid1",
  259. source.DeploymentLabel: "deployment1",
  260. source.NamespaceLabel: "namespace1",
  261. },
  262. Value: 0,
  263. AdditionalInfo: map[string]string{},
  264. },
  265. {
  266. Name: metric.DeploymentMatchLabels,
  267. Labels: map[string]string{
  268. source.UIDLabel: "uuid1",
  269. source.NamespaceUIDLabel: "ns-uuid1",
  270. source.DeploymentLabel: "deployment1",
  271. source.NamespaceLabel: "namespace1",
  272. },
  273. Value: 0,
  274. AdditionalInfo: map[string]string{
  275. "label_test1": "blah",
  276. "label_test2": "blah2",
  277. },
  278. },
  279. },
  280. },
  281. }
  282. for _, tt := range tests {
  283. t.Run(tt.name, func(t *testing.T) {
  284. ks := &ClusterCacheScraper{}
  285. nsIndex := make(map[string]types.UID, 0)
  286. nsIndex["namespace1"] = "ns-uuid1"
  287. var scrapeResults []metric.Update
  288. for _, s := range tt.scrapes {
  289. res := ks.scrapeDeployments(s.Deployments, nsIndex)
  290. scrapeResults = append(scrapeResults, res...)
  291. }
  292. if len(scrapeResults) != len(tt.expected) {
  293. t.Errorf("Expected result length of %d, got %d", len(tt.expected), len(scrapeResults))
  294. }
  295. for i, expected := range tt.expected {
  296. got := scrapeResults[i]
  297. if !reflect.DeepEqual(expected, got) {
  298. t.Errorf("Result did not match expected at index %d: got %v, want %v", i, got, expected)
  299. }
  300. }
  301. })
  302. }
  303. }
  304. func Test_kubernetesScraper_scrapeNamespaces(t *testing.T) {
  305. start1, _ := time.Parse(time.RFC3339, Start1Str)
  306. type scrape struct {
  307. Namespaces []*clustercache.Namespace
  308. Timestamp time.Time
  309. }
  310. tests := []struct {
  311. name string
  312. scrapes []scrape
  313. expected []metric.Update
  314. }{
  315. {
  316. name: "simple",
  317. scrapes: []scrape{
  318. {
  319. Namespaces: []*clustercache.Namespace{
  320. {
  321. Name: "namespace1",
  322. UID: "uuid1",
  323. Labels: map[string]string{
  324. "test1": "blah",
  325. "test2": "blah2",
  326. },
  327. Annotations: map[string]string{
  328. "test3": "blah3",
  329. "test4": "blah4",
  330. },
  331. },
  332. },
  333. Timestamp: start1,
  334. },
  335. },
  336. expected: []metric.Update{
  337. {
  338. Name: metric.NamespaceInfo,
  339. Labels: map[string]string{
  340. source.NamespaceLabel: "namespace1",
  341. source.UIDLabel: "uuid1",
  342. },
  343. Value: 0,
  344. AdditionalInfo: map[string]string{
  345. source.NamespaceLabel: "namespace1",
  346. source.UIDLabel: "uuid1",
  347. },
  348. },
  349. {
  350. Name: metric.KubeNamespaceLabels,
  351. Labels: map[string]string{
  352. source.NamespaceLabel: "namespace1",
  353. source.UIDLabel: "uuid1",
  354. },
  355. Value: 0,
  356. AdditionalInfo: map[string]string{
  357. "label_test1": "blah",
  358. "label_test2": "blah2",
  359. },
  360. },
  361. {
  362. Name: metric.KubeNamespaceAnnotations,
  363. Labels: map[string]string{
  364. source.NamespaceLabel: "namespace1",
  365. source.UIDLabel: "uuid1",
  366. },
  367. Value: 0,
  368. AdditionalInfo: map[string]string{
  369. "annotation_test3": "blah3",
  370. "annotation_test4": "blah4",
  371. },
  372. },
  373. },
  374. },
  375. }
  376. for _, tt := range tests {
  377. t.Run(tt.name, func(t *testing.T) {
  378. ks := &ClusterCacheScraper{}
  379. var scrapeResults []metric.Update
  380. for _, s := range tt.scrapes {
  381. res := ks.scrapeNamespaces(s.Namespaces)
  382. scrapeResults = append(scrapeResults, res...)
  383. }
  384. if len(scrapeResults) != len(tt.expected) {
  385. t.Errorf("Expected result length of %d, got %d", len(tt.expected), len(scrapeResults))
  386. }
  387. for i, expected := range tt.expected {
  388. got := scrapeResults[i]
  389. if !reflect.DeepEqual(expected, got) {
  390. t.Errorf("Result did not match expected at index %d: got %v, want %v", i, got, expected)
  391. }
  392. }
  393. })
  394. }
  395. }
  396. func Test_kubernetesScraper_scrapePods(t *testing.T) {
  397. start1, _ := time.Parse(time.RFC3339, Start1Str)
  398. type scrape struct {
  399. PVCs []*clustercache.PersistentVolumeClaim
  400. Pods []*clustercache.Pod
  401. Timestamp time.Time
  402. }
  403. tests := []struct {
  404. name string
  405. nsSetup func(map[string]types.UID)
  406. scrapes []scrape
  407. expected []metric.Update
  408. }{
  409. {
  410. name: "simple",
  411. scrapes: []scrape{
  412. {
  413. PVCs: []*clustercache.PersistentVolumeClaim{
  414. {
  415. Name: "pvc1",
  416. Namespace: "namespace1",
  417. UID: "uuid1",
  418. Spec: v1.PersistentVolumeClaimSpec{
  419. VolumeName: "vol1",
  420. StorageClassName: util.Ptr("storageClass1"),
  421. Resources: v1.VolumeResourceRequirements{
  422. Requests: v1.ResourceList{
  423. v1.ResourceStorage: resource.MustParse("4096"),
  424. },
  425. },
  426. },
  427. },
  428. },
  429. Pods: []*clustercache.Pod{
  430. {
  431. Name: "pod1",
  432. Namespace: "namespace1",
  433. UID: "uuid1",
  434. Spec: clustercache.PodSpec{
  435. NodeName: "node1",
  436. Containers: []clustercache.Container{
  437. {
  438. Name: "container1",
  439. Resources: v1.ResourceRequirements{
  440. Requests: map[v1.ResourceName]resource.Quantity{
  441. v1.ResourceCPU: resource.MustParse("500m"),
  442. v1.ResourceMemory: resource.MustParse("512"),
  443. },
  444. Limits: map[v1.ResourceName]resource.Quantity{
  445. v1.ResourceCPU: resource.MustParse("1"),
  446. v1.ResourceMemory: resource.MustParse("1024"),
  447. },
  448. },
  449. },
  450. },
  451. },
  452. Labels: map[string]string{
  453. "test1": "blah",
  454. "test2": "blah2",
  455. },
  456. Annotations: map[string]string{
  457. "test3": "blah3",
  458. "test4": "blah4",
  459. },
  460. OwnerReferences: []metav1.OwnerReference{
  461. {
  462. Kind: source.DeploymentLabel,
  463. Name: "deployment1",
  464. Controller: nil,
  465. },
  466. },
  467. Status: clustercache.PodStatus{
  468. ContainerStatuses: []v1.ContainerStatus{
  469. {
  470. Name: "container1",
  471. State: v1.ContainerState{
  472. Running: &v1.ContainerStateRunning{},
  473. },
  474. },
  475. },
  476. },
  477. },
  478. },
  479. Timestamp: start1,
  480. },
  481. },
  482. // podInfo is mutated after PodInfo is appended (namespace/node/instance added),
  483. // so PodInfo.Labels also reflects those fields at assertion time.
  484. expected: []metric.Update{
  485. {
  486. Name: metric.PodInfo,
  487. Labels: map[string]string{
  488. source.UIDLabel: "uuid1",
  489. source.PodLabel: "pod1",
  490. source.NamespaceUIDLabel: "",
  491. source.NodeUIDLabel: "",
  492. source.NamespaceLabel: "namespace1",
  493. source.NodeLabel: "node1",
  494. source.InstanceLabel: "node1",
  495. },
  496. Value: 0,
  497. AdditionalInfo: map[string]string{
  498. source.UIDLabel: "uuid1",
  499. source.PodLabel: "pod1",
  500. source.NamespaceUIDLabel: "",
  501. source.NodeUIDLabel: "",
  502. source.NamespaceLabel: "namespace1",
  503. source.NodeLabel: "node1",
  504. source.InstanceLabel: "node1",
  505. },
  506. },
  507. {
  508. Name: metric.KubePodLabels,
  509. Labels: map[string]string{
  510. source.UIDLabel: "uuid1",
  511. source.PodLabel: "pod1",
  512. source.NamespaceUIDLabel: "",
  513. source.NodeUIDLabel: "",
  514. source.NamespaceLabel: "namespace1",
  515. source.NodeLabel: "node1",
  516. source.InstanceLabel: "node1",
  517. },
  518. Value: 0,
  519. AdditionalInfo: map[string]string{
  520. "label_test1": "blah",
  521. "label_test2": "blah2",
  522. },
  523. },
  524. {
  525. Name: metric.KubePodAnnotations,
  526. Labels: map[string]string{
  527. source.UIDLabel: "uuid1",
  528. source.PodLabel: "pod1",
  529. source.NamespaceUIDLabel: "",
  530. source.NodeUIDLabel: "",
  531. source.NamespaceLabel: "namespace1",
  532. source.NodeLabel: "node1",
  533. source.InstanceLabel: "node1",
  534. },
  535. Value: 0,
  536. AdditionalInfo: map[string]string{
  537. "annotation_test3": "blah3",
  538. "annotation_test4": "blah4",
  539. },
  540. },
  541. {
  542. Name: metric.KubePodOwner,
  543. Labels: map[string]string{
  544. source.UIDLabel: "uuid1",
  545. source.PodLabel: "pod1",
  546. source.NamespaceUIDLabel: "",
  547. source.NodeUIDLabel: "",
  548. source.NamespaceLabel: "namespace1",
  549. source.NodeLabel: "node1",
  550. source.InstanceLabel: "node1",
  551. source.OwnerKindLabel: "deployment",
  552. source.OwnerNameLabel: "deployment1",
  553. source.OwnerUIDLabel: "",
  554. source.ContainerLabel: "false",
  555. },
  556. Value: 0,
  557. AdditionalInfo: nil,
  558. },
  559. {
  560. Name: metric.KubePodContainerStatusRunning,
  561. Labels: map[string]string{
  562. source.UIDLabel: "uuid1",
  563. source.PodLabel: "pod1",
  564. source.NamespaceUIDLabel: "",
  565. source.NodeUIDLabel: "",
  566. source.NamespaceLabel: "namespace1",
  567. source.NodeLabel: "node1",
  568. source.InstanceLabel: "node1",
  569. source.ContainerLabel: "container1",
  570. },
  571. Value: 0,
  572. AdditionalInfo: map[string]string{
  573. source.UIDLabel: "uuid1",
  574. source.PodLabel: "pod1",
  575. source.NamespaceUIDLabel: "",
  576. source.NodeUIDLabel: "",
  577. source.NamespaceLabel: "namespace1",
  578. source.NodeLabel: "node1",
  579. source.InstanceLabel: "node1",
  580. source.ContainerLabel: "container1",
  581. },
  582. },
  583. {
  584. Name: metric.KubePodContainerResourceRequests,
  585. Labels: map[string]string{
  586. source.UIDLabel: "uuid1",
  587. source.PodLabel: "pod1",
  588. source.NamespaceUIDLabel: "",
  589. source.NodeUIDLabel: "",
  590. source.NamespaceLabel: "namespace1",
  591. source.NodeLabel: "node1",
  592. source.InstanceLabel: "node1",
  593. source.ContainerLabel: "container1",
  594. source.ResourceLabel: "cpu",
  595. source.UnitLabel: "core",
  596. },
  597. Value: 0.5,
  598. AdditionalInfo: nil,
  599. },
  600. {
  601. Name: metric.KubePodContainerResourceRequests,
  602. Labels: map[string]string{
  603. source.UIDLabel: "uuid1",
  604. source.PodLabel: "pod1",
  605. source.NamespaceUIDLabel: "",
  606. source.NodeUIDLabel: "",
  607. source.NamespaceLabel: "namespace1",
  608. source.NodeLabel: "node1",
  609. source.InstanceLabel: "node1",
  610. source.ContainerLabel: "container1",
  611. source.ResourceLabel: "memory",
  612. source.UnitLabel: "byte",
  613. },
  614. Value: 512,
  615. AdditionalInfo: nil,
  616. },
  617. {
  618. Name: metric.KubePodContainerResourceLimits,
  619. Labels: map[string]string{
  620. source.UIDLabel: "uuid1",
  621. source.PodLabel: "pod1",
  622. source.NamespaceUIDLabel: "",
  623. source.NodeUIDLabel: "",
  624. source.NamespaceLabel: "namespace1",
  625. source.NodeLabel: "node1",
  626. source.InstanceLabel: "node1",
  627. source.ContainerLabel: "container1",
  628. source.ResourceLabel: "cpu",
  629. source.UnitLabel: "core",
  630. },
  631. Value: 1,
  632. AdditionalInfo: nil,
  633. },
  634. {
  635. Name: metric.KubePodContainerResourceLimits,
  636. Labels: map[string]string{
  637. source.UIDLabel: "uuid1",
  638. source.PodLabel: "pod1",
  639. source.NamespaceUIDLabel: "",
  640. source.NodeUIDLabel: "",
  641. source.NamespaceLabel: "namespace1",
  642. source.NodeLabel: "node1",
  643. source.InstanceLabel: "node1",
  644. source.ContainerLabel: "container1",
  645. source.ResourceLabel: "memory",
  646. source.UnitLabel: "byte",
  647. },
  648. Value: 1024,
  649. AdditionalInfo: nil,
  650. },
  651. {
  652. Name: metric.PodPVCAllocation,
  653. Labels: map[string]string{
  654. source.PodLabel: unmountedPVsContainer,
  655. source.NamespaceLabel: "namespace1",
  656. source.PVCLabel: "pvc1",
  657. source.PVLabel: "vol1",
  658. },
  659. Value: 4096,
  660. AdditionalInfo: nil,
  661. },
  662. },
  663. },
  664. {
  665. name: "with namespace index",
  666. nsSetup: func(nsIndex map[string]types.UID) {
  667. nsIndex["namespace1"] = "ns-uuid1"
  668. },
  669. scrapes: []scrape{
  670. {
  671. Pods: []*clustercache.Pod{
  672. {
  673. Name: "pod1",
  674. Namespace: "namespace1",
  675. UID: "uuid1",
  676. Spec: clustercache.PodSpec{
  677. NodeName: "node1",
  678. Containers: []clustercache.Container{
  679. {
  680. Name: "container1",
  681. Resources: v1.ResourceRequirements{
  682. Requests: map[v1.ResourceName]resource.Quantity{
  683. v1.ResourceCPU: resource.MustParse("500m"),
  684. v1.ResourceMemory: resource.MustParse("512"),
  685. },
  686. Limits: map[v1.ResourceName]resource.Quantity{
  687. v1.ResourceCPU: resource.MustParse("1"),
  688. v1.ResourceMemory: resource.MustParse("1024"),
  689. },
  690. },
  691. },
  692. },
  693. },
  694. Status: clustercache.PodStatus{
  695. ContainerStatuses: []v1.ContainerStatus{
  696. {
  697. Name: "container1",
  698. State: v1.ContainerState{
  699. Running: &v1.ContainerStateRunning{},
  700. },
  701. },
  702. },
  703. },
  704. },
  705. },
  706. Timestamp: start1,
  707. },
  708. },
  709. expected: []metric.Update{
  710. {
  711. Name: metric.PodInfo,
  712. Labels: map[string]string{
  713. source.UIDLabel: "uuid1",
  714. source.PodLabel: "pod1",
  715. source.NamespaceUIDLabel: "ns-uuid1",
  716. source.NodeUIDLabel: "",
  717. source.NamespaceLabel: "namespace1",
  718. source.NodeLabel: "node1",
  719. source.InstanceLabel: "node1",
  720. },
  721. Value: 0,
  722. AdditionalInfo: map[string]string{
  723. source.UIDLabel: "uuid1",
  724. source.PodLabel: "pod1",
  725. source.NamespaceUIDLabel: "ns-uuid1",
  726. source.NodeUIDLabel: "",
  727. source.NamespaceLabel: "namespace1",
  728. source.NodeLabel: "node1",
  729. source.InstanceLabel: "node1",
  730. },
  731. },
  732. {
  733. Name: metric.KubePodLabels,
  734. Labels: map[string]string{
  735. source.UIDLabel: "uuid1",
  736. source.PodLabel: "pod1",
  737. source.NamespaceUIDLabel: "ns-uuid1",
  738. source.NodeUIDLabel: "",
  739. source.NamespaceLabel: "namespace1",
  740. source.NodeLabel: "node1",
  741. source.InstanceLabel: "node1",
  742. },
  743. Value: 0,
  744. AdditionalInfo: map[string]string{},
  745. },
  746. {
  747. Name: metric.KubePodAnnotations,
  748. Labels: map[string]string{
  749. source.UIDLabel: "uuid1",
  750. source.PodLabel: "pod1",
  751. source.NamespaceUIDLabel: "ns-uuid1",
  752. source.NodeUIDLabel: "",
  753. source.NamespaceLabel: "namespace1",
  754. source.NodeLabel: "node1",
  755. source.InstanceLabel: "node1",
  756. },
  757. Value: 0,
  758. AdditionalInfo: map[string]string{},
  759. },
  760. {
  761. Name: metric.KubePodContainerStatusRunning,
  762. Labels: map[string]string{
  763. source.UIDLabel: "uuid1",
  764. source.PodLabel: "pod1",
  765. source.NamespaceUIDLabel: "ns-uuid1",
  766. source.NodeUIDLabel: "",
  767. source.NamespaceLabel: "namespace1",
  768. source.NodeLabel: "node1",
  769. source.InstanceLabel: "node1",
  770. source.ContainerLabel: "container1",
  771. },
  772. Value: 0,
  773. AdditionalInfo: map[string]string{
  774. source.UIDLabel: "uuid1",
  775. source.PodLabel: "pod1",
  776. source.NamespaceUIDLabel: "ns-uuid1",
  777. source.NodeUIDLabel: "",
  778. source.NamespaceLabel: "namespace1",
  779. source.NodeLabel: "node1",
  780. source.InstanceLabel: "node1",
  781. source.ContainerLabel: "container1",
  782. },
  783. },
  784. {
  785. Name: metric.KubePodContainerResourceRequests,
  786. Labels: map[string]string{
  787. source.UIDLabel: "uuid1",
  788. source.PodLabel: "pod1",
  789. source.NamespaceUIDLabel: "ns-uuid1",
  790. source.NodeUIDLabel: "",
  791. source.NamespaceLabel: "namespace1",
  792. source.NodeLabel: "node1",
  793. source.InstanceLabel: "node1",
  794. source.ContainerLabel: "container1",
  795. source.ResourceLabel: "cpu",
  796. source.UnitLabel: "core",
  797. },
  798. Value: 0.5,
  799. AdditionalInfo: nil,
  800. },
  801. {
  802. Name: metric.KubePodContainerResourceRequests,
  803. Labels: map[string]string{
  804. source.UIDLabel: "uuid1",
  805. source.PodLabel: "pod1",
  806. source.NamespaceUIDLabel: "ns-uuid1",
  807. source.NodeUIDLabel: "",
  808. source.NamespaceLabel: "namespace1",
  809. source.NodeLabel: "node1",
  810. source.InstanceLabel: "node1",
  811. source.ContainerLabel: "container1",
  812. source.ResourceLabel: "memory",
  813. source.UnitLabel: "byte",
  814. },
  815. Value: 512,
  816. AdditionalInfo: nil,
  817. },
  818. {
  819. Name: metric.KubePodContainerResourceLimits,
  820. Labels: map[string]string{
  821. source.UIDLabel: "uuid1",
  822. source.PodLabel: "pod1",
  823. source.NamespaceUIDLabel: "ns-uuid1",
  824. source.NodeUIDLabel: "",
  825. source.NamespaceLabel: "namespace1",
  826. source.NodeLabel: "node1",
  827. source.InstanceLabel: "node1",
  828. source.ContainerLabel: "container1",
  829. source.ResourceLabel: "cpu",
  830. source.UnitLabel: "core",
  831. },
  832. Value: 1,
  833. AdditionalInfo: nil,
  834. },
  835. {
  836. Name: metric.KubePodContainerResourceLimits,
  837. Labels: map[string]string{
  838. source.UIDLabel: "uuid1",
  839. source.PodLabel: "pod1",
  840. source.NamespaceUIDLabel: "ns-uuid1",
  841. source.NodeUIDLabel: "",
  842. source.NamespaceLabel: "namespace1",
  843. source.NodeLabel: "node1",
  844. source.InstanceLabel: "node1",
  845. source.ContainerLabel: "container1",
  846. source.ResourceLabel: "memory",
  847. source.UnitLabel: "byte",
  848. },
  849. Value: 1024,
  850. AdditionalInfo: nil,
  851. },
  852. },
  853. },
  854. }
  855. for _, tt := range tests {
  856. t.Run(tt.name, func(t *testing.T) {
  857. ks := &ClusterCacheScraper{}
  858. nodeIndex := make(map[string]types.UID, 0)
  859. nsIndex := make(map[string]types.UID, 0)
  860. if tt.nsSetup != nil {
  861. tt.nsSetup(nsIndex)
  862. }
  863. pvcIndex := make(map[pvcKey]types.UID, 0)
  864. var scrapeResults []metric.Update
  865. for _, s := range tt.scrapes {
  866. res := ks.scrapePods(s.Pods, s.PVCs, nodeIndex, nsIndex, pvcIndex)
  867. scrapeResults = append(scrapeResults, res...)
  868. }
  869. if len(scrapeResults) != len(tt.expected) {
  870. t.Errorf("Expected result length of %d, got %d", len(tt.expected), len(scrapeResults))
  871. }
  872. for i, expected := range tt.expected {
  873. got := scrapeResults[i]
  874. if !reflect.DeepEqual(expected, got) {
  875. t.Errorf("Result did not match expected at index %d: got %v, want %v", i, got, expected)
  876. }
  877. }
  878. })
  879. }
  880. }
  881. func Test_kubernetesScraper_scrapePVCs(t *testing.T) {
  882. start1, _ := time.Parse(time.RFC3339, Start1Str)
  883. type scrape struct {
  884. PVCs []*clustercache.PersistentVolumeClaim
  885. Timestamp time.Time
  886. }
  887. tests := []struct {
  888. name string
  889. nsSetup func(map[string]types.UID)
  890. scrapes []scrape
  891. expected []metric.Update
  892. }{
  893. {
  894. name: "simple",
  895. scrapes: []scrape{
  896. {
  897. PVCs: []*clustercache.PersistentVolumeClaim{
  898. {
  899. Name: "pvc1",
  900. Namespace: "namespace1",
  901. UID: "uuid1",
  902. Spec: v1.PersistentVolumeClaimSpec{
  903. VolumeName: "vol1",
  904. StorageClassName: util.Ptr("storageClass1"),
  905. Resources: v1.VolumeResourceRequirements{
  906. Requests: v1.ResourceList{
  907. v1.ResourceStorage: resource.MustParse("4096"),
  908. },
  909. },
  910. },
  911. },
  912. },
  913. Timestamp: start1,
  914. },
  915. },
  916. expected: []metric.Update{
  917. {
  918. Name: metric.KubePersistentVolumeClaimInfo,
  919. Labels: map[string]string{
  920. source.UIDLabel: "uuid1",
  921. source.PVCLabel: "pvc1",
  922. source.NamespaceUIDLabel: "",
  923. source.NamespaceLabel: "namespace1",
  924. source.VolumeNameLabel: "vol1",
  925. source.PVUIDLabel: "",
  926. source.StorageClassLabel: "storageClass1",
  927. },
  928. Value: 0,
  929. AdditionalInfo: map[string]string{
  930. source.UIDLabel: "uuid1",
  931. source.PVCLabel: "pvc1",
  932. source.NamespaceUIDLabel: "",
  933. source.NamespaceLabel: "namespace1",
  934. source.VolumeNameLabel: "vol1",
  935. source.PVUIDLabel: "",
  936. source.StorageClassLabel: "storageClass1",
  937. },
  938. },
  939. {
  940. Name: metric.KubePersistentVolumeClaimResourceRequestsStorageBytes,
  941. Labels: map[string]string{
  942. source.UIDLabel: "uuid1",
  943. source.PVCLabel: "pvc1",
  944. source.NamespaceUIDLabel: "",
  945. source.NamespaceLabel: "namespace1",
  946. source.VolumeNameLabel: "vol1",
  947. source.PVUIDLabel: "",
  948. source.StorageClassLabel: "storageClass1",
  949. },
  950. Value: 4096,
  951. AdditionalInfo: nil,
  952. },
  953. },
  954. },
  955. {
  956. name: "with namespace index",
  957. nsSetup: func(nsIndex map[string]types.UID) {
  958. nsIndex["namespace1"] = "ns-uuid1"
  959. },
  960. scrapes: []scrape{
  961. {
  962. PVCs: []*clustercache.PersistentVolumeClaim{
  963. {
  964. Name: "pvc1",
  965. Namespace: "namespace1",
  966. UID: "uuid1",
  967. Spec: v1.PersistentVolumeClaimSpec{
  968. VolumeName: "vol1",
  969. StorageClassName: util.Ptr("storageClass1"),
  970. Resources: v1.VolumeResourceRequirements{
  971. Requests: v1.ResourceList{
  972. v1.ResourceStorage: resource.MustParse("4096"),
  973. },
  974. },
  975. },
  976. },
  977. },
  978. Timestamp: start1,
  979. },
  980. },
  981. expected: []metric.Update{
  982. {
  983. Name: metric.KubePersistentVolumeClaimInfo,
  984. Labels: map[string]string{
  985. source.UIDLabel: "uuid1",
  986. source.PVCLabel: "pvc1",
  987. source.NamespaceUIDLabel: "ns-uuid1",
  988. source.NamespaceLabel: "namespace1",
  989. source.VolumeNameLabel: "vol1",
  990. source.PVUIDLabel: "",
  991. source.StorageClassLabel: "storageClass1",
  992. },
  993. Value: 0,
  994. AdditionalInfo: map[string]string{
  995. source.UIDLabel: "uuid1",
  996. source.PVCLabel: "pvc1",
  997. source.NamespaceUIDLabel: "ns-uuid1",
  998. source.NamespaceLabel: "namespace1",
  999. source.VolumeNameLabel: "vol1",
  1000. source.PVUIDLabel: "",
  1001. source.StorageClassLabel: "storageClass1",
  1002. },
  1003. },
  1004. {
  1005. Name: metric.KubePersistentVolumeClaimResourceRequestsStorageBytes,
  1006. Labels: map[string]string{
  1007. source.UIDLabel: "uuid1",
  1008. source.PVCLabel: "pvc1",
  1009. source.NamespaceUIDLabel: "ns-uuid1",
  1010. source.NamespaceLabel: "namespace1",
  1011. source.VolumeNameLabel: "vol1",
  1012. source.PVUIDLabel: "",
  1013. source.StorageClassLabel: "storageClass1",
  1014. },
  1015. Value: 4096,
  1016. AdditionalInfo: nil,
  1017. },
  1018. },
  1019. },
  1020. }
  1021. for _, tt := range tests {
  1022. t.Run(tt.name, func(t *testing.T) {
  1023. ks := &ClusterCacheScraper{}
  1024. nsIndex := make(map[string]types.UID, 0)
  1025. if tt.nsSetup != nil {
  1026. tt.nsSetup(nsIndex)
  1027. }
  1028. pvIndex := make(map[string]types.UID, 0)
  1029. var scrapeResults []metric.Update
  1030. for _, s := range tt.scrapes {
  1031. res := ks.scrapePVCs(s.PVCs, nsIndex, pvIndex)
  1032. scrapeResults = append(scrapeResults, res...)
  1033. }
  1034. if len(scrapeResults) != len(tt.expected) {
  1035. t.Errorf("Expected result length of %d, got %d", len(tt.expected), len(scrapeResults))
  1036. }
  1037. for i, expected := range tt.expected {
  1038. got := scrapeResults[i]
  1039. if !reflect.DeepEqual(expected, got) {
  1040. t.Errorf("Result did not match expected at index %d: got %v, want %v", i, got, expected)
  1041. }
  1042. }
  1043. })
  1044. }
  1045. }
  1046. func Test_kubernetesScraper_scrapePVs(t *testing.T) {
  1047. start1, _ := time.Parse(time.RFC3339, Start1Str)
  1048. type scrape struct {
  1049. PVs []*clustercache.PersistentVolume
  1050. Timestamp time.Time
  1051. }
  1052. tests := []struct {
  1053. name string
  1054. scrapes []scrape
  1055. expected []metric.Update
  1056. }{
  1057. {
  1058. name: "simple",
  1059. scrapes: []scrape{
  1060. {
  1061. PVs: []*clustercache.PersistentVolume{
  1062. {
  1063. Name: "pv1",
  1064. UID: "uuid1",
  1065. Spec: v1.PersistentVolumeSpec{
  1066. StorageClassName: "storageClass1",
  1067. PersistentVolumeSource: v1.PersistentVolumeSource{
  1068. CSI: &v1.CSIPersistentVolumeSource{
  1069. VolumeHandle: "vol-1",
  1070. },
  1071. },
  1072. Capacity: v1.ResourceList{
  1073. v1.ResourceStorage: resource.MustParse("4096"),
  1074. },
  1075. },
  1076. },
  1077. },
  1078. Timestamp: start1,
  1079. },
  1080. },
  1081. expected: []metric.Update{
  1082. {
  1083. Name: metric.KubecostPVInfo,
  1084. Labels: map[string]string{
  1085. source.UIDLabel: "uuid1",
  1086. source.PVLabel: "pv1",
  1087. source.StorageClassLabel: "storageClass1",
  1088. source.ProviderIDLabel: "vol-1",
  1089. source.CSIVolumeHandleLabel: "vol-1",
  1090. },
  1091. Value: 0,
  1092. AdditionalInfo: map[string]string{
  1093. source.UIDLabel: "uuid1",
  1094. source.PVLabel: "pv1",
  1095. source.StorageClassLabel: "storageClass1",
  1096. source.ProviderIDLabel: "vol-1",
  1097. source.CSIVolumeHandleLabel: "vol-1",
  1098. },
  1099. },
  1100. {
  1101. Name: metric.KubePersistentVolumeCapacityBytes,
  1102. Labels: map[string]string{
  1103. source.UIDLabel: "uuid1",
  1104. source.PVLabel: "pv1",
  1105. source.StorageClassLabel: "storageClass1",
  1106. source.ProviderIDLabel: "vol-1",
  1107. source.CSIVolumeHandleLabel: "vol-1",
  1108. },
  1109. Value: 4096,
  1110. AdditionalInfo: nil,
  1111. },
  1112. },
  1113. },
  1114. }
  1115. for _, tt := range tests {
  1116. t.Run(tt.name, func(t *testing.T) {
  1117. ks := &ClusterCacheScraper{}
  1118. var scrapeResults []metric.Update
  1119. for _, s := range tt.scrapes {
  1120. res := ks.scrapePVs(s.PVs)
  1121. scrapeResults = append(scrapeResults, res...)
  1122. }
  1123. if len(scrapeResults) != len(tt.expected) {
  1124. t.Errorf("Expected result length of %d, got %d", len(tt.expected), len(scrapeResults))
  1125. }
  1126. for i, expected := range tt.expected {
  1127. got := scrapeResults[i]
  1128. if !reflect.DeepEqual(expected, got) {
  1129. t.Errorf("Result did not match expected at index %d: got %v, want %v", i, got, expected)
  1130. }
  1131. }
  1132. })
  1133. }
  1134. }
  1135. func Test_kubernetesScraper_scrapeServices(t *testing.T) {
  1136. start1, _ := time.Parse(time.RFC3339, Start1Str)
  1137. type scrape struct {
  1138. Services []*clustercache.Service
  1139. Timestamp time.Time
  1140. }
  1141. tests := []struct {
  1142. name string
  1143. scrapes []scrape
  1144. expected []metric.Update
  1145. }{
  1146. {
  1147. name: "simple",
  1148. scrapes: []scrape{
  1149. {
  1150. Services: []*clustercache.Service{
  1151. {
  1152. Name: "service1",
  1153. Namespace: "namespace1",
  1154. UID: "uuid1",
  1155. SpecSelector: map[string]string{
  1156. "test1": "blah",
  1157. "test2": "blah2",
  1158. },
  1159. },
  1160. },
  1161. Timestamp: start1,
  1162. },
  1163. },
  1164. expected: []metric.Update{
  1165. {
  1166. Name: metric.ServiceInfo,
  1167. Labels: map[string]string{
  1168. source.UIDLabel: "uuid1",
  1169. source.ServiceLabel: "service1",
  1170. source.NamespaceLabel: "namespace1",
  1171. source.ServiceTypeLabel: "",
  1172. },
  1173. Value: 0,
  1174. AdditionalInfo: map[string]string{
  1175. source.UIDLabel: "uuid1",
  1176. source.ServiceLabel: "service1",
  1177. source.NamespaceLabel: "namespace1",
  1178. source.ServiceTypeLabel: "",
  1179. },
  1180. },
  1181. {
  1182. Name: metric.ServiceSelectorLabels,
  1183. Labels: map[string]string{
  1184. source.UIDLabel: "uuid1",
  1185. source.ServiceLabel: "service1",
  1186. source.NamespaceLabel: "namespace1",
  1187. source.ServiceTypeLabel: "",
  1188. },
  1189. Value: 0,
  1190. AdditionalInfo: map[string]string{
  1191. "label_test1": "blah",
  1192. "label_test2": "blah2",
  1193. },
  1194. },
  1195. },
  1196. },
  1197. }
  1198. for _, tt := range tests {
  1199. t.Run(tt.name, func(t *testing.T) {
  1200. ks := &ClusterCacheScraper{}
  1201. var scrapeResults []metric.Update
  1202. for _, s := range tt.scrapes {
  1203. res := ks.scrapeServices(s.Services)
  1204. scrapeResults = append(scrapeResults, res...)
  1205. }
  1206. if len(scrapeResults) != len(tt.expected) {
  1207. t.Errorf("Expected result length of %d, got %d", len(tt.expected), len(scrapeResults))
  1208. }
  1209. for i, expected := range tt.expected {
  1210. got := scrapeResults[i]
  1211. if !reflect.DeepEqual(expected, got) {
  1212. t.Errorf("Result did not match expected at index %d: got %v, want %v", i, got, expected)
  1213. }
  1214. }
  1215. })
  1216. }
  1217. }
  1218. func Test_kubernetesScraper_scrapeStatefulSets(t *testing.T) {
  1219. start1, _ := time.Parse(time.RFC3339, Start1Str)
  1220. type scrape struct {
  1221. StatefulSets []*clustercache.StatefulSet
  1222. Timestamp time.Time
  1223. }
  1224. tests := []struct {
  1225. name string
  1226. nsSetup func(map[string]types.UID)
  1227. scrapes []scrape
  1228. expected []metric.Update
  1229. }{
  1230. {
  1231. name: "simple",
  1232. scrapes: []scrape{
  1233. {
  1234. StatefulSets: []*clustercache.StatefulSet{
  1235. {
  1236. Name: "statefulSet1",
  1237. Namespace: "namespace1",
  1238. UID: "uuid1",
  1239. SpecSelector: &metav1.LabelSelector{
  1240. MatchLabels: map[string]string{
  1241. "test1": "blah",
  1242. "test2": "blah2",
  1243. },
  1244. },
  1245. },
  1246. },
  1247. Timestamp: start1,
  1248. },
  1249. },
  1250. // statefulSetInfo map is shared across all 4 metrics; namespace is added
  1251. // before StatefulSetMatchLabels is appended, so all 4 reflect the final state.
  1252. expected: []metric.Update{
  1253. {
  1254. Name: metric.StatefulSetInfo,
  1255. Labels: map[string]string{
  1256. source.UIDLabel: "uuid1",
  1257. source.NamespaceUIDLabel: "",
  1258. source.StatefulSetLabel: "statefulSet1",
  1259. source.NamespaceLabel: "namespace1",
  1260. },
  1261. Value: 0,
  1262. AdditionalInfo: map[string]string{
  1263. source.UIDLabel: "uuid1",
  1264. source.NamespaceUIDLabel: "",
  1265. source.StatefulSetLabel: "statefulSet1",
  1266. source.NamespaceLabel: "namespace1",
  1267. },
  1268. },
  1269. {
  1270. Name: metric.StatefulSetLabels,
  1271. Labels: map[string]string{
  1272. source.UIDLabel: "uuid1",
  1273. source.NamespaceUIDLabel: "",
  1274. source.StatefulSetLabel: "statefulSet1",
  1275. source.NamespaceLabel: "namespace1",
  1276. },
  1277. Value: 0,
  1278. AdditionalInfo: map[string]string{},
  1279. },
  1280. {
  1281. Name: metric.StatefulSetAnnotations,
  1282. Labels: map[string]string{
  1283. source.UIDLabel: "uuid1",
  1284. source.NamespaceUIDLabel: "",
  1285. source.StatefulSetLabel: "statefulSet1",
  1286. source.NamespaceLabel: "namespace1",
  1287. },
  1288. Value: 0,
  1289. AdditionalInfo: map[string]string{},
  1290. },
  1291. {
  1292. Name: metric.StatefulSetMatchLabels,
  1293. Labels: map[string]string{
  1294. source.UIDLabel: "uuid1",
  1295. source.NamespaceUIDLabel: "",
  1296. source.StatefulSetLabel: "statefulSet1",
  1297. source.NamespaceLabel: "namespace1",
  1298. },
  1299. Value: 0,
  1300. AdditionalInfo: map[string]string{
  1301. "label_test1": "blah",
  1302. "label_test2": "blah2",
  1303. },
  1304. },
  1305. },
  1306. },
  1307. {
  1308. // statefulSetInfo map is shared; NamespaceLabel is added before MatchLabels,
  1309. // so all 4 metrics reflect the final state including namespace_uid.
  1310. name: "with namespace index",
  1311. nsSetup: func(nsIndex map[string]types.UID) {
  1312. nsIndex["namespace1"] = "ns-uuid1"
  1313. },
  1314. scrapes: []scrape{
  1315. {
  1316. StatefulSets: []*clustercache.StatefulSet{
  1317. {
  1318. Name: "statefulSet1",
  1319. Namespace: "namespace1",
  1320. UID: "uuid1",
  1321. SpecSelector: &metav1.LabelSelector{},
  1322. },
  1323. },
  1324. Timestamp: start1,
  1325. },
  1326. },
  1327. expected: []metric.Update{
  1328. {
  1329. Name: metric.StatefulSetInfo,
  1330. Labels: map[string]string{
  1331. source.UIDLabel: "uuid1",
  1332. source.NamespaceUIDLabel: "ns-uuid1",
  1333. source.StatefulSetLabel: "statefulSet1",
  1334. source.NamespaceLabel: "namespace1",
  1335. },
  1336. Value: 0,
  1337. AdditionalInfo: map[string]string{
  1338. source.UIDLabel: "uuid1",
  1339. source.NamespaceUIDLabel: "ns-uuid1",
  1340. source.StatefulSetLabel: "statefulSet1",
  1341. source.NamespaceLabel: "namespace1",
  1342. },
  1343. },
  1344. {
  1345. Name: metric.StatefulSetLabels,
  1346. Labels: map[string]string{
  1347. source.UIDLabel: "uuid1",
  1348. source.NamespaceUIDLabel: "ns-uuid1",
  1349. source.StatefulSetLabel: "statefulSet1",
  1350. source.NamespaceLabel: "namespace1",
  1351. },
  1352. Value: 0,
  1353. AdditionalInfo: map[string]string{},
  1354. },
  1355. {
  1356. Name: metric.StatefulSetAnnotations,
  1357. Labels: map[string]string{
  1358. source.UIDLabel: "uuid1",
  1359. source.NamespaceUIDLabel: "ns-uuid1",
  1360. source.StatefulSetLabel: "statefulSet1",
  1361. source.NamespaceLabel: "namespace1",
  1362. },
  1363. Value: 0,
  1364. AdditionalInfo: map[string]string{},
  1365. },
  1366. {
  1367. Name: metric.StatefulSetMatchLabels,
  1368. Labels: map[string]string{
  1369. source.UIDLabel: "uuid1",
  1370. source.NamespaceUIDLabel: "ns-uuid1",
  1371. source.StatefulSetLabel: "statefulSet1",
  1372. source.NamespaceLabel: "namespace1",
  1373. },
  1374. Value: 0,
  1375. AdditionalInfo: map[string]string{},
  1376. },
  1377. },
  1378. },
  1379. }
  1380. for _, tt := range tests {
  1381. t.Run(tt.name, func(t *testing.T) {
  1382. ks := &ClusterCacheScraper{}
  1383. nsIndex := make(map[string]types.UID, 0)
  1384. if tt.nsSetup != nil {
  1385. tt.nsSetup(nsIndex)
  1386. }
  1387. var scrapeResults []metric.Update
  1388. for _, s := range tt.scrapes {
  1389. res := ks.scrapeStatefulSets(s.StatefulSets, nsIndex)
  1390. scrapeResults = append(scrapeResults, res...)
  1391. }
  1392. if len(scrapeResults) != len(tt.expected) {
  1393. t.Errorf("Expected result length of %d, got %d", len(tt.expected), len(scrapeResults))
  1394. }
  1395. for i, expected := range tt.expected {
  1396. got := scrapeResults[i]
  1397. if !reflect.DeepEqual(expected, got) {
  1398. t.Errorf("Result did not match expected at index %d: got %v, want %v", i, got, expected)
  1399. }
  1400. }
  1401. })
  1402. }
  1403. }
  1404. func Test_kubernetesScraper_scrapeReplicaSets(t *testing.T) {
  1405. start1, _ := time.Parse(time.RFC3339, Start1Str)
  1406. type scrape struct {
  1407. ReplicaSets []*clustercache.ReplicaSet
  1408. Timestamp time.Time
  1409. }
  1410. tests := []struct {
  1411. name string
  1412. nsSetup func(map[string]types.UID)
  1413. scrapes []scrape
  1414. expected []metric.Update
  1415. }{
  1416. {
  1417. name: "simple",
  1418. scrapes: []scrape{
  1419. {
  1420. ReplicaSets: []*clustercache.ReplicaSet{
  1421. {
  1422. Name: "replicaSet1",
  1423. Namespace: "namespace1",
  1424. UID: "uuid1",
  1425. OwnerReferences: []metav1.OwnerReference{
  1426. {
  1427. Name: "rollout1",
  1428. Kind: "Rollout",
  1429. },
  1430. },
  1431. },
  1432. {
  1433. Name: "pureReplicaSet",
  1434. Namespace: "namespace1",
  1435. UID: "uuid2",
  1436. OwnerReferences: []metav1.OwnerReference{},
  1437. },
  1438. },
  1439. Timestamp: start1,
  1440. },
  1441. },
  1442. expected: []metric.Update{
  1443. // replicaSet1: info/labels/annotations use replicaSetInfo (uid, namespace_uid, replicaset)
  1444. {
  1445. Name: metric.ReplicaSetInfo,
  1446. Labels: map[string]string{
  1447. source.UIDLabel: "uuid1",
  1448. source.NamespaceUIDLabel: "",
  1449. source.ReplicaSetLabel: "replicaSet1",
  1450. },
  1451. Value: 0,
  1452. AdditionalInfo: map[string]string{
  1453. source.UIDLabel: "uuid1",
  1454. source.NamespaceUIDLabel: "",
  1455. source.ReplicaSetLabel: "replicaSet1",
  1456. },
  1457. },
  1458. {
  1459. Name: metric.ReplicaSetLabels,
  1460. Labels: map[string]string{
  1461. source.UIDLabel: "uuid1",
  1462. source.NamespaceUIDLabel: "",
  1463. source.ReplicaSetLabel: "replicaSet1",
  1464. },
  1465. Value: 0,
  1466. AdditionalInfo: map[string]string{},
  1467. },
  1468. {
  1469. Name: metric.ReplicaSetAnnotations,
  1470. Labels: map[string]string{
  1471. source.UIDLabel: "uuid1",
  1472. source.NamespaceUIDLabel: "",
  1473. source.ReplicaSetLabel: "replicaSet1",
  1474. },
  1475. Value: 0,
  1476. AdditionalInfo: map[string]string{},
  1477. },
  1478. // replicaSet1 owner: uses replicaSetOwnerInfo (replicaset, namespace, uid) + owner fields
  1479. {
  1480. Name: metric.KubeReplicasetOwner,
  1481. Labels: map[string]string{
  1482. source.ReplicaSetLabel: "replicaSet1",
  1483. source.NamespaceLabel: "namespace1",
  1484. source.UIDLabel: "uuid1",
  1485. source.OwnerNameLabel: "rollout1",
  1486. source.OwnerKindLabel: "Rollout",
  1487. source.OwnerUIDLabel: "",
  1488. source.ControllerLabel: "false",
  1489. },
  1490. Value: 0,
  1491. },
  1492. // pureReplicaSet: info/labels/annotations
  1493. {
  1494. Name: metric.ReplicaSetInfo,
  1495. Labels: map[string]string{
  1496. source.UIDLabel: "uuid2",
  1497. source.NamespaceUIDLabel: "",
  1498. source.ReplicaSetLabel: "pureReplicaSet",
  1499. },
  1500. Value: 0,
  1501. AdditionalInfo: map[string]string{
  1502. source.UIDLabel: "uuid2",
  1503. source.NamespaceUIDLabel: "",
  1504. source.ReplicaSetLabel: "pureReplicaSet",
  1505. },
  1506. },
  1507. {
  1508. Name: metric.ReplicaSetLabels,
  1509. Labels: map[string]string{
  1510. source.UIDLabel: "uuid2",
  1511. source.NamespaceUIDLabel: "",
  1512. source.ReplicaSetLabel: "pureReplicaSet",
  1513. },
  1514. Value: 0,
  1515. AdditionalInfo: map[string]string{},
  1516. },
  1517. {
  1518. Name: metric.ReplicaSetAnnotations,
  1519. Labels: map[string]string{
  1520. source.UIDLabel: "uuid2",
  1521. source.NamespaceUIDLabel: "",
  1522. source.ReplicaSetLabel: "pureReplicaSet",
  1523. },
  1524. Value: 0,
  1525. AdditionalInfo: map[string]string{},
  1526. },
  1527. // pureReplicaSet owner: no owners path uses <none> sentinel, no owner_uid/controller
  1528. {
  1529. Name: metric.KubeReplicasetOwner,
  1530. Labels: map[string]string{
  1531. source.ReplicaSetLabel: "pureReplicaSet",
  1532. source.NamespaceLabel: "namespace1",
  1533. source.UIDLabel: "uuid2",
  1534. source.OwnerNameLabel: source.NoneLabelValue,
  1535. source.OwnerKindLabel: source.NoneLabelValue,
  1536. },
  1537. Value: 0,
  1538. },
  1539. },
  1540. },
  1541. {
  1542. name: "with namespace index",
  1543. nsSetup: func(nsIndex map[string]types.UID) {
  1544. nsIndex["namespace1"] = "ns-uuid1"
  1545. },
  1546. scrapes: []scrape{
  1547. {
  1548. ReplicaSets: []*clustercache.ReplicaSet{
  1549. {
  1550. Name: "replicaSet1",
  1551. Namespace: "namespace1",
  1552. UID: "uuid1",
  1553. OwnerReferences: []metav1.OwnerReference{},
  1554. },
  1555. },
  1556. Timestamp: start1,
  1557. },
  1558. },
  1559. expected: []metric.Update{
  1560. {
  1561. Name: metric.ReplicaSetInfo,
  1562. Labels: map[string]string{
  1563. source.UIDLabel: "uuid1",
  1564. source.NamespaceUIDLabel: "ns-uuid1",
  1565. source.ReplicaSetLabel: "replicaSet1",
  1566. },
  1567. Value: 0,
  1568. AdditionalInfo: map[string]string{
  1569. source.UIDLabel: "uuid1",
  1570. source.NamespaceUIDLabel: "ns-uuid1",
  1571. source.ReplicaSetLabel: "replicaSet1",
  1572. },
  1573. },
  1574. {
  1575. Name: metric.ReplicaSetLabels,
  1576. Labels: map[string]string{
  1577. source.UIDLabel: "uuid1",
  1578. source.NamespaceUIDLabel: "ns-uuid1",
  1579. source.ReplicaSetLabel: "replicaSet1",
  1580. },
  1581. Value: 0,
  1582. AdditionalInfo: map[string]string{},
  1583. },
  1584. {
  1585. Name: metric.ReplicaSetAnnotations,
  1586. Labels: map[string]string{
  1587. source.UIDLabel: "uuid1",
  1588. source.NamespaceUIDLabel: "ns-uuid1",
  1589. source.ReplicaSetLabel: "replicaSet1",
  1590. },
  1591. Value: 0,
  1592. AdditionalInfo: map[string]string{},
  1593. },
  1594. {
  1595. Name: metric.KubeReplicasetOwner,
  1596. Labels: map[string]string{
  1597. source.ReplicaSetLabel: "replicaSet1",
  1598. source.NamespaceLabel: "namespace1",
  1599. source.UIDLabel: "uuid1",
  1600. source.OwnerNameLabel: source.NoneLabelValue,
  1601. source.OwnerKindLabel: source.NoneLabelValue,
  1602. },
  1603. Value: 0,
  1604. },
  1605. },
  1606. },
  1607. }
  1608. for _, tt := range tests {
  1609. t.Run(tt.name, func(t *testing.T) {
  1610. ks := &ClusterCacheScraper{}
  1611. nsIndex := make(map[string]types.UID, 0)
  1612. if tt.nsSetup != nil {
  1613. tt.nsSetup(nsIndex)
  1614. }
  1615. var scrapeResults []metric.Update
  1616. for _, s := range tt.scrapes {
  1617. res := ks.scrapeReplicaSets(s.ReplicaSets, nsIndex)
  1618. scrapeResults = append(scrapeResults, res...)
  1619. }
  1620. if len(scrapeResults) != len(tt.expected) {
  1621. t.Errorf("Expected result length of %d, got %d", len(tt.expected), len(scrapeResults))
  1622. }
  1623. for i, expected := range tt.expected {
  1624. got := scrapeResults[i]
  1625. if !reflect.DeepEqual(expected, got) {
  1626. t.Errorf("Result did not match expected at index %d: got %v, want %v", i, got, expected)
  1627. }
  1628. }
  1629. })
  1630. }
  1631. }
  1632. func Test_kubernetesScraper_scrapeResourceQuotas(t *testing.T) {
  1633. start1, _ := time.Parse(time.RFC3339, Start1Str)
  1634. type scrape struct {
  1635. ResourceQuotas []*clustercache.ResourceQuota
  1636. Timestamp time.Time
  1637. }
  1638. tests := []struct {
  1639. name string
  1640. nsSetup func(map[string]types.UID)
  1641. scrapes []scrape
  1642. expected []metric.Update
  1643. }{
  1644. {
  1645. name: "simple",
  1646. scrapes: []scrape{
  1647. {
  1648. ResourceQuotas: []*clustercache.ResourceQuota{
  1649. {
  1650. Name: "resourceQuota1",
  1651. Namespace: "namespace1",
  1652. UID: "uuid1",
  1653. Spec: v1.ResourceQuotaSpec{
  1654. Hard: v1.ResourceList{
  1655. v1.ResourceRequestsCPU: resource.MustParse("1"),
  1656. v1.ResourceRequestsMemory: resource.MustParse("1024"),
  1657. v1.ResourceLimitsCPU: resource.MustParse("2"),
  1658. v1.ResourceLimitsMemory: resource.MustParse("2048"),
  1659. },
  1660. },
  1661. Status: v1.ResourceQuotaStatus{
  1662. Used: v1.ResourceList{
  1663. v1.ResourceRequestsCPU: resource.MustParse("0.5"),
  1664. v1.ResourceRequestsMemory: resource.MustParse("512"),
  1665. v1.ResourceLimitsCPU: resource.MustParse("1"),
  1666. v1.ResourceLimitsMemory: resource.MustParse("1024"),
  1667. },
  1668. },
  1669. },
  1670. },
  1671. Timestamp: start1,
  1672. },
  1673. },
  1674. expected: []metric.Update{
  1675. {
  1676. Name: metric.ResourceQuotaInfo,
  1677. Labels: map[string]string{
  1678. source.UIDLabel: "uuid1",
  1679. source.NamespaceUIDLabel: "",
  1680. source.ResourceQuotaLabel: "resourceQuota1",
  1681. },
  1682. Value: 0,
  1683. AdditionalInfo: map[string]string{
  1684. source.UIDLabel: "uuid1",
  1685. source.NamespaceUIDLabel: "",
  1686. source.ResourceQuotaLabel: "resourceQuota1",
  1687. },
  1688. },
  1689. {
  1690. Name: metric.KubeResourceQuotaSpecResourceRequests,
  1691. Labels: map[string]string{
  1692. source.UIDLabel: "uuid1",
  1693. source.NamespaceUIDLabel: "",
  1694. source.ResourceQuotaLabel: "resourceQuota1",
  1695. source.ResourceLabel: "cpu",
  1696. source.UnitLabel: "core",
  1697. },
  1698. Value: 1,
  1699. AdditionalInfo: nil,
  1700. },
  1701. {
  1702. Name: metric.KubeResourceQuotaSpecResourceRequests,
  1703. Labels: map[string]string{
  1704. source.UIDLabel: "uuid1",
  1705. source.NamespaceUIDLabel: "",
  1706. source.ResourceQuotaLabel: "resourceQuota1",
  1707. source.ResourceLabel: "memory",
  1708. source.UnitLabel: "byte",
  1709. },
  1710. Value: 1024,
  1711. AdditionalInfo: nil,
  1712. },
  1713. {
  1714. Name: metric.KubeResourceQuotaSpecResourceLimits,
  1715. Labels: map[string]string{
  1716. source.UIDLabel: "uuid1",
  1717. source.NamespaceUIDLabel: "",
  1718. source.ResourceQuotaLabel: "resourceQuota1",
  1719. source.ResourceLabel: "cpu",
  1720. source.UnitLabel: "core",
  1721. },
  1722. Value: 2,
  1723. AdditionalInfo: nil,
  1724. },
  1725. {
  1726. Name: metric.KubeResourceQuotaSpecResourceLimits,
  1727. Labels: map[string]string{
  1728. source.UIDLabel: "uuid1",
  1729. source.NamespaceUIDLabel: "",
  1730. source.ResourceQuotaLabel: "resourceQuota1",
  1731. source.ResourceLabel: "memory",
  1732. source.UnitLabel: "byte",
  1733. },
  1734. Value: 2048,
  1735. AdditionalInfo: nil,
  1736. },
  1737. {
  1738. Name: metric.KubeResourceQuotaStatusUsedResourceRequests,
  1739. Labels: map[string]string{
  1740. source.UIDLabel: "uuid1",
  1741. source.NamespaceUIDLabel: "",
  1742. source.ResourceQuotaLabel: "resourceQuota1",
  1743. source.ResourceLabel: "cpu",
  1744. source.UnitLabel: "core",
  1745. },
  1746. Value: 0.5,
  1747. AdditionalInfo: nil,
  1748. },
  1749. {
  1750. Name: metric.KubeResourceQuotaStatusUsedResourceRequests,
  1751. Labels: map[string]string{
  1752. source.UIDLabel: "uuid1",
  1753. source.NamespaceUIDLabel: "",
  1754. source.ResourceQuotaLabel: "resourceQuota1",
  1755. source.ResourceLabel: "memory",
  1756. source.UnitLabel: "byte",
  1757. },
  1758. Value: 512,
  1759. AdditionalInfo: nil,
  1760. },
  1761. {
  1762. Name: metric.KubeResourceQuotaStatusUsedResourceLimits,
  1763. Labels: map[string]string{
  1764. source.UIDLabel: "uuid1",
  1765. source.NamespaceUIDLabel: "",
  1766. source.ResourceQuotaLabel: "resourceQuota1",
  1767. source.ResourceLabel: "cpu",
  1768. source.UnitLabel: "core",
  1769. },
  1770. Value: 1,
  1771. AdditionalInfo: nil,
  1772. },
  1773. {
  1774. Name: metric.KubeResourceQuotaStatusUsedResourceLimits,
  1775. Labels: map[string]string{
  1776. source.UIDLabel: "uuid1",
  1777. source.NamespaceUIDLabel: "",
  1778. source.ResourceQuotaLabel: "resourceQuota1",
  1779. source.ResourceLabel: "memory",
  1780. source.UnitLabel: "byte",
  1781. },
  1782. Value: 1024,
  1783. AdditionalInfo: nil,
  1784. },
  1785. },
  1786. },
  1787. {
  1788. name: "with namespace index",
  1789. nsSetup: func(nsIndex map[string]types.UID) {
  1790. nsIndex["namespace1"] = "ns-uuid1"
  1791. },
  1792. scrapes: []scrape{
  1793. {
  1794. ResourceQuotas: []*clustercache.ResourceQuota{
  1795. {
  1796. Name: "resourceQuota1",
  1797. Namespace: "namespace1",
  1798. UID: "uuid1",
  1799. Spec: v1.ResourceQuotaSpec{
  1800. Hard: v1.ResourceList{
  1801. v1.ResourceRequestsCPU: resource.MustParse("1"),
  1802. },
  1803. },
  1804. },
  1805. },
  1806. Timestamp: start1,
  1807. },
  1808. },
  1809. expected: []metric.Update{
  1810. {
  1811. Name: metric.ResourceQuotaInfo,
  1812. Labels: map[string]string{
  1813. source.UIDLabel: "uuid1",
  1814. source.NamespaceUIDLabel: "ns-uuid1",
  1815. source.ResourceQuotaLabel: "resourceQuota1",
  1816. },
  1817. Value: 0,
  1818. AdditionalInfo: map[string]string{
  1819. source.UIDLabel: "uuid1",
  1820. source.NamespaceUIDLabel: "ns-uuid1",
  1821. source.ResourceQuotaLabel: "resourceQuota1",
  1822. },
  1823. },
  1824. {
  1825. Name: metric.KubeResourceQuotaSpecResourceRequests,
  1826. Labels: map[string]string{
  1827. source.UIDLabel: "uuid1",
  1828. source.NamespaceUIDLabel: "ns-uuid1",
  1829. source.ResourceQuotaLabel: "resourceQuota1",
  1830. source.ResourceLabel: "cpu",
  1831. source.UnitLabel: "core",
  1832. },
  1833. Value: 1,
  1834. AdditionalInfo: nil,
  1835. },
  1836. },
  1837. },
  1838. }
  1839. for _, tt := range tests {
  1840. t.Run(tt.name, func(t *testing.T) {
  1841. ks := &ClusterCacheScraper{}
  1842. nsIndex := make(map[string]types.UID, 0)
  1843. if tt.nsSetup != nil {
  1844. tt.nsSetup(nsIndex)
  1845. }
  1846. var scrapeResults []metric.Update
  1847. for _, s := range tt.scrapes {
  1848. res := ks.scrapeResourceQuotas(s.ResourceQuotas, nsIndex)
  1849. scrapeResults = append(scrapeResults, res...)
  1850. }
  1851. if len(scrapeResults) != len(tt.expected) {
  1852. t.Errorf("Expected result length of %d, got %d", len(tt.expected), len(scrapeResults))
  1853. }
  1854. for i, expected := range tt.expected {
  1855. got := scrapeResults[i]
  1856. if !reflect.DeepEqual(expected, got) {
  1857. t.Errorf("Result did not match expected at index %d: got %v, want %v", i, got, expected)
  1858. }
  1859. }
  1860. })
  1861. }
  1862. }
  1863. func Test_kubernetesScraper_scrapeDaemonSets(t *testing.T) {
  1864. start1, _ := time.Parse(time.RFC3339, Start1Str)
  1865. type scrape struct {
  1866. DaemonSets []*clustercache.DaemonSet
  1867. Timestamp time.Time
  1868. }
  1869. tests := []struct {
  1870. name string
  1871. nsSetup func(map[string]types.UID)
  1872. scrapes []scrape
  1873. expected []metric.Update
  1874. }{
  1875. {
  1876. name: "simple",
  1877. scrapes: []scrape{
  1878. {
  1879. DaemonSets: []*clustercache.DaemonSet{
  1880. {
  1881. Name: "daemonSet1",
  1882. Namespace: "namespace1",
  1883. UID: "uuid1",
  1884. },
  1885. },
  1886. Timestamp: start1,
  1887. },
  1888. },
  1889. expected: []metric.Update{
  1890. {
  1891. Name: metric.DaemonSetInfo,
  1892. Labels: map[string]string{
  1893. source.UIDLabel: "uuid1",
  1894. source.NamespaceUIDLabel: "",
  1895. source.DaemonSetLabel: "daemonSet1",
  1896. },
  1897. Value: 0,
  1898. AdditionalInfo: map[string]string{
  1899. source.UIDLabel: "uuid1",
  1900. source.NamespaceUIDLabel: "",
  1901. source.DaemonSetLabel: "daemonSet1",
  1902. },
  1903. },
  1904. {
  1905. Name: metric.DaemonSetLabels,
  1906. Labels: map[string]string{
  1907. source.UIDLabel: "uuid1",
  1908. source.NamespaceUIDLabel: "",
  1909. source.DaemonSetLabel: "daemonSet1",
  1910. },
  1911. Value: 0,
  1912. AdditionalInfo: map[string]string{},
  1913. },
  1914. {
  1915. Name: metric.DaemonSetAnnotations,
  1916. Labels: map[string]string{
  1917. source.UIDLabel: "uuid1",
  1918. source.NamespaceUIDLabel: "",
  1919. source.DaemonSetLabel: "daemonSet1",
  1920. },
  1921. Value: 0,
  1922. AdditionalInfo: map[string]string{},
  1923. },
  1924. },
  1925. },
  1926. {
  1927. name: "with namespace index",
  1928. nsSetup: func(nsIndex map[string]types.UID) {
  1929. nsIndex["namespace1"] = "ns-uuid1"
  1930. },
  1931. scrapes: []scrape{
  1932. {
  1933. DaemonSets: []*clustercache.DaemonSet{
  1934. {
  1935. Name: "daemonSet1",
  1936. Namespace: "namespace1",
  1937. UID: "uuid1",
  1938. },
  1939. },
  1940. Timestamp: start1,
  1941. },
  1942. },
  1943. expected: []metric.Update{
  1944. {
  1945. Name: metric.DaemonSetInfo,
  1946. Labels: map[string]string{
  1947. source.UIDLabel: "uuid1",
  1948. source.NamespaceUIDLabel: "ns-uuid1",
  1949. source.DaemonSetLabel: "daemonSet1",
  1950. },
  1951. Value: 0,
  1952. AdditionalInfo: map[string]string{
  1953. source.UIDLabel: "uuid1",
  1954. source.NamespaceUIDLabel: "ns-uuid1",
  1955. source.DaemonSetLabel: "daemonSet1",
  1956. },
  1957. },
  1958. {
  1959. Name: metric.DaemonSetLabels,
  1960. Labels: map[string]string{
  1961. source.UIDLabel: "uuid1",
  1962. source.NamespaceUIDLabel: "ns-uuid1",
  1963. source.DaemonSetLabel: "daemonSet1",
  1964. },
  1965. Value: 0,
  1966. AdditionalInfo: map[string]string{},
  1967. },
  1968. {
  1969. Name: metric.DaemonSetAnnotations,
  1970. Labels: map[string]string{
  1971. source.UIDLabel: "uuid1",
  1972. source.NamespaceUIDLabel: "ns-uuid1",
  1973. source.DaemonSetLabel: "daemonSet1",
  1974. },
  1975. Value: 0,
  1976. AdditionalInfo: map[string]string{},
  1977. },
  1978. },
  1979. },
  1980. }
  1981. for _, tt := range tests {
  1982. t.Run(tt.name, func(t *testing.T) {
  1983. ks := &ClusterCacheScraper{}
  1984. nsIndex := make(map[string]types.UID, 0)
  1985. if tt.nsSetup != nil {
  1986. tt.nsSetup(nsIndex)
  1987. }
  1988. var scrapeResults []metric.Update
  1989. for _, s := range tt.scrapes {
  1990. res := ks.scrapeDaemonSets(s.DaemonSets, nsIndex)
  1991. scrapeResults = append(scrapeResults, res...)
  1992. }
  1993. if len(scrapeResults) != len(tt.expected) {
  1994. t.Errorf("Expected result length of %d, got %d", len(tt.expected), len(scrapeResults))
  1995. }
  1996. for i, expected := range tt.expected {
  1997. got := scrapeResults[i]
  1998. if !reflect.DeepEqual(expected, got) {
  1999. t.Errorf("Result did not match expected at index %d: got %v, want %v", i, got, expected)
  2000. }
  2001. }
  2002. })
  2003. }
  2004. }
  2005. func Test_kubernetesScraper_scrapeJobs(t *testing.T) {
  2006. start1, _ := time.Parse(time.RFC3339, Start1Str)
  2007. type scrape struct {
  2008. Jobs []*clustercache.Job
  2009. Timestamp time.Time
  2010. }
  2011. tests := []struct {
  2012. name string
  2013. nsSetup func(map[string]types.UID)
  2014. scrapes []scrape
  2015. expected []metric.Update
  2016. }{
  2017. {
  2018. name: "simple",
  2019. scrapes: []scrape{
  2020. {
  2021. Jobs: []*clustercache.Job{
  2022. {
  2023. Name: "job1",
  2024. Namespace: "namespace1",
  2025. UID: "uuid1",
  2026. },
  2027. },
  2028. Timestamp: start1,
  2029. },
  2030. },
  2031. expected: []metric.Update{
  2032. {
  2033. Name: metric.JobInfo,
  2034. Labels: map[string]string{
  2035. source.UIDLabel: "uuid1",
  2036. source.NamespaceUIDLabel: "",
  2037. source.JobLabel: "job1",
  2038. },
  2039. Value: 0,
  2040. AdditionalInfo: map[string]string{
  2041. source.UIDLabel: "uuid1",
  2042. source.NamespaceUIDLabel: "",
  2043. source.JobLabel: "job1",
  2044. },
  2045. },
  2046. {
  2047. Name: metric.JobLabels,
  2048. Labels: map[string]string{
  2049. source.UIDLabel: "uuid1",
  2050. source.NamespaceUIDLabel: "",
  2051. source.JobLabel: "job1",
  2052. },
  2053. Value: 0,
  2054. AdditionalInfo: map[string]string{},
  2055. },
  2056. {
  2057. Name: metric.JobAnnotations,
  2058. Labels: map[string]string{
  2059. source.UIDLabel: "uuid1",
  2060. source.NamespaceUIDLabel: "",
  2061. source.JobLabel: "job1",
  2062. },
  2063. Value: 0,
  2064. AdditionalInfo: map[string]string{},
  2065. },
  2066. },
  2067. },
  2068. {
  2069. name: "with namespace index",
  2070. nsSetup: func(nsIndex map[string]types.UID) {
  2071. nsIndex["namespace1"] = "ns-uuid1"
  2072. },
  2073. scrapes: []scrape{
  2074. {
  2075. Jobs: []*clustercache.Job{
  2076. {
  2077. Name: "job1",
  2078. Namespace: "namespace1",
  2079. UID: "uuid1",
  2080. },
  2081. },
  2082. Timestamp: start1,
  2083. },
  2084. },
  2085. expected: []metric.Update{
  2086. {
  2087. Name: metric.JobInfo,
  2088. Labels: map[string]string{
  2089. source.UIDLabel: "uuid1",
  2090. source.NamespaceUIDLabel: "ns-uuid1",
  2091. source.JobLabel: "job1",
  2092. },
  2093. Value: 0,
  2094. AdditionalInfo: map[string]string{
  2095. source.UIDLabel: "uuid1",
  2096. source.NamespaceUIDLabel: "ns-uuid1",
  2097. source.JobLabel: "job1",
  2098. },
  2099. },
  2100. {
  2101. Name: metric.JobLabels,
  2102. Labels: map[string]string{
  2103. source.UIDLabel: "uuid1",
  2104. source.NamespaceUIDLabel: "ns-uuid1",
  2105. source.JobLabel: "job1",
  2106. },
  2107. Value: 0,
  2108. AdditionalInfo: map[string]string{},
  2109. },
  2110. {
  2111. Name: metric.JobAnnotations,
  2112. Labels: map[string]string{
  2113. source.UIDLabel: "uuid1",
  2114. source.NamespaceUIDLabel: "ns-uuid1",
  2115. source.JobLabel: "job1",
  2116. },
  2117. Value: 0,
  2118. AdditionalInfo: map[string]string{},
  2119. },
  2120. },
  2121. },
  2122. }
  2123. for _, tt := range tests {
  2124. t.Run(tt.name, func(t *testing.T) {
  2125. ks := &ClusterCacheScraper{}
  2126. nsIndex := make(map[string]types.UID, 0)
  2127. if tt.nsSetup != nil {
  2128. tt.nsSetup(nsIndex)
  2129. }
  2130. var scrapeResults []metric.Update
  2131. for _, s := range tt.scrapes {
  2132. res := ks.scrapeJobs(s.Jobs, nsIndex)
  2133. scrapeResults = append(scrapeResults, res...)
  2134. }
  2135. if len(scrapeResults) != len(tt.expected) {
  2136. t.Errorf("Expected result length of %d, got %d", len(tt.expected), len(scrapeResults))
  2137. }
  2138. for i, expected := range tt.expected {
  2139. got := scrapeResults[i]
  2140. if !reflect.DeepEqual(expected, got) {
  2141. t.Errorf("Result did not match expected at index %d: got %v, want %v", i, got, expected)
  2142. }
  2143. }
  2144. })
  2145. }
  2146. }
  2147. func Test_kubernetesScraper_scrapeCronJobs(t *testing.T) {
  2148. start1, _ := time.Parse(time.RFC3339, Start1Str)
  2149. type scrape struct {
  2150. CronJobs []*clustercache.CronJob
  2151. Timestamp time.Time
  2152. }
  2153. tests := []struct {
  2154. name string
  2155. nsSetup func(map[string]types.UID)
  2156. scrapes []scrape
  2157. expected []metric.Update
  2158. }{
  2159. {
  2160. name: "simple",
  2161. scrapes: []scrape{
  2162. {
  2163. CronJobs: []*clustercache.CronJob{
  2164. {
  2165. Name: "cronJob1",
  2166. Namespace: "namespace1",
  2167. UID: "uuid1",
  2168. },
  2169. },
  2170. Timestamp: start1,
  2171. },
  2172. },
  2173. expected: []metric.Update{
  2174. {
  2175. Name: metric.CronJobInfo,
  2176. Labels: map[string]string{
  2177. source.UIDLabel: "uuid1",
  2178. source.NamespaceUIDLabel: "",
  2179. source.CronJobLabel: "cronJob1",
  2180. },
  2181. Value: 0,
  2182. AdditionalInfo: map[string]string{
  2183. source.UIDLabel: "uuid1",
  2184. source.NamespaceUIDLabel: "",
  2185. source.CronJobLabel: "cronJob1",
  2186. },
  2187. },
  2188. {
  2189. Name: metric.CronJobLabels,
  2190. Labels: map[string]string{
  2191. source.UIDLabel: "uuid1",
  2192. source.NamespaceUIDLabel: "",
  2193. source.CronJobLabel: "cronJob1",
  2194. },
  2195. Value: 0,
  2196. AdditionalInfo: map[string]string{},
  2197. },
  2198. {
  2199. Name: metric.CronJobAnnotations,
  2200. Labels: map[string]string{
  2201. source.UIDLabel: "uuid1",
  2202. source.NamespaceUIDLabel: "",
  2203. source.CronJobLabel: "cronJob1",
  2204. },
  2205. Value: 0,
  2206. AdditionalInfo: map[string]string{},
  2207. },
  2208. },
  2209. },
  2210. {
  2211. name: "with namespace index",
  2212. nsSetup: func(nsIndex map[string]types.UID) {
  2213. nsIndex["namespace1"] = "ns-uuid1"
  2214. },
  2215. scrapes: []scrape{
  2216. {
  2217. CronJobs: []*clustercache.CronJob{
  2218. {
  2219. Name: "cronJob1",
  2220. Namespace: "namespace1",
  2221. UID: "uuid1",
  2222. },
  2223. },
  2224. Timestamp: start1,
  2225. },
  2226. },
  2227. expected: []metric.Update{
  2228. {
  2229. Name: metric.CronJobInfo,
  2230. Labels: map[string]string{
  2231. source.UIDLabel: "uuid1",
  2232. source.NamespaceUIDLabel: "ns-uuid1",
  2233. source.CronJobLabel: "cronJob1",
  2234. },
  2235. Value: 0,
  2236. AdditionalInfo: map[string]string{
  2237. source.UIDLabel: "uuid1",
  2238. source.NamespaceUIDLabel: "ns-uuid1",
  2239. source.CronJobLabel: "cronJob1",
  2240. },
  2241. },
  2242. {
  2243. Name: metric.CronJobLabels,
  2244. Labels: map[string]string{
  2245. source.UIDLabel: "uuid1",
  2246. source.NamespaceUIDLabel: "ns-uuid1",
  2247. source.CronJobLabel: "cronJob1",
  2248. },
  2249. Value: 0,
  2250. AdditionalInfo: map[string]string{},
  2251. },
  2252. {
  2253. Name: metric.CronJobAnnotations,
  2254. Labels: map[string]string{
  2255. source.UIDLabel: "uuid1",
  2256. source.NamespaceUIDLabel: "ns-uuid1",
  2257. source.CronJobLabel: "cronJob1",
  2258. },
  2259. Value: 0,
  2260. AdditionalInfo: map[string]string{},
  2261. },
  2262. },
  2263. },
  2264. }
  2265. for _, tt := range tests {
  2266. t.Run(tt.name, func(t *testing.T) {
  2267. ks := &ClusterCacheScraper{}
  2268. nsIndex := make(map[string]types.UID, 0)
  2269. if tt.nsSetup != nil {
  2270. tt.nsSetup(nsIndex)
  2271. }
  2272. var scrapeResults []metric.Update
  2273. for _, s := range tt.scrapes {
  2274. res := ks.scrapeCronJobs(s.CronJobs, nsIndex)
  2275. scrapeResults = append(scrapeResults, res...)
  2276. }
  2277. if len(scrapeResults) != len(tt.expected) {
  2278. t.Errorf("Expected result length of %d, got %d", len(tt.expected), len(scrapeResults))
  2279. }
  2280. for i, expected := range tt.expected {
  2281. got := scrapeResults[i]
  2282. if !reflect.DeepEqual(expected, got) {
  2283. t.Errorf("Result did not match expected at index %d: got %v, want %v", i, got, expected)
  2284. }
  2285. }
  2286. })
  2287. }
  2288. }