1
1
package kubernetes
2
2
3
3
import (
4
+ "bytes"
4
5
"context"
5
6
"encoding/json"
7
+ "github.com/cloudability/metrics-agent/retrieval/k8s"
6
8
"net/http"
7
9
"net/http/httptest"
8
10
"os"
@@ -268,12 +270,12 @@ func TestCollectMetrics(t *testing.T) {
268
270
ka .NodeMetrics .SetAvailability (NodeStatsSummaryEndpoint , Direct , true )
269
271
270
272
stopCh := make (chan struct {})
271
- ka .Informers , err = getMockInformers (ka .ClusterVersion .version , stopCh )
273
+ ka .Informers , err = getMockInformers (ka .ClusterVersion .version , false , stopCh )
272
274
if err != nil {
273
275
t .Error (err )
274
276
}
275
277
parseStopCh := make (chan struct {})
276
- parseInformers , err := getMockInformers (1.22 , parseStopCh )
278
+ parseInformers , err := getMockInformers (1.22 , true , parseStopCh )
277
279
if err != nil {
278
280
t .Error (err )
279
281
}
@@ -364,7 +366,7 @@ func TestCollectMetrics(t *testing.T) {
364
366
}
365
367
})
366
368
t .Run ("Ensure collection occurs with parseMetrics is disabled" +
367
- " ensure sensitive data is not stripped" , func (t * testing.T ) {
369
+ " ensure only expected data is stripped" , func (t * testing.T ) {
368
370
369
371
filepath .Walk (ka .msExportDirectory .Name (), func (path string , info os.FileInfo , err error ) error {
370
372
if err != nil {
@@ -376,30 +378,51 @@ func TestCollectMetrics(t *testing.T) {
376
378
t .Error (err )
377
379
}
378
380
if strings .Contains (info .Name (), "pods" ) {
379
- // check if secrets were not stripped from pods if parseMetrics is false
380
- if ! strings .Contains (string (in ), "ReallySecretStuff" ) {
381
- t .Error ("Original file should have contained secret, but did not" )
381
+ // check if secrets were still stripped from pods if parseMetrics is false
382
+ if strings .Contains (string (in ), "ReallySecretStuff" ) {
383
+ t .Error ("file should not have contained secret, but did" )
384
+ }
385
+ if ! strings .Contains (string (in ), "\" imagePullPolicy\" :\" Always\" " ) {
386
+ t .Error ("file should have contained imagePullPolicy, but did not" )
382
387
}
383
388
} else if strings .Contains (info .Name (), "namespaces" ) {
384
- // check if secrets were not stripped from namespaces if parseMetrics is false
385
- if ! strings .Contains (string (in ), "ManageFieldToBeDeleted" ) {
386
- t .Error ("Original file should have contained ManagedField data, but did not " )
389
+ // check if secrets were still stripped from namespaces if parseMetrics is false
390
+ if strings .Contains (string (in ), "ManageFieldToBeDeleted" ) {
391
+ t .Error ("file should not have contained ManagedField data, but did" )
387
392
}
388
393
} else if strings .Contains (info .Name (), "deployments" ) {
389
- // check if sensitive fields were not stripped from deployments if parseMetrics is false
390
- if ! strings .Contains (string (in ), "DangThisIsSecret" ) {
391
- t .Error ("Original file should have contained sensitive data, but did not " )
394
+ // check if sensitive fields was still stripped from deployments if parseMetrics is false
395
+ if strings .Contains (string (in ), "DangThisIsSecret" ) {
396
+ t .Error ("file should not have contained sensitive data, but did" )
392
397
}
393
398
} else {
394
- // all other jsonl share the same annotation that should not be removed
395
- if ! strings .Contains (string (in ), "IAmSecretEnvVariables" ) {
396
- t .Error ("Original file should have contained sensitive data, but did not " )
399
+ // all other jsonl share the same annotation that should be removed
400
+ if strings .Contains (string (in ), "IAmSecretEnvVariables" ) {
401
+ t .Error ("file should not have contained sensitive data, but did" )
397
402
}
398
403
}
399
404
}
400
405
return nil
401
406
})
402
407
})
408
+ t .Run ("Ensure that resources are properly filtered out" , func (t * testing.T ) {
409
+ filepath .Walk (ka .msExportDirectory .Name (), func (path string , info os.FileInfo , err error ) error {
410
+ if err != nil {
411
+ t .Error (err )
412
+ }
413
+ if strings .Contains (info .Name (), "jsonl" ) {
414
+ in , err := os .ReadFile (path )
415
+ if err != nil {
416
+ t .Error (err )
417
+ }
418
+ fileLen := strings .Count (string (in ), "\n " )
419
+ if fileLen != 1 {
420
+ t .Errorf ("Expected 1 entry in file %s, got %d" , info .Name (), fileLen )
421
+ }
422
+ }
423
+ return nil
424
+ })
425
+ })
403
426
t .Run ("Ensure collection occurs with parseMetrics enabled" +
404
427
"ensure sensitive data is stripped" , func (t * testing.T ) {
405
428
err = kubeAgentParseMetrics .collectMetrics (context .TODO (), kubeAgentParseMetrics , cs , fns )
@@ -420,6 +443,9 @@ func TestCollectMetrics(t *testing.T) {
420
443
if strings .Contains (string (in ), "ReallySecretStuff" ) {
421
444
t .Error ("Stripped file should not have contained secret, but did" )
422
445
}
446
+ if strings .Contains (string (in ), "\" imagePullPolicy\" :\" Always\" " ) {
447
+ t .Error ("file should not have contained imagePullPolicy, but did" )
448
+ }
423
449
} else if strings .Contains (info .Name (), "namespaces" ) {
424
450
// check if sensitive fields were stripped from namespaces if parseMetrics is true
425
451
if strings .Contains (string (in ), "ManageFieldToBeDeleted" ) {
@@ -524,7 +550,8 @@ func NewTestServer() *httptest.Server {
524
550
}
525
551
526
552
// nolint: lll
527
- func getMockInformers (clusterVersion float64 , stopCh chan struct {}) (map [string ]* cache.SharedIndexInformer , error ) {
553
+ func getMockInformers (clusterVersion float64 , parseMetricsData bool ,
554
+ stopCh chan struct {}) (map [string ]* cache.SharedIndexInformer , error ) {
528
555
// create mock informers for each resource we collect k8s metrics on
529
556
replicationControllers := fcache .NewFakeControllerSource ()
530
557
rcinformer := cache .NewSharedInformer (replicationControllers , & v1.ReplicationController {}, 1 * time .Second ).(cache.SharedIndexInformer )
@@ -581,7 +608,7 @@ func getMockInformers(clusterVersion float64, stopCh chan struct{}) (map[string]
581
608
"cronjobs" : & cjinformer ,
582
609
}
583
610
// Call the Run function for each Informer, allowing the informers to listen for Add events
584
- startMockInformers (mockInformers , stopCh )
611
+ startMockInformers (mockInformers , parseMetricsData , stopCh )
585
612
586
613
// Private Annotation to be removed if ParseMetrics is enabled
587
614
annotation := map [string ]string {
@@ -594,25 +621,40 @@ func getMockInformers(clusterVersion float64, stopCh chan struct{}) (map[string]
594
621
nodes .Add (& v1.Node {ObjectMeta : metav1.ObjectMeta {Name : "n1" , Annotations : annotation }})
595
622
persistentVolumes .Add (& v1.PersistentVolume {ObjectMeta : metav1.ObjectMeta {Name : "pv1" , Annotations : annotation }})
596
623
persistentVolumeClaims .Add (& v1.PersistentVolumeClaim {ObjectMeta : metav1.ObjectMeta {Name : "pvc1" , Annotations : annotation }})
597
- replicaSets .Add (& v1apps.ReplicaSet {ObjectMeta : metav1.ObjectMeta {Name : "rs1" , Annotations : annotation }})
624
+ replicaSets .Add (& v1apps.ReplicaSet {ObjectMeta : metav1.ObjectMeta {Name : "rs1" , Annotations : annotation },
625
+ Status : v1apps.ReplicaSetStatus {Replicas : int32 (1 )}})
626
+ // should not be exported as replicaset is empty
627
+ replicaSets .Add (& v1apps.ReplicaSet {ObjectMeta : metav1.ObjectMeta {Name : "rs2" , Annotations : annotation }})
598
628
daemonSets .Add (& v1apps.DaemonSet {ObjectMeta : metav1.ObjectMeta {Name : "ds1" , Annotations : annotation }})
599
629
jobs .Add (& v1batch.Job {ObjectMeta : metav1.ObjectMeta {Name : "job1" , Annotations : annotation }})
630
+ oneDayAgo := metav1 .NewTime (time .Now ().Add (- 24 * time .Hour ))
631
+ // should not be exported as job was completed some time ago
632
+ jobs .Add (& v1batch.Job {ObjectMeta : metav1.ObjectMeta {Name : "job2" , Annotations : annotation },
633
+ Status : v1batch.JobStatus {CompletionTime : & oneDayAgo }})
634
+ // should not be exported as job was completed some time ago
635
+ jobs .Add (& v1batch.Job {ObjectMeta : metav1.ObjectMeta {Name : "job3" , Annotations : annotation },
636
+ Status : v1batch.JobStatus {
637
+ Failed : int32 (1 ),
638
+ Conditions : []v1batch.JobCondition {{Type : v1batch .JobFailed , LastTransitionTime : oneDayAgo }},
639
+ }})
600
640
if clusterVersion > 1.20 {
601
641
cronJobs .Add (& v1batch.CronJob {ObjectMeta : metav1.ObjectMeta {Name : "cj1" , Annotations : annotation }})
602
642
}
603
643
604
- // pods is unique as we use this pod file for parseMetrics testing
605
- // for parseMetricData testing, add a cldy metrics-agent pod to the mock informers
644
+ // adds 3 pods, two of which completed long ago and will not be added to export sample
606
645
podData , err := os .ReadFile ("../testdata/pods.jsonl" )
607
646
if err != nil {
608
647
return nil , err
609
648
}
610
- var myPod * v1.Pod
611
- err = json .Unmarshal (podData , & myPod )
612
- if err != nil {
613
- return nil , err
649
+ dec := json .NewDecoder (bytes .NewReader (podData ))
650
+ for dec .More () {
651
+ var pod v1.Pod
652
+ if err := dec .Decode (& pod ); err != nil {
653
+ return nil , err
654
+ }
655
+ pods .Add (& pod )
614
656
}
615
- pods . Add ( myPod )
657
+
616
658
// namespace also used in testing
617
659
namespaceData , err := os .ReadFile ("../testdata/namespaces.jsonl" )
618
660
if err != nil {
@@ -639,11 +681,12 @@ func getMockInformers(clusterVersion float64, stopCh chan struct{}) (map[string]
639
681
return mockInformers , nil
640
682
}
641
683
642
- func startMockInformers (mockInformers map [string ]* cache.SharedIndexInformer , stopCh chan struct {}) {
684
+ func startMockInformers (mockInformers map [string ]* cache.SharedIndexInformer , parseMetrics bool , stopCh chan struct {}) {
643
685
for _ , informer := range mockInformers {
644
686
if (* informer ) == nil {
645
687
continue
646
688
}
689
+ _ = (* informer ).SetTransform (k8s .GetTransformFunc (parseMetrics ))
647
690
go (* informer ).Run (stopCh )
648
691
}
649
692
}
0 commit comments