clustercache_test.go 68 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520
  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.ControllerLabel: "false",
  555. },
  556. Value: 0,
  557. AdditionalInfo: map[string]string{
  558. source.UIDLabel: "uuid1",
  559. source.PodLabel: "pod1",
  560. source.NamespaceUIDLabel: "",
  561. source.NodeUIDLabel: "",
  562. source.NamespaceLabel: "namespace1",
  563. source.NodeLabel: "node1",
  564. source.InstanceLabel: "node1",
  565. source.OwnerKindLabel: "deployment",
  566. source.OwnerNameLabel: "deployment1",
  567. source.OwnerUIDLabel: "",
  568. source.ControllerLabel: "false",
  569. },
  570. },
  571. {
  572. Name: metric.KubePodContainerStatusRunning,
  573. Labels: map[string]string{
  574. source.UIDLabel: "uuid1",
  575. source.PodLabel: "pod1",
  576. source.NamespaceUIDLabel: "",
  577. source.NodeUIDLabel: "",
  578. source.NamespaceLabel: "namespace1",
  579. source.NodeLabel: "node1",
  580. source.InstanceLabel: "node1",
  581. source.ContainerLabel: "container1",
  582. },
  583. Value: 0,
  584. AdditionalInfo: map[string]string{
  585. source.UIDLabel: "uuid1",
  586. source.PodLabel: "pod1",
  587. source.NamespaceUIDLabel: "",
  588. source.NodeUIDLabel: "",
  589. source.NamespaceLabel: "namespace1",
  590. source.NodeLabel: "node1",
  591. source.InstanceLabel: "node1",
  592. source.ContainerLabel: "container1",
  593. },
  594. },
  595. {
  596. Name: metric.KubePodContainerResourceRequests,
  597. Labels: map[string]string{
  598. source.UIDLabel: "uuid1",
  599. source.PodLabel: "pod1",
  600. source.NamespaceUIDLabel: "",
  601. source.NodeUIDLabel: "",
  602. source.NamespaceLabel: "namespace1",
  603. source.NodeLabel: "node1",
  604. source.InstanceLabel: "node1",
  605. source.ContainerLabel: "container1",
  606. source.ResourceLabel: "cpu",
  607. source.UnitLabel: "core",
  608. },
  609. Value: 0.5,
  610. AdditionalInfo: nil,
  611. },
  612. {
  613. Name: metric.KubePodContainerResourceRequests,
  614. Labels: map[string]string{
  615. source.UIDLabel: "uuid1",
  616. source.PodLabel: "pod1",
  617. source.NamespaceUIDLabel: "",
  618. source.NodeUIDLabel: "",
  619. source.NamespaceLabel: "namespace1",
  620. source.NodeLabel: "node1",
  621. source.InstanceLabel: "node1",
  622. source.ContainerLabel: "container1",
  623. source.ResourceLabel: "memory",
  624. source.UnitLabel: "byte",
  625. },
  626. Value: 512,
  627. AdditionalInfo: nil,
  628. },
  629. {
  630. Name: metric.KubePodContainerResourceLimits,
  631. Labels: map[string]string{
  632. source.UIDLabel: "uuid1",
  633. source.PodLabel: "pod1",
  634. source.NamespaceUIDLabel: "",
  635. source.NodeUIDLabel: "",
  636. source.NamespaceLabel: "namespace1",
  637. source.NodeLabel: "node1",
  638. source.InstanceLabel: "node1",
  639. source.ContainerLabel: "container1",
  640. source.ResourceLabel: "cpu",
  641. source.UnitLabel: "core",
  642. },
  643. Value: 1,
  644. AdditionalInfo: nil,
  645. },
  646. {
  647. Name: metric.KubePodContainerResourceLimits,
  648. Labels: map[string]string{
  649. source.UIDLabel: "uuid1",
  650. source.PodLabel: "pod1",
  651. source.NamespaceUIDLabel: "",
  652. source.NodeUIDLabel: "",
  653. source.NamespaceLabel: "namespace1",
  654. source.NodeLabel: "node1",
  655. source.InstanceLabel: "node1",
  656. source.ContainerLabel: "container1",
  657. source.ResourceLabel: "memory",
  658. source.UnitLabel: "byte",
  659. },
  660. Value: 1024,
  661. AdditionalInfo: nil,
  662. },
  663. {
  664. Name: metric.PodPVCAllocation,
  665. Labels: map[string]string{
  666. source.PodLabel: unmountedPVsContainer,
  667. source.NamespaceLabel: "namespace1",
  668. source.PVCLabel: "pvc1",
  669. source.PVLabel: "vol1",
  670. },
  671. Value: 4096,
  672. AdditionalInfo: nil,
  673. },
  674. },
  675. },
  676. {
  677. name: "with namespace index",
  678. nsSetup: func(nsIndex map[string]types.UID) {
  679. nsIndex["namespace1"] = "ns-uuid1"
  680. },
  681. scrapes: []scrape{
  682. {
  683. Pods: []*clustercache.Pod{
  684. {
  685. Name: "pod1",
  686. Namespace: "namespace1",
  687. UID: "uuid1",
  688. Spec: clustercache.PodSpec{
  689. NodeName: "node1",
  690. Containers: []clustercache.Container{
  691. {
  692. Name: "container1",
  693. Resources: v1.ResourceRequirements{
  694. Requests: map[v1.ResourceName]resource.Quantity{
  695. v1.ResourceCPU: resource.MustParse("500m"),
  696. v1.ResourceMemory: resource.MustParse("512"),
  697. },
  698. Limits: map[v1.ResourceName]resource.Quantity{
  699. v1.ResourceCPU: resource.MustParse("1"),
  700. v1.ResourceMemory: resource.MustParse("1024"),
  701. },
  702. },
  703. },
  704. },
  705. },
  706. Status: clustercache.PodStatus{
  707. ContainerStatuses: []v1.ContainerStatus{
  708. {
  709. Name: "container1",
  710. State: v1.ContainerState{
  711. Running: &v1.ContainerStateRunning{},
  712. },
  713. },
  714. },
  715. },
  716. },
  717. },
  718. Timestamp: start1,
  719. },
  720. },
  721. expected: []metric.Update{
  722. {
  723. Name: metric.PodInfo,
  724. Labels: map[string]string{
  725. source.UIDLabel: "uuid1",
  726. source.PodLabel: "pod1",
  727. source.NamespaceUIDLabel: "ns-uuid1",
  728. source.NodeUIDLabel: "",
  729. source.NamespaceLabel: "namespace1",
  730. source.NodeLabel: "node1",
  731. source.InstanceLabel: "node1",
  732. },
  733. Value: 0,
  734. AdditionalInfo: 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. },
  744. {
  745. Name: metric.KubePodLabels,
  746. Labels: map[string]string{
  747. source.UIDLabel: "uuid1",
  748. source.PodLabel: "pod1",
  749. source.NamespaceUIDLabel: "ns-uuid1",
  750. source.NodeUIDLabel: "",
  751. source.NamespaceLabel: "namespace1",
  752. source.NodeLabel: "node1",
  753. source.InstanceLabel: "node1",
  754. },
  755. Value: 0,
  756. AdditionalInfo: map[string]string{},
  757. },
  758. {
  759. Name: metric.KubePodAnnotations,
  760. Labels: map[string]string{
  761. source.UIDLabel: "uuid1",
  762. source.PodLabel: "pod1",
  763. source.NamespaceUIDLabel: "ns-uuid1",
  764. source.NodeUIDLabel: "",
  765. source.NamespaceLabel: "namespace1",
  766. source.NodeLabel: "node1",
  767. source.InstanceLabel: "node1",
  768. },
  769. Value: 0,
  770. AdditionalInfo: map[string]string{},
  771. },
  772. {
  773. Name: metric.KubePodContainerStatusRunning,
  774. Labels: map[string]string{
  775. source.UIDLabel: "uuid1",
  776. source.PodLabel: "pod1",
  777. source.NamespaceUIDLabel: "ns-uuid1",
  778. source.NodeUIDLabel: "",
  779. source.NamespaceLabel: "namespace1",
  780. source.NodeLabel: "node1",
  781. source.InstanceLabel: "node1",
  782. source.ContainerLabel: "container1",
  783. },
  784. Value: 0,
  785. AdditionalInfo: map[string]string{
  786. source.UIDLabel: "uuid1",
  787. source.PodLabel: "pod1",
  788. source.NamespaceUIDLabel: "ns-uuid1",
  789. source.NodeUIDLabel: "",
  790. source.NamespaceLabel: "namespace1",
  791. source.NodeLabel: "node1",
  792. source.InstanceLabel: "node1",
  793. source.ContainerLabel: "container1",
  794. },
  795. },
  796. {
  797. Name: metric.KubePodContainerResourceRequests,
  798. Labels: map[string]string{
  799. source.UIDLabel: "uuid1",
  800. source.PodLabel: "pod1",
  801. source.NamespaceUIDLabel: "ns-uuid1",
  802. source.NodeUIDLabel: "",
  803. source.NamespaceLabel: "namespace1",
  804. source.NodeLabel: "node1",
  805. source.InstanceLabel: "node1",
  806. source.ContainerLabel: "container1",
  807. source.ResourceLabel: "cpu",
  808. source.UnitLabel: "core",
  809. },
  810. Value: 0.5,
  811. AdditionalInfo: nil,
  812. },
  813. {
  814. Name: metric.KubePodContainerResourceRequests,
  815. Labels: map[string]string{
  816. source.UIDLabel: "uuid1",
  817. source.PodLabel: "pod1",
  818. source.NamespaceUIDLabel: "ns-uuid1",
  819. source.NodeUIDLabel: "",
  820. source.NamespaceLabel: "namespace1",
  821. source.NodeLabel: "node1",
  822. source.InstanceLabel: "node1",
  823. source.ContainerLabel: "container1",
  824. source.ResourceLabel: "memory",
  825. source.UnitLabel: "byte",
  826. },
  827. Value: 512,
  828. AdditionalInfo: nil,
  829. },
  830. {
  831. Name: metric.KubePodContainerResourceLimits,
  832. Labels: map[string]string{
  833. source.UIDLabel: "uuid1",
  834. source.PodLabel: "pod1",
  835. source.NamespaceUIDLabel: "ns-uuid1",
  836. source.NodeUIDLabel: "",
  837. source.NamespaceLabel: "namespace1",
  838. source.NodeLabel: "node1",
  839. source.InstanceLabel: "node1",
  840. source.ContainerLabel: "container1",
  841. source.ResourceLabel: "cpu",
  842. source.UnitLabel: "core",
  843. },
  844. Value: 1,
  845. AdditionalInfo: nil,
  846. },
  847. {
  848. Name: metric.KubePodContainerResourceLimits,
  849. Labels: map[string]string{
  850. source.UIDLabel: "uuid1",
  851. source.PodLabel: "pod1",
  852. source.NamespaceUIDLabel: "ns-uuid1",
  853. source.NodeUIDLabel: "",
  854. source.NamespaceLabel: "namespace1",
  855. source.NodeLabel: "node1",
  856. source.InstanceLabel: "node1",
  857. source.ContainerLabel: "container1",
  858. source.ResourceLabel: "memory",
  859. source.UnitLabel: "byte",
  860. },
  861. Value: 1024,
  862. AdditionalInfo: nil,
  863. },
  864. },
  865. },
  866. }
  867. for _, tt := range tests {
  868. t.Run(tt.name, func(t *testing.T) {
  869. ks := &ClusterCacheScraper{}
  870. nodeIndex := make(map[string]types.UID, 0)
  871. nsIndex := make(map[string]types.UID, 0)
  872. if tt.nsSetup != nil {
  873. tt.nsSetup(nsIndex)
  874. }
  875. pvcIndex := make(map[pvcKey]types.UID, 0)
  876. var scrapeResults []metric.Update
  877. for _, s := range tt.scrapes {
  878. res := ks.scrapePods(s.Pods, s.PVCs, nodeIndex, nsIndex, pvcIndex)
  879. scrapeResults = append(scrapeResults, res...)
  880. }
  881. if len(scrapeResults) != len(tt.expected) {
  882. t.Errorf("Expected result length of %d, got %d", len(tt.expected), len(scrapeResults))
  883. }
  884. for i, expected := range tt.expected {
  885. got := scrapeResults[i]
  886. if !reflect.DeepEqual(expected, got) {
  887. t.Errorf("Result did not match expected at index %d: got %v, want %v", i, got, expected)
  888. }
  889. }
  890. })
  891. }
  892. }
  893. func Test_kubernetesScraper_scrapePVCs(t *testing.T) {
  894. start1, _ := time.Parse(time.RFC3339, Start1Str)
  895. type scrape struct {
  896. PVCs []*clustercache.PersistentVolumeClaim
  897. Timestamp time.Time
  898. }
  899. tests := []struct {
  900. name string
  901. nsSetup func(map[string]types.UID)
  902. scrapes []scrape
  903. expected []metric.Update
  904. }{
  905. {
  906. name: "simple",
  907. scrapes: []scrape{
  908. {
  909. PVCs: []*clustercache.PersistentVolumeClaim{
  910. {
  911. Name: "pvc1",
  912. Namespace: "namespace1",
  913. UID: "uuid1",
  914. Spec: v1.PersistentVolumeClaimSpec{
  915. VolumeName: "vol1",
  916. StorageClassName: util.Ptr("storageClass1"),
  917. Resources: v1.VolumeResourceRequirements{
  918. Requests: v1.ResourceList{
  919. v1.ResourceStorage: resource.MustParse("4096"),
  920. },
  921. },
  922. },
  923. },
  924. },
  925. Timestamp: start1,
  926. },
  927. },
  928. expected: []metric.Update{
  929. {
  930. Name: metric.KubePersistentVolumeClaimInfo,
  931. Labels: map[string]string{
  932. source.UIDLabel: "uuid1",
  933. source.PVCLabel: "pvc1",
  934. source.NamespaceUIDLabel: "",
  935. source.NamespaceLabel: "namespace1",
  936. source.VolumeNameLabel: "vol1",
  937. source.PVUIDLabel: "",
  938. source.StorageClassLabel: "storageClass1",
  939. },
  940. Value: 0,
  941. AdditionalInfo: 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. },
  951. {
  952. Name: metric.KubePersistentVolumeClaimResourceRequestsStorageBytes,
  953. Labels: map[string]string{
  954. source.UIDLabel: "uuid1",
  955. source.PVCLabel: "pvc1",
  956. source.NamespaceUIDLabel: "",
  957. source.NamespaceLabel: "namespace1",
  958. source.VolumeNameLabel: "vol1",
  959. source.PVUIDLabel: "",
  960. source.StorageClassLabel: "storageClass1",
  961. },
  962. Value: 4096,
  963. AdditionalInfo: nil,
  964. },
  965. },
  966. },
  967. {
  968. name: "with namespace index",
  969. nsSetup: func(nsIndex map[string]types.UID) {
  970. nsIndex["namespace1"] = "ns-uuid1"
  971. },
  972. scrapes: []scrape{
  973. {
  974. PVCs: []*clustercache.PersistentVolumeClaim{
  975. {
  976. Name: "pvc1",
  977. Namespace: "namespace1",
  978. UID: "uuid1",
  979. Spec: v1.PersistentVolumeClaimSpec{
  980. VolumeName: "vol1",
  981. StorageClassName: util.Ptr("storageClass1"),
  982. Resources: v1.VolumeResourceRequirements{
  983. Requests: v1.ResourceList{
  984. v1.ResourceStorage: resource.MustParse("4096"),
  985. },
  986. },
  987. },
  988. },
  989. },
  990. Timestamp: start1,
  991. },
  992. },
  993. expected: []metric.Update{
  994. {
  995. Name: metric.KubePersistentVolumeClaimInfo,
  996. Labels: map[string]string{
  997. source.UIDLabel: "uuid1",
  998. source.PVCLabel: "pvc1",
  999. source.NamespaceUIDLabel: "ns-uuid1",
  1000. source.NamespaceLabel: "namespace1",
  1001. source.VolumeNameLabel: "vol1",
  1002. source.PVUIDLabel: "",
  1003. source.StorageClassLabel: "storageClass1",
  1004. },
  1005. Value: 0,
  1006. AdditionalInfo: 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. },
  1016. {
  1017. Name: metric.KubePersistentVolumeClaimResourceRequestsStorageBytes,
  1018. Labels: map[string]string{
  1019. source.UIDLabel: "uuid1",
  1020. source.PVCLabel: "pvc1",
  1021. source.NamespaceUIDLabel: "ns-uuid1",
  1022. source.NamespaceLabel: "namespace1",
  1023. source.VolumeNameLabel: "vol1",
  1024. source.PVUIDLabel: "",
  1025. source.StorageClassLabel: "storageClass1",
  1026. },
  1027. Value: 4096,
  1028. AdditionalInfo: nil,
  1029. },
  1030. },
  1031. },
  1032. }
  1033. for _, tt := range tests {
  1034. t.Run(tt.name, func(t *testing.T) {
  1035. ks := &ClusterCacheScraper{}
  1036. nsIndex := make(map[string]types.UID, 0)
  1037. if tt.nsSetup != nil {
  1038. tt.nsSetup(nsIndex)
  1039. }
  1040. pvIndex := make(map[string]types.UID, 0)
  1041. var scrapeResults []metric.Update
  1042. for _, s := range tt.scrapes {
  1043. res := ks.scrapePVCs(s.PVCs, nsIndex, pvIndex)
  1044. scrapeResults = append(scrapeResults, res...)
  1045. }
  1046. if len(scrapeResults) != len(tt.expected) {
  1047. t.Errorf("Expected result length of %d, got %d", len(tt.expected), len(scrapeResults))
  1048. }
  1049. for i, expected := range tt.expected {
  1050. got := scrapeResults[i]
  1051. if !reflect.DeepEqual(expected, got) {
  1052. t.Errorf("Result did not match expected at index %d: got %v, want %v", i, got, expected)
  1053. }
  1054. }
  1055. })
  1056. }
  1057. }
  1058. func Test_kubernetesScraper_scrapePVs(t *testing.T) {
  1059. start1, _ := time.Parse(time.RFC3339, Start1Str)
  1060. type scrape struct {
  1061. PVs []*clustercache.PersistentVolume
  1062. Timestamp time.Time
  1063. }
  1064. tests := []struct {
  1065. name string
  1066. scrapes []scrape
  1067. expected []metric.Update
  1068. }{
  1069. {
  1070. name: "simple",
  1071. scrapes: []scrape{
  1072. {
  1073. PVs: []*clustercache.PersistentVolume{
  1074. {
  1075. Name: "pv1",
  1076. UID: "uuid1",
  1077. Spec: v1.PersistentVolumeSpec{
  1078. StorageClassName: "storageClass1",
  1079. PersistentVolumeSource: v1.PersistentVolumeSource{
  1080. CSI: &v1.CSIPersistentVolumeSource{
  1081. VolumeHandle: "vol-1",
  1082. },
  1083. },
  1084. Capacity: v1.ResourceList{
  1085. v1.ResourceStorage: resource.MustParse("4096"),
  1086. },
  1087. },
  1088. },
  1089. },
  1090. Timestamp: start1,
  1091. },
  1092. },
  1093. expected: []metric.Update{
  1094. {
  1095. Name: metric.KubecostPVInfo,
  1096. Labels: map[string]string{
  1097. source.UIDLabel: "uuid1",
  1098. source.PVLabel: "pv1",
  1099. source.StorageClassLabel: "storageClass1",
  1100. source.ProviderIDLabel: "vol-1",
  1101. source.CSIVolumeHandleLabel: "vol-1",
  1102. },
  1103. Value: 0,
  1104. AdditionalInfo: map[string]string{
  1105. source.UIDLabel: "uuid1",
  1106. source.PVLabel: "pv1",
  1107. source.StorageClassLabel: "storageClass1",
  1108. source.ProviderIDLabel: "vol-1",
  1109. source.CSIVolumeHandleLabel: "vol-1",
  1110. },
  1111. },
  1112. {
  1113. Name: metric.KubePersistentVolumeCapacityBytes,
  1114. Labels: map[string]string{
  1115. source.UIDLabel: "uuid1",
  1116. source.PVLabel: "pv1",
  1117. source.StorageClassLabel: "storageClass1",
  1118. source.ProviderIDLabel: "vol-1",
  1119. source.CSIVolumeHandleLabel: "vol-1",
  1120. },
  1121. Value: 4096,
  1122. AdditionalInfo: nil,
  1123. },
  1124. },
  1125. },
  1126. }
  1127. for _, tt := range tests {
  1128. t.Run(tt.name, func(t *testing.T) {
  1129. ks := &ClusterCacheScraper{}
  1130. var scrapeResults []metric.Update
  1131. for _, s := range tt.scrapes {
  1132. res := ks.scrapePVs(s.PVs)
  1133. scrapeResults = append(scrapeResults, res...)
  1134. }
  1135. if len(scrapeResults) != len(tt.expected) {
  1136. t.Errorf("Expected result length of %d, got %d", len(tt.expected), len(scrapeResults))
  1137. }
  1138. for i, expected := range tt.expected {
  1139. got := scrapeResults[i]
  1140. if !reflect.DeepEqual(expected, got) {
  1141. t.Errorf("Result did not match expected at index %d: got %v, want %v", i, got, expected)
  1142. }
  1143. }
  1144. })
  1145. }
  1146. }
  1147. func Test_kubernetesScraper_scrapeServices(t *testing.T) {
  1148. start1, _ := time.Parse(time.RFC3339, Start1Str)
  1149. type scrape struct {
  1150. Services []*clustercache.Service
  1151. Timestamp time.Time
  1152. }
  1153. tests := []struct {
  1154. name string
  1155. nsSetup func(map[string]types.UID)
  1156. scrapes []scrape
  1157. expected []metric.Update
  1158. }{
  1159. {
  1160. name: "simple",
  1161. scrapes: []scrape{
  1162. {
  1163. Services: []*clustercache.Service{
  1164. {
  1165. Name: "service1",
  1166. Namespace: "namespace1",
  1167. UID: "uuid1",
  1168. SpecSelector: map[string]string{
  1169. "test1": "blah",
  1170. "test2": "blah2",
  1171. },
  1172. },
  1173. },
  1174. Timestamp: start1,
  1175. },
  1176. },
  1177. expected: []metric.Update{
  1178. {
  1179. Name: metric.ServiceInfo,
  1180. Labels: map[string]string{
  1181. source.UIDLabel: "uuid1",
  1182. source.ServiceLabel: "service1",
  1183. source.NamespaceLabel: "namespace1",
  1184. source.NamespaceUIDLabel: "",
  1185. source.ServiceTypeLabel: "",
  1186. source.LBIngressAddress: "",
  1187. },
  1188. Value: 0,
  1189. AdditionalInfo: map[string]string{
  1190. source.UIDLabel: "uuid1",
  1191. source.ServiceLabel: "service1",
  1192. source.NamespaceLabel: "namespace1",
  1193. source.NamespaceUIDLabel: "",
  1194. source.ServiceTypeLabel: "",
  1195. source.LBIngressAddress: "",
  1196. },
  1197. },
  1198. {
  1199. Name: metric.ServiceSelectorLabels,
  1200. Labels: map[string]string{
  1201. source.UIDLabel: "uuid1",
  1202. source.ServiceLabel: "service1",
  1203. source.NamespaceLabel: "namespace1",
  1204. source.NamespaceUIDLabel: "",
  1205. source.ServiceTypeLabel: "",
  1206. source.LBIngressAddress: "",
  1207. },
  1208. Value: 0,
  1209. AdditionalInfo: map[string]string{
  1210. "label_test1": "blah",
  1211. "label_test2": "blah2",
  1212. },
  1213. },
  1214. },
  1215. },
  1216. {
  1217. name: "with namespace index",
  1218. nsSetup: func(nsIndex map[string]types.UID) {
  1219. nsIndex["namespace1"] = "ns-uuid1"
  1220. },
  1221. scrapes: []scrape{
  1222. {
  1223. Services: []*clustercache.Service{
  1224. {
  1225. Name: "service1",
  1226. Namespace: "namespace1",
  1227. UID: "uuid1",
  1228. },
  1229. },
  1230. Timestamp: start1,
  1231. },
  1232. },
  1233. expected: []metric.Update{
  1234. {
  1235. Name: metric.ServiceInfo,
  1236. Labels: map[string]string{
  1237. source.UIDLabel: "uuid1",
  1238. source.ServiceLabel: "service1",
  1239. source.NamespaceLabel: "namespace1",
  1240. source.NamespaceUIDLabel: "ns-uuid1",
  1241. source.ServiceTypeLabel: "",
  1242. source.LBIngressAddress: "",
  1243. },
  1244. Value: 0,
  1245. AdditionalInfo: map[string]string{
  1246. source.UIDLabel: "uuid1",
  1247. source.ServiceLabel: "service1",
  1248. source.NamespaceLabel: "namespace1",
  1249. source.NamespaceUIDLabel: "ns-uuid1",
  1250. source.ServiceTypeLabel: "",
  1251. source.LBIngressAddress: "",
  1252. },
  1253. },
  1254. {
  1255. Name: metric.ServiceSelectorLabels,
  1256. Labels: map[string]string{
  1257. source.UIDLabel: "uuid1",
  1258. source.ServiceLabel: "service1",
  1259. source.NamespaceLabel: "namespace1",
  1260. source.NamespaceUIDLabel: "ns-uuid1",
  1261. source.ServiceTypeLabel: "",
  1262. source.LBIngressAddress: "",
  1263. },
  1264. Value: 0,
  1265. AdditionalInfo: map[string]string{},
  1266. },
  1267. },
  1268. },
  1269. {
  1270. name: "with LB ingress IP",
  1271. nsSetup: func(nsIndex map[string]types.UID) {
  1272. nsIndex["namespace1"] = "ns-uuid1"
  1273. },
  1274. scrapes: []scrape{
  1275. {
  1276. Services: []*clustercache.Service{
  1277. {
  1278. Name: "service1",
  1279. Namespace: "namespace1",
  1280. UID: "uuid1",
  1281. Type: v1.ServiceTypeLoadBalancer,
  1282. Status: v1.ServiceStatus{
  1283. LoadBalancer: v1.LoadBalancerStatus{
  1284. Ingress: []v1.LoadBalancerIngress{
  1285. {IP: "1.2.3.4"},
  1286. },
  1287. },
  1288. },
  1289. },
  1290. },
  1291. Timestamp: start1,
  1292. },
  1293. },
  1294. expected: []metric.Update{
  1295. {
  1296. Name: metric.ServiceInfo,
  1297. Labels: map[string]string{
  1298. source.UIDLabel: "uuid1",
  1299. source.ServiceLabel: "service1",
  1300. source.NamespaceLabel: "namespace1",
  1301. source.NamespaceUIDLabel: "ns-uuid1",
  1302. source.ServiceTypeLabel: "LoadBalancer",
  1303. source.LBIngressAddress: "1.2.3.4",
  1304. },
  1305. Value: 0,
  1306. AdditionalInfo: map[string]string{
  1307. source.UIDLabel: "uuid1",
  1308. source.ServiceLabel: "service1",
  1309. source.NamespaceLabel: "namespace1",
  1310. source.NamespaceUIDLabel: "ns-uuid1",
  1311. source.ServiceTypeLabel: "LoadBalancer",
  1312. source.LBIngressAddress: "1.2.3.4",
  1313. },
  1314. },
  1315. {
  1316. Name: metric.ServiceSelectorLabels,
  1317. Labels: map[string]string{
  1318. source.UIDLabel: "uuid1",
  1319. source.ServiceLabel: "service1",
  1320. source.NamespaceLabel: "namespace1",
  1321. source.NamespaceUIDLabel: "ns-uuid1",
  1322. source.ServiceTypeLabel: "LoadBalancer",
  1323. source.LBIngressAddress: "1.2.3.4",
  1324. },
  1325. Value: 0,
  1326. AdditionalInfo: map[string]string{},
  1327. },
  1328. },
  1329. },
  1330. }
  1331. for _, tt := range tests {
  1332. t.Run(tt.name, func(t *testing.T) {
  1333. ks := &ClusterCacheScraper{}
  1334. nsIndex := make(map[string]types.UID)
  1335. if tt.nsSetup != nil {
  1336. tt.nsSetup(nsIndex)
  1337. }
  1338. var scrapeResults []metric.Update
  1339. for _, s := range tt.scrapes {
  1340. res := ks.scrapeServices(s.Services, nsIndex)
  1341. scrapeResults = append(scrapeResults, res...)
  1342. }
  1343. if len(scrapeResults) != len(tt.expected) {
  1344. t.Errorf("Expected result length of %d, got %d", len(tt.expected), len(scrapeResults))
  1345. }
  1346. for i, expected := range tt.expected {
  1347. got := scrapeResults[i]
  1348. if !reflect.DeepEqual(expected, got) {
  1349. t.Errorf("Result did not match expected at index %d: got %v, want %v", i, got, expected)
  1350. }
  1351. }
  1352. })
  1353. }
  1354. }
  1355. func Test_kubernetesScraper_scrapeStatefulSets(t *testing.T) {
  1356. start1, _ := time.Parse(time.RFC3339, Start1Str)
  1357. type scrape struct {
  1358. StatefulSets []*clustercache.StatefulSet
  1359. Timestamp time.Time
  1360. }
  1361. tests := []struct {
  1362. name string
  1363. nsSetup func(map[string]types.UID)
  1364. scrapes []scrape
  1365. expected []metric.Update
  1366. }{
  1367. {
  1368. name: "simple",
  1369. scrapes: []scrape{
  1370. {
  1371. StatefulSets: []*clustercache.StatefulSet{
  1372. {
  1373. Name: "statefulSet1",
  1374. Namespace: "namespace1",
  1375. UID: "uuid1",
  1376. SpecSelector: &metav1.LabelSelector{
  1377. MatchLabels: map[string]string{
  1378. "test1": "blah",
  1379. "test2": "blah2",
  1380. },
  1381. },
  1382. },
  1383. },
  1384. Timestamp: start1,
  1385. },
  1386. },
  1387. // statefulSetInfo map is shared across all 4 metrics; namespace is added
  1388. // before StatefulSetMatchLabels is appended, so all 4 reflect the final state.
  1389. expected: []metric.Update{
  1390. {
  1391. Name: metric.StatefulSetInfo,
  1392. Labels: map[string]string{
  1393. source.UIDLabel: "uuid1",
  1394. source.NamespaceUIDLabel: "",
  1395. source.StatefulSetLabel: "statefulSet1",
  1396. source.NamespaceLabel: "namespace1",
  1397. },
  1398. Value: 0,
  1399. AdditionalInfo: map[string]string{
  1400. source.UIDLabel: "uuid1",
  1401. source.NamespaceUIDLabel: "",
  1402. source.StatefulSetLabel: "statefulSet1",
  1403. source.NamespaceLabel: "namespace1",
  1404. },
  1405. },
  1406. {
  1407. Name: metric.StatefulSetLabels,
  1408. Labels: map[string]string{
  1409. source.UIDLabel: "uuid1",
  1410. source.NamespaceUIDLabel: "",
  1411. source.StatefulSetLabel: "statefulSet1",
  1412. source.NamespaceLabel: "namespace1",
  1413. },
  1414. Value: 0,
  1415. AdditionalInfo: map[string]string{},
  1416. },
  1417. {
  1418. Name: metric.StatefulSetAnnotations,
  1419. Labels: map[string]string{
  1420. source.UIDLabel: "uuid1",
  1421. source.NamespaceUIDLabel: "",
  1422. source.StatefulSetLabel: "statefulSet1",
  1423. source.NamespaceLabel: "namespace1",
  1424. },
  1425. Value: 0,
  1426. AdditionalInfo: map[string]string{},
  1427. },
  1428. {
  1429. Name: metric.StatefulSetMatchLabels,
  1430. Labels: map[string]string{
  1431. source.UIDLabel: "uuid1",
  1432. source.NamespaceUIDLabel: "",
  1433. source.StatefulSetLabel: "statefulSet1",
  1434. source.NamespaceLabel: "namespace1",
  1435. },
  1436. Value: 0,
  1437. AdditionalInfo: map[string]string{
  1438. "label_test1": "blah",
  1439. "label_test2": "blah2",
  1440. },
  1441. },
  1442. },
  1443. },
  1444. {
  1445. // statefulSetInfo map is shared; NamespaceLabel is added before MatchLabels,
  1446. // so all 4 metrics reflect the final state including namespace_uid.
  1447. name: "with namespace index",
  1448. nsSetup: func(nsIndex map[string]types.UID) {
  1449. nsIndex["namespace1"] = "ns-uuid1"
  1450. },
  1451. scrapes: []scrape{
  1452. {
  1453. StatefulSets: []*clustercache.StatefulSet{
  1454. {
  1455. Name: "statefulSet1",
  1456. Namespace: "namespace1",
  1457. UID: "uuid1",
  1458. SpecSelector: &metav1.LabelSelector{},
  1459. },
  1460. },
  1461. Timestamp: start1,
  1462. },
  1463. },
  1464. expected: []metric.Update{
  1465. {
  1466. Name: metric.StatefulSetInfo,
  1467. Labels: map[string]string{
  1468. source.UIDLabel: "uuid1",
  1469. source.NamespaceUIDLabel: "ns-uuid1",
  1470. source.StatefulSetLabel: "statefulSet1",
  1471. source.NamespaceLabel: "namespace1",
  1472. },
  1473. Value: 0,
  1474. AdditionalInfo: map[string]string{
  1475. source.UIDLabel: "uuid1",
  1476. source.NamespaceUIDLabel: "ns-uuid1",
  1477. source.StatefulSetLabel: "statefulSet1",
  1478. source.NamespaceLabel: "namespace1",
  1479. },
  1480. },
  1481. {
  1482. Name: metric.StatefulSetLabels,
  1483. Labels: map[string]string{
  1484. source.UIDLabel: "uuid1",
  1485. source.NamespaceUIDLabel: "ns-uuid1",
  1486. source.StatefulSetLabel: "statefulSet1",
  1487. source.NamespaceLabel: "namespace1",
  1488. },
  1489. Value: 0,
  1490. AdditionalInfo: map[string]string{},
  1491. },
  1492. {
  1493. Name: metric.StatefulSetAnnotations,
  1494. Labels: map[string]string{
  1495. source.UIDLabel: "uuid1",
  1496. source.NamespaceUIDLabel: "ns-uuid1",
  1497. source.StatefulSetLabel: "statefulSet1",
  1498. source.NamespaceLabel: "namespace1",
  1499. },
  1500. Value: 0,
  1501. AdditionalInfo: map[string]string{},
  1502. },
  1503. {
  1504. Name: metric.StatefulSetMatchLabels,
  1505. Labels: map[string]string{
  1506. source.UIDLabel: "uuid1",
  1507. source.NamespaceUIDLabel: "ns-uuid1",
  1508. source.StatefulSetLabel: "statefulSet1",
  1509. source.NamespaceLabel: "namespace1",
  1510. },
  1511. Value: 0,
  1512. AdditionalInfo: map[string]string{},
  1513. },
  1514. },
  1515. },
  1516. }
  1517. for _, tt := range tests {
  1518. t.Run(tt.name, func(t *testing.T) {
  1519. ks := &ClusterCacheScraper{}
  1520. nsIndex := make(map[string]types.UID, 0)
  1521. if tt.nsSetup != nil {
  1522. tt.nsSetup(nsIndex)
  1523. }
  1524. var scrapeResults []metric.Update
  1525. for _, s := range tt.scrapes {
  1526. res := ks.scrapeStatefulSets(s.StatefulSets, nsIndex)
  1527. scrapeResults = append(scrapeResults, res...)
  1528. }
  1529. if len(scrapeResults) != len(tt.expected) {
  1530. t.Errorf("Expected result length of %d, got %d", len(tt.expected), len(scrapeResults))
  1531. }
  1532. for i, expected := range tt.expected {
  1533. got := scrapeResults[i]
  1534. if !reflect.DeepEqual(expected, got) {
  1535. t.Errorf("Result did not match expected at index %d: got %v, want %v", i, got, expected)
  1536. }
  1537. }
  1538. })
  1539. }
  1540. }
  1541. func Test_kubernetesScraper_scrapeReplicaSets(t *testing.T) {
  1542. start1, _ := time.Parse(time.RFC3339, Start1Str)
  1543. type scrape struct {
  1544. ReplicaSets []*clustercache.ReplicaSet
  1545. Timestamp time.Time
  1546. }
  1547. tests := []struct {
  1548. name string
  1549. nsSetup func(map[string]types.UID)
  1550. scrapes []scrape
  1551. expected []metric.Update
  1552. }{
  1553. {
  1554. name: "simple",
  1555. scrapes: []scrape{
  1556. {
  1557. ReplicaSets: []*clustercache.ReplicaSet{
  1558. {
  1559. Name: "replicaSet1",
  1560. Namespace: "namespace1",
  1561. UID: "uuid1",
  1562. OwnerReferences: []metav1.OwnerReference{
  1563. {
  1564. Name: "rollout1",
  1565. Kind: "Rollout",
  1566. },
  1567. },
  1568. },
  1569. {
  1570. Name: "pureReplicaSet",
  1571. Namespace: "namespace1",
  1572. UID: "uuid2",
  1573. OwnerReferences: []metav1.OwnerReference{},
  1574. },
  1575. },
  1576. Timestamp: start1,
  1577. },
  1578. },
  1579. expected: []metric.Update{
  1580. // replicaSet1: info/labels/annotations use replicaSetInfo (uid, namespace_uid, replicaset)
  1581. {
  1582. Name: metric.ReplicaSetInfo,
  1583. Labels: map[string]string{
  1584. source.UIDLabel: "uuid1",
  1585. source.NamespaceUIDLabel: "",
  1586. source.ReplicaSetLabel: "replicaSet1",
  1587. },
  1588. Value: 0,
  1589. AdditionalInfo: map[string]string{
  1590. source.UIDLabel: "uuid1",
  1591. source.NamespaceUIDLabel: "",
  1592. source.ReplicaSetLabel: "replicaSet1",
  1593. },
  1594. },
  1595. {
  1596. Name: metric.ReplicaSetLabels,
  1597. Labels: map[string]string{
  1598. source.UIDLabel: "uuid1",
  1599. source.NamespaceUIDLabel: "",
  1600. source.ReplicaSetLabel: "replicaSet1",
  1601. },
  1602. Value: 0,
  1603. AdditionalInfo: map[string]string{},
  1604. },
  1605. {
  1606. Name: metric.ReplicaSetAnnotations,
  1607. Labels: map[string]string{
  1608. source.UIDLabel: "uuid1",
  1609. source.NamespaceUIDLabel: "",
  1610. source.ReplicaSetLabel: "replicaSet1",
  1611. },
  1612. Value: 0,
  1613. AdditionalInfo: map[string]string{},
  1614. },
  1615. // replicaSet1 owner: uses replicaSetOwnerInfo (replicaset, namespace, uid) + owner fields
  1616. {
  1617. Name: metric.KubeReplicasetOwner,
  1618. Labels: map[string]string{
  1619. source.ReplicaSetLabel: "replicaSet1",
  1620. source.NamespaceLabel: "namespace1",
  1621. source.UIDLabel: "uuid1",
  1622. source.OwnerNameLabel: "rollout1",
  1623. source.OwnerKindLabel: "Rollout",
  1624. source.OwnerUIDLabel: "",
  1625. source.ControllerLabel: "false",
  1626. },
  1627. Value: 0,
  1628. AdditionalInfo: map[string]string{
  1629. source.ReplicaSetLabel: "replicaSet1",
  1630. source.NamespaceLabel: "namespace1",
  1631. source.UIDLabel: "uuid1",
  1632. source.OwnerNameLabel: "rollout1",
  1633. source.OwnerKindLabel: "Rollout",
  1634. source.OwnerUIDLabel: "",
  1635. source.ControllerLabel: "false",
  1636. },
  1637. },
  1638. // pureReplicaSet: info/labels/annotations
  1639. {
  1640. Name: metric.ReplicaSetInfo,
  1641. Labels: map[string]string{
  1642. source.UIDLabel: "uuid2",
  1643. source.NamespaceUIDLabel: "",
  1644. source.ReplicaSetLabel: "pureReplicaSet",
  1645. },
  1646. Value: 0,
  1647. AdditionalInfo: map[string]string{
  1648. source.UIDLabel: "uuid2",
  1649. source.NamespaceUIDLabel: "",
  1650. source.ReplicaSetLabel: "pureReplicaSet",
  1651. },
  1652. },
  1653. {
  1654. Name: metric.ReplicaSetLabels,
  1655. Labels: map[string]string{
  1656. source.UIDLabel: "uuid2",
  1657. source.NamespaceUIDLabel: "",
  1658. source.ReplicaSetLabel: "pureReplicaSet",
  1659. },
  1660. Value: 0,
  1661. AdditionalInfo: map[string]string{},
  1662. },
  1663. {
  1664. Name: metric.ReplicaSetAnnotations,
  1665. Labels: map[string]string{
  1666. source.UIDLabel: "uuid2",
  1667. source.NamespaceUIDLabel: "",
  1668. source.ReplicaSetLabel: "pureReplicaSet",
  1669. },
  1670. Value: 0,
  1671. AdditionalInfo: map[string]string{},
  1672. },
  1673. // pureReplicaSet owner: no owners path uses <none> sentinel, no owner_uid/controller
  1674. {
  1675. Name: metric.KubeReplicasetOwner,
  1676. Labels: map[string]string{
  1677. source.ReplicaSetLabel: "pureReplicaSet",
  1678. source.NamespaceLabel: "namespace1",
  1679. source.UIDLabel: "uuid2",
  1680. source.OwnerNameLabel: source.NoneLabelValue,
  1681. source.OwnerKindLabel: source.NoneLabelValue,
  1682. source.ControllerLabel: "false",
  1683. },
  1684. Value: 0,
  1685. AdditionalInfo: map[string]string{
  1686. source.ReplicaSetLabel: "pureReplicaSet",
  1687. source.NamespaceLabel: "namespace1",
  1688. source.UIDLabel: "uuid2",
  1689. source.OwnerNameLabel: source.NoneLabelValue,
  1690. source.OwnerKindLabel: source.NoneLabelValue,
  1691. source.ControllerLabel: "false",
  1692. },
  1693. },
  1694. },
  1695. },
  1696. {
  1697. name: "with namespace index",
  1698. nsSetup: func(nsIndex map[string]types.UID) {
  1699. nsIndex["namespace1"] = "ns-uuid1"
  1700. },
  1701. scrapes: []scrape{
  1702. {
  1703. ReplicaSets: []*clustercache.ReplicaSet{
  1704. {
  1705. Name: "replicaSet1",
  1706. Namespace: "namespace1",
  1707. UID: "uuid1",
  1708. OwnerReferences: []metav1.OwnerReference{},
  1709. },
  1710. },
  1711. Timestamp: start1,
  1712. },
  1713. },
  1714. expected: []metric.Update{
  1715. {
  1716. Name: metric.ReplicaSetInfo,
  1717. Labels: map[string]string{
  1718. source.UIDLabel: "uuid1",
  1719. source.NamespaceUIDLabel: "ns-uuid1",
  1720. source.ReplicaSetLabel: "replicaSet1",
  1721. },
  1722. Value: 0,
  1723. AdditionalInfo: map[string]string{
  1724. source.UIDLabel: "uuid1",
  1725. source.NamespaceUIDLabel: "ns-uuid1",
  1726. source.ReplicaSetLabel: "replicaSet1",
  1727. },
  1728. },
  1729. {
  1730. Name: metric.ReplicaSetLabels,
  1731. Labels: map[string]string{
  1732. source.UIDLabel: "uuid1",
  1733. source.NamespaceUIDLabel: "ns-uuid1",
  1734. source.ReplicaSetLabel: "replicaSet1",
  1735. },
  1736. Value: 0,
  1737. AdditionalInfo: map[string]string{},
  1738. },
  1739. {
  1740. Name: metric.ReplicaSetAnnotations,
  1741. Labels: map[string]string{
  1742. source.UIDLabel: "uuid1",
  1743. source.NamespaceUIDLabel: "ns-uuid1",
  1744. source.ReplicaSetLabel: "replicaSet1",
  1745. },
  1746. Value: 0,
  1747. AdditionalInfo: map[string]string{},
  1748. },
  1749. {
  1750. Name: metric.KubeReplicasetOwner,
  1751. Labels: map[string]string{
  1752. source.ReplicaSetLabel: "replicaSet1",
  1753. source.NamespaceLabel: "namespace1",
  1754. source.UIDLabel: "uuid1",
  1755. source.OwnerNameLabel: source.NoneLabelValue,
  1756. source.OwnerKindLabel: source.NoneLabelValue,
  1757. source.ControllerLabel: "false",
  1758. },
  1759. Value: 0,
  1760. AdditionalInfo: map[string]string{
  1761. source.ReplicaSetLabel: "replicaSet1",
  1762. source.NamespaceLabel: "namespace1",
  1763. source.UIDLabel: "uuid1",
  1764. source.OwnerNameLabel: source.NoneLabelValue,
  1765. source.OwnerKindLabel: source.NoneLabelValue,
  1766. source.ControllerLabel: "false",
  1767. },
  1768. },
  1769. },
  1770. },
  1771. }
  1772. for _, tt := range tests {
  1773. t.Run(tt.name, func(t *testing.T) {
  1774. ks := &ClusterCacheScraper{}
  1775. nsIndex := make(map[string]types.UID, 0)
  1776. if tt.nsSetup != nil {
  1777. tt.nsSetup(nsIndex)
  1778. }
  1779. var scrapeResults []metric.Update
  1780. for _, s := range tt.scrapes {
  1781. res := ks.scrapeReplicaSets(s.ReplicaSets, nsIndex)
  1782. scrapeResults = append(scrapeResults, res...)
  1783. }
  1784. if len(scrapeResults) != len(tt.expected) {
  1785. t.Errorf("Expected result length of %d, got %d", len(tt.expected), len(scrapeResults))
  1786. }
  1787. for i, expected := range tt.expected {
  1788. got := scrapeResults[i]
  1789. if !reflect.DeepEqual(expected, got) {
  1790. t.Errorf("Result did not match expected at index %d: got %v, want %v", i, got, expected)
  1791. }
  1792. }
  1793. })
  1794. }
  1795. }
  1796. func Test_kubernetesScraper_scrapeResourceQuotas(t *testing.T) {
  1797. start1, _ := time.Parse(time.RFC3339, Start1Str)
  1798. type scrape struct {
  1799. ResourceQuotas []*clustercache.ResourceQuota
  1800. Timestamp time.Time
  1801. }
  1802. tests := []struct {
  1803. name string
  1804. nsSetup func(map[string]types.UID)
  1805. scrapes []scrape
  1806. expected []metric.Update
  1807. }{
  1808. {
  1809. name: "simple",
  1810. scrapes: []scrape{
  1811. {
  1812. ResourceQuotas: []*clustercache.ResourceQuota{
  1813. {
  1814. Name: "resourceQuota1",
  1815. Namespace: "namespace1",
  1816. UID: "uuid1",
  1817. Spec: v1.ResourceQuotaSpec{
  1818. Hard: v1.ResourceList{
  1819. v1.ResourceRequestsCPU: resource.MustParse("1"),
  1820. v1.ResourceRequestsMemory: resource.MustParse("1024"),
  1821. v1.ResourceLimitsCPU: resource.MustParse("2"),
  1822. v1.ResourceLimitsMemory: resource.MustParse("2048"),
  1823. },
  1824. },
  1825. Status: v1.ResourceQuotaStatus{
  1826. Used: v1.ResourceList{
  1827. v1.ResourceRequestsCPU: resource.MustParse("0.5"),
  1828. v1.ResourceRequestsMemory: resource.MustParse("512"),
  1829. v1.ResourceLimitsCPU: resource.MustParse("1"),
  1830. v1.ResourceLimitsMemory: resource.MustParse("1024"),
  1831. },
  1832. },
  1833. },
  1834. },
  1835. Timestamp: start1,
  1836. },
  1837. },
  1838. expected: []metric.Update{
  1839. {
  1840. Name: metric.ResourceQuotaInfo,
  1841. Labels: map[string]string{
  1842. source.UIDLabel: "uuid1",
  1843. source.NamespaceUIDLabel: "",
  1844. source.ResourceQuotaLabel: "resourceQuota1",
  1845. },
  1846. Value: 0,
  1847. AdditionalInfo: map[string]string{
  1848. source.UIDLabel: "uuid1",
  1849. source.NamespaceUIDLabel: "",
  1850. source.ResourceQuotaLabel: "resourceQuota1",
  1851. },
  1852. },
  1853. {
  1854. Name: metric.KubeResourceQuotaSpecResourceRequests,
  1855. Labels: map[string]string{
  1856. source.UIDLabel: "uuid1",
  1857. source.NamespaceUIDLabel: "",
  1858. source.ResourceQuotaLabel: "resourceQuota1",
  1859. source.ResourceLabel: "cpu",
  1860. source.UnitLabel: "core",
  1861. },
  1862. Value: 1,
  1863. AdditionalInfo: nil,
  1864. },
  1865. {
  1866. Name: metric.KubeResourceQuotaSpecResourceRequests,
  1867. Labels: map[string]string{
  1868. source.UIDLabel: "uuid1",
  1869. source.NamespaceUIDLabel: "",
  1870. source.ResourceQuotaLabel: "resourceQuota1",
  1871. source.ResourceLabel: "memory",
  1872. source.UnitLabel: "byte",
  1873. },
  1874. Value: 1024,
  1875. AdditionalInfo: nil,
  1876. },
  1877. {
  1878. Name: metric.KubeResourceQuotaSpecResourceLimits,
  1879. Labels: map[string]string{
  1880. source.UIDLabel: "uuid1",
  1881. source.NamespaceUIDLabel: "",
  1882. source.ResourceQuotaLabel: "resourceQuota1",
  1883. source.ResourceLabel: "cpu",
  1884. source.UnitLabel: "core",
  1885. },
  1886. Value: 2,
  1887. AdditionalInfo: nil,
  1888. },
  1889. {
  1890. Name: metric.KubeResourceQuotaSpecResourceLimits,
  1891. Labels: map[string]string{
  1892. source.UIDLabel: "uuid1",
  1893. source.NamespaceUIDLabel: "",
  1894. source.ResourceQuotaLabel: "resourceQuota1",
  1895. source.ResourceLabel: "memory",
  1896. source.UnitLabel: "byte",
  1897. },
  1898. Value: 2048,
  1899. AdditionalInfo: nil,
  1900. },
  1901. {
  1902. Name: metric.KubeResourceQuotaStatusUsedResourceRequests,
  1903. Labels: map[string]string{
  1904. source.UIDLabel: "uuid1",
  1905. source.NamespaceUIDLabel: "",
  1906. source.ResourceQuotaLabel: "resourceQuota1",
  1907. source.ResourceLabel: "cpu",
  1908. source.UnitLabel: "core",
  1909. },
  1910. Value: 0.5,
  1911. AdditionalInfo: nil,
  1912. },
  1913. {
  1914. Name: metric.KubeResourceQuotaStatusUsedResourceRequests,
  1915. Labels: map[string]string{
  1916. source.UIDLabel: "uuid1",
  1917. source.NamespaceUIDLabel: "",
  1918. source.ResourceQuotaLabel: "resourceQuota1",
  1919. source.ResourceLabel: "memory",
  1920. source.UnitLabel: "byte",
  1921. },
  1922. Value: 512,
  1923. AdditionalInfo: nil,
  1924. },
  1925. {
  1926. Name: metric.KubeResourceQuotaStatusUsedResourceLimits,
  1927. Labels: map[string]string{
  1928. source.UIDLabel: "uuid1",
  1929. source.NamespaceUIDLabel: "",
  1930. source.ResourceQuotaLabel: "resourceQuota1",
  1931. source.ResourceLabel: "cpu",
  1932. source.UnitLabel: "core",
  1933. },
  1934. Value: 1,
  1935. AdditionalInfo: nil,
  1936. },
  1937. {
  1938. Name: metric.KubeResourceQuotaStatusUsedResourceLimits,
  1939. Labels: map[string]string{
  1940. source.UIDLabel: "uuid1",
  1941. source.NamespaceUIDLabel: "",
  1942. source.ResourceQuotaLabel: "resourceQuota1",
  1943. source.ResourceLabel: "memory",
  1944. source.UnitLabel: "byte",
  1945. },
  1946. Value: 1024,
  1947. AdditionalInfo: nil,
  1948. },
  1949. },
  1950. },
  1951. {
  1952. name: "with namespace index",
  1953. nsSetup: func(nsIndex map[string]types.UID) {
  1954. nsIndex["namespace1"] = "ns-uuid1"
  1955. },
  1956. scrapes: []scrape{
  1957. {
  1958. ResourceQuotas: []*clustercache.ResourceQuota{
  1959. {
  1960. Name: "resourceQuota1",
  1961. Namespace: "namespace1",
  1962. UID: "uuid1",
  1963. Spec: v1.ResourceQuotaSpec{
  1964. Hard: v1.ResourceList{
  1965. v1.ResourceRequestsCPU: resource.MustParse("1"),
  1966. },
  1967. },
  1968. },
  1969. },
  1970. Timestamp: start1,
  1971. },
  1972. },
  1973. expected: []metric.Update{
  1974. {
  1975. Name: metric.ResourceQuotaInfo,
  1976. Labels: map[string]string{
  1977. source.UIDLabel: "uuid1",
  1978. source.NamespaceUIDLabel: "ns-uuid1",
  1979. source.ResourceQuotaLabel: "resourceQuota1",
  1980. },
  1981. Value: 0,
  1982. AdditionalInfo: map[string]string{
  1983. source.UIDLabel: "uuid1",
  1984. source.NamespaceUIDLabel: "ns-uuid1",
  1985. source.ResourceQuotaLabel: "resourceQuota1",
  1986. },
  1987. },
  1988. {
  1989. Name: metric.KubeResourceQuotaSpecResourceRequests,
  1990. Labels: map[string]string{
  1991. source.UIDLabel: "uuid1",
  1992. source.NamespaceUIDLabel: "ns-uuid1",
  1993. source.ResourceQuotaLabel: "resourceQuota1",
  1994. source.ResourceLabel: "cpu",
  1995. source.UnitLabel: "core",
  1996. },
  1997. Value: 1,
  1998. AdditionalInfo: nil,
  1999. },
  2000. },
  2001. },
  2002. }
  2003. for _, tt := range tests {
  2004. t.Run(tt.name, func(t *testing.T) {
  2005. ks := &ClusterCacheScraper{}
  2006. nsIndex := make(map[string]types.UID, 0)
  2007. if tt.nsSetup != nil {
  2008. tt.nsSetup(nsIndex)
  2009. }
  2010. var scrapeResults []metric.Update
  2011. for _, s := range tt.scrapes {
  2012. res := ks.scrapeResourceQuotas(s.ResourceQuotas, nsIndex)
  2013. scrapeResults = append(scrapeResults, res...)
  2014. }
  2015. if len(scrapeResults) != len(tt.expected) {
  2016. t.Errorf("Expected result length of %d, got %d", len(tt.expected), len(scrapeResults))
  2017. }
  2018. for i, expected := range tt.expected {
  2019. got := scrapeResults[i]
  2020. if !reflect.DeepEqual(expected, got) {
  2021. t.Errorf("Result did not match expected at index %d: got %v, want %v", i, got, expected)
  2022. }
  2023. }
  2024. })
  2025. }
  2026. }
  2027. func Test_kubernetesScraper_scrapeDaemonSets(t *testing.T) {
  2028. start1, _ := time.Parse(time.RFC3339, Start1Str)
  2029. type scrape struct {
  2030. DaemonSets []*clustercache.DaemonSet
  2031. Timestamp time.Time
  2032. }
  2033. tests := []struct {
  2034. name string
  2035. nsSetup func(map[string]types.UID)
  2036. scrapes []scrape
  2037. expected []metric.Update
  2038. }{
  2039. {
  2040. name: "simple",
  2041. scrapes: []scrape{
  2042. {
  2043. DaemonSets: []*clustercache.DaemonSet{
  2044. {
  2045. Name: "daemonSet1",
  2046. Namespace: "namespace1",
  2047. UID: "uuid1",
  2048. },
  2049. },
  2050. Timestamp: start1,
  2051. },
  2052. },
  2053. expected: []metric.Update{
  2054. {
  2055. Name: metric.DaemonSetInfo,
  2056. Labels: map[string]string{
  2057. source.UIDLabel: "uuid1",
  2058. source.NamespaceUIDLabel: "",
  2059. source.DaemonSetLabel: "daemonSet1",
  2060. },
  2061. Value: 0,
  2062. AdditionalInfo: map[string]string{
  2063. source.UIDLabel: "uuid1",
  2064. source.NamespaceUIDLabel: "",
  2065. source.DaemonSetLabel: "daemonSet1",
  2066. },
  2067. },
  2068. {
  2069. Name: metric.DaemonSetLabels,
  2070. Labels: map[string]string{
  2071. source.UIDLabel: "uuid1",
  2072. source.NamespaceUIDLabel: "",
  2073. source.DaemonSetLabel: "daemonSet1",
  2074. },
  2075. Value: 0,
  2076. AdditionalInfo: map[string]string{},
  2077. },
  2078. {
  2079. Name: metric.DaemonSetAnnotations,
  2080. Labels: map[string]string{
  2081. source.UIDLabel: "uuid1",
  2082. source.NamespaceUIDLabel: "",
  2083. source.DaemonSetLabel: "daemonSet1",
  2084. },
  2085. Value: 0,
  2086. AdditionalInfo: map[string]string{},
  2087. },
  2088. },
  2089. },
  2090. {
  2091. name: "with namespace index",
  2092. nsSetup: func(nsIndex map[string]types.UID) {
  2093. nsIndex["namespace1"] = "ns-uuid1"
  2094. },
  2095. scrapes: []scrape{
  2096. {
  2097. DaemonSets: []*clustercache.DaemonSet{
  2098. {
  2099. Name: "daemonSet1",
  2100. Namespace: "namespace1",
  2101. UID: "uuid1",
  2102. },
  2103. },
  2104. Timestamp: start1,
  2105. },
  2106. },
  2107. expected: []metric.Update{
  2108. {
  2109. Name: metric.DaemonSetInfo,
  2110. Labels: map[string]string{
  2111. source.UIDLabel: "uuid1",
  2112. source.NamespaceUIDLabel: "ns-uuid1",
  2113. source.DaemonSetLabel: "daemonSet1",
  2114. },
  2115. Value: 0,
  2116. AdditionalInfo: map[string]string{
  2117. source.UIDLabel: "uuid1",
  2118. source.NamespaceUIDLabel: "ns-uuid1",
  2119. source.DaemonSetLabel: "daemonSet1",
  2120. },
  2121. },
  2122. {
  2123. Name: metric.DaemonSetLabels,
  2124. Labels: map[string]string{
  2125. source.UIDLabel: "uuid1",
  2126. source.NamespaceUIDLabel: "ns-uuid1",
  2127. source.DaemonSetLabel: "daemonSet1",
  2128. },
  2129. Value: 0,
  2130. AdditionalInfo: map[string]string{},
  2131. },
  2132. {
  2133. Name: metric.DaemonSetAnnotations,
  2134. Labels: map[string]string{
  2135. source.UIDLabel: "uuid1",
  2136. source.NamespaceUIDLabel: "ns-uuid1",
  2137. source.DaemonSetLabel: "daemonSet1",
  2138. },
  2139. Value: 0,
  2140. AdditionalInfo: map[string]string{},
  2141. },
  2142. },
  2143. },
  2144. }
  2145. for _, tt := range tests {
  2146. t.Run(tt.name, func(t *testing.T) {
  2147. ks := &ClusterCacheScraper{}
  2148. nsIndex := make(map[string]types.UID, 0)
  2149. if tt.nsSetup != nil {
  2150. tt.nsSetup(nsIndex)
  2151. }
  2152. var scrapeResults []metric.Update
  2153. for _, s := range tt.scrapes {
  2154. res := ks.scrapeDaemonSets(s.DaemonSets, nsIndex)
  2155. scrapeResults = append(scrapeResults, res...)
  2156. }
  2157. if len(scrapeResults) != len(tt.expected) {
  2158. t.Errorf("Expected result length of %d, got %d", len(tt.expected), len(scrapeResults))
  2159. }
  2160. for i, expected := range tt.expected {
  2161. got := scrapeResults[i]
  2162. if !reflect.DeepEqual(expected, got) {
  2163. t.Errorf("Result did not match expected at index %d: got %v, want %v", i, got, expected)
  2164. }
  2165. }
  2166. })
  2167. }
  2168. }
  2169. func Test_kubernetesScraper_scrapeJobs(t *testing.T) {
  2170. start1, _ := time.Parse(time.RFC3339, Start1Str)
  2171. type scrape struct {
  2172. Jobs []*clustercache.Job
  2173. Timestamp time.Time
  2174. }
  2175. tests := []struct {
  2176. name string
  2177. nsSetup func(map[string]types.UID)
  2178. scrapes []scrape
  2179. expected []metric.Update
  2180. }{
  2181. {
  2182. name: "simple",
  2183. scrapes: []scrape{
  2184. {
  2185. Jobs: []*clustercache.Job{
  2186. {
  2187. Name: "job1",
  2188. Namespace: "namespace1",
  2189. UID: "uuid1",
  2190. },
  2191. },
  2192. Timestamp: start1,
  2193. },
  2194. },
  2195. expected: []metric.Update{
  2196. {
  2197. Name: metric.JobInfo,
  2198. Labels: map[string]string{
  2199. source.UIDLabel: "uuid1",
  2200. source.NamespaceUIDLabel: "",
  2201. source.JobLabel: "job1",
  2202. },
  2203. Value: 0,
  2204. AdditionalInfo: map[string]string{
  2205. source.UIDLabel: "uuid1",
  2206. source.NamespaceUIDLabel: "",
  2207. source.JobLabel: "job1",
  2208. },
  2209. },
  2210. {
  2211. Name: metric.JobLabels,
  2212. Labels: map[string]string{
  2213. source.UIDLabel: "uuid1",
  2214. source.NamespaceUIDLabel: "",
  2215. source.JobLabel: "job1",
  2216. },
  2217. Value: 0,
  2218. AdditionalInfo: map[string]string{},
  2219. },
  2220. {
  2221. Name: metric.JobAnnotations,
  2222. Labels: map[string]string{
  2223. source.UIDLabel: "uuid1",
  2224. source.NamespaceUIDLabel: "",
  2225. source.JobLabel: "job1",
  2226. },
  2227. Value: 0,
  2228. AdditionalInfo: map[string]string{},
  2229. },
  2230. },
  2231. },
  2232. {
  2233. name: "with namespace index",
  2234. nsSetup: func(nsIndex map[string]types.UID) {
  2235. nsIndex["namespace1"] = "ns-uuid1"
  2236. },
  2237. scrapes: []scrape{
  2238. {
  2239. Jobs: []*clustercache.Job{
  2240. {
  2241. Name: "job1",
  2242. Namespace: "namespace1",
  2243. UID: "uuid1",
  2244. },
  2245. },
  2246. Timestamp: start1,
  2247. },
  2248. },
  2249. expected: []metric.Update{
  2250. {
  2251. Name: metric.JobInfo,
  2252. Labels: map[string]string{
  2253. source.UIDLabel: "uuid1",
  2254. source.NamespaceUIDLabel: "ns-uuid1",
  2255. source.JobLabel: "job1",
  2256. },
  2257. Value: 0,
  2258. AdditionalInfo: map[string]string{
  2259. source.UIDLabel: "uuid1",
  2260. source.NamespaceUIDLabel: "ns-uuid1",
  2261. source.JobLabel: "job1",
  2262. },
  2263. },
  2264. {
  2265. Name: metric.JobLabels,
  2266. Labels: map[string]string{
  2267. source.UIDLabel: "uuid1",
  2268. source.NamespaceUIDLabel: "ns-uuid1",
  2269. source.JobLabel: "job1",
  2270. },
  2271. Value: 0,
  2272. AdditionalInfo: map[string]string{},
  2273. },
  2274. {
  2275. Name: metric.JobAnnotations,
  2276. Labels: map[string]string{
  2277. source.UIDLabel: "uuid1",
  2278. source.NamespaceUIDLabel: "ns-uuid1",
  2279. source.JobLabel: "job1",
  2280. },
  2281. Value: 0,
  2282. AdditionalInfo: map[string]string{},
  2283. },
  2284. },
  2285. },
  2286. }
  2287. for _, tt := range tests {
  2288. t.Run(tt.name, func(t *testing.T) {
  2289. ks := &ClusterCacheScraper{}
  2290. nsIndex := make(map[string]types.UID, 0)
  2291. if tt.nsSetup != nil {
  2292. tt.nsSetup(nsIndex)
  2293. }
  2294. var scrapeResults []metric.Update
  2295. for _, s := range tt.scrapes {
  2296. res := ks.scrapeJobs(s.Jobs, nsIndex)
  2297. scrapeResults = append(scrapeResults, res...)
  2298. }
  2299. if len(scrapeResults) != len(tt.expected) {
  2300. t.Errorf("Expected result length of %d, got %d", len(tt.expected), len(scrapeResults))
  2301. }
  2302. for i, expected := range tt.expected {
  2303. got := scrapeResults[i]
  2304. if !reflect.DeepEqual(expected, got) {
  2305. t.Errorf("Result did not match expected at index %d: got %v, want %v", i, got, expected)
  2306. }
  2307. }
  2308. })
  2309. }
  2310. }
  2311. func Test_kubernetesScraper_scrapeCronJobs(t *testing.T) {
  2312. start1, _ := time.Parse(time.RFC3339, Start1Str)
  2313. type scrape struct {
  2314. CronJobs []*clustercache.CronJob
  2315. Timestamp time.Time
  2316. }
  2317. tests := []struct {
  2318. name string
  2319. nsSetup func(map[string]types.UID)
  2320. scrapes []scrape
  2321. expected []metric.Update
  2322. }{
  2323. {
  2324. name: "simple",
  2325. scrapes: []scrape{
  2326. {
  2327. CronJobs: []*clustercache.CronJob{
  2328. {
  2329. Name: "cronJob1",
  2330. Namespace: "namespace1",
  2331. UID: "uuid1",
  2332. },
  2333. },
  2334. Timestamp: start1,
  2335. },
  2336. },
  2337. expected: []metric.Update{
  2338. {
  2339. Name: metric.CronJobInfo,
  2340. Labels: map[string]string{
  2341. source.UIDLabel: "uuid1",
  2342. source.NamespaceUIDLabel: "",
  2343. source.CronJobLabel: "cronJob1",
  2344. },
  2345. Value: 0,
  2346. AdditionalInfo: map[string]string{
  2347. source.UIDLabel: "uuid1",
  2348. source.NamespaceUIDLabel: "",
  2349. source.CronJobLabel: "cronJob1",
  2350. },
  2351. },
  2352. {
  2353. Name: metric.CronJobLabels,
  2354. Labels: map[string]string{
  2355. source.UIDLabel: "uuid1",
  2356. source.NamespaceUIDLabel: "",
  2357. source.CronJobLabel: "cronJob1",
  2358. },
  2359. Value: 0,
  2360. AdditionalInfo: map[string]string{},
  2361. },
  2362. {
  2363. Name: metric.CronJobAnnotations,
  2364. Labels: map[string]string{
  2365. source.UIDLabel: "uuid1",
  2366. source.NamespaceUIDLabel: "",
  2367. source.CronJobLabel: "cronJob1",
  2368. },
  2369. Value: 0,
  2370. AdditionalInfo: map[string]string{},
  2371. },
  2372. },
  2373. },
  2374. {
  2375. name: "with namespace index",
  2376. nsSetup: func(nsIndex map[string]types.UID) {
  2377. nsIndex["namespace1"] = "ns-uuid1"
  2378. },
  2379. scrapes: []scrape{
  2380. {
  2381. CronJobs: []*clustercache.CronJob{
  2382. {
  2383. Name: "cronJob1",
  2384. Namespace: "namespace1",
  2385. UID: "uuid1",
  2386. },
  2387. },
  2388. Timestamp: start1,
  2389. },
  2390. },
  2391. expected: []metric.Update{
  2392. {
  2393. Name: metric.CronJobInfo,
  2394. Labels: map[string]string{
  2395. source.UIDLabel: "uuid1",
  2396. source.NamespaceUIDLabel: "ns-uuid1",
  2397. source.CronJobLabel: "cronJob1",
  2398. },
  2399. Value: 0,
  2400. AdditionalInfo: map[string]string{
  2401. source.UIDLabel: "uuid1",
  2402. source.NamespaceUIDLabel: "ns-uuid1",
  2403. source.CronJobLabel: "cronJob1",
  2404. },
  2405. },
  2406. {
  2407. Name: metric.CronJobLabels,
  2408. Labels: map[string]string{
  2409. source.UIDLabel: "uuid1",
  2410. source.NamespaceUIDLabel: "ns-uuid1",
  2411. source.CronJobLabel: "cronJob1",
  2412. },
  2413. Value: 0,
  2414. AdditionalInfo: map[string]string{},
  2415. },
  2416. {
  2417. Name: metric.CronJobAnnotations,
  2418. Labels: map[string]string{
  2419. source.UIDLabel: "uuid1",
  2420. source.NamespaceUIDLabel: "ns-uuid1",
  2421. source.CronJobLabel: "cronJob1",
  2422. },
  2423. Value: 0,
  2424. AdditionalInfo: map[string]string{},
  2425. },
  2426. },
  2427. },
  2428. }
  2429. for _, tt := range tests {
  2430. t.Run(tt.name, func(t *testing.T) {
  2431. ks := &ClusterCacheScraper{}
  2432. nsIndex := make(map[string]types.UID, 0)
  2433. if tt.nsSetup != nil {
  2434. tt.nsSetup(nsIndex)
  2435. }
  2436. var scrapeResults []metric.Update
  2437. for _, s := range tt.scrapes {
  2438. res := ks.scrapeCronJobs(s.CronJobs, nsIndex)
  2439. scrapeResults = append(scrapeResults, res...)
  2440. }
  2441. if len(scrapeResults) != len(tt.expected) {
  2442. t.Errorf("Expected result length of %d, got %d", len(tt.expected), len(scrapeResults))
  2443. }
  2444. for i, expected := range tt.expected {
  2445. got := scrapeResults[i]
  2446. if !reflect.DeepEqual(expected, got) {
  2447. t.Errorf("Result did not match expected at index %d: got %v, want %v", i, got, expected)
  2448. }
  2449. }
  2450. })
  2451. }
  2452. }