@@ -453,3 +453,291 @@ describe('AwsEcsResourceDetector', () => {
453
453
} ) ;
454
454
} ) ;
455
455
} ) ;
456
+
457
+ describe ( 'AwsEcsDetector - Container ID extraction improvements' , ( ) => {
458
+ let readStub : sinon . SinonStub ;
459
+
460
+ beforeEach ( ( ) => {
461
+ process . env . ECS_CONTAINER_METADATA_URI_V4 = 'http://169.254.170.2/v4/test' ;
462
+ } ) ;
463
+
464
+ afterEach ( ( ) => {
465
+ sinon . restore ( ) ;
466
+ } ) ;
467
+
468
+ describe ( 'New AWS ECS Fargate cgroup format support' , ( ) => {
469
+ it ( 'should extract full container ID from new AWS ECS Fargate format' , async ( ) => {
470
+ const taskId = 'c23e5f76c09d438aa1824ca4058bdcab' ;
471
+ const containerId = '1234567890abcdef' ;
472
+ const cgroupData = `/ecs/${ taskId } /${ taskId } -${ containerId } ` ;
473
+
474
+ sinon . stub ( os , 'hostname' ) . returns ( 'test-hostname' ) ;
475
+ readStub = sinon
476
+ . stub ( AwsEcsDetector , 'readFileAsync' as any )
477
+ . resolves ( cgroupData ) ;
478
+
479
+ // Mock the metadata requests
480
+ const nockScope = nock ( 'http://169.254.170.2:80' )
481
+ . persist ( false )
482
+ . get ( '/v4/test' )
483
+ . reply ( 200 , { ContainerARN : 'arn:aws:ecs:us-west-2:111122223333:container/test' } )
484
+ . get ( '/v4/test/task' )
485
+ . reply ( 200 , {
486
+ TaskARN : 'arn:aws:ecs:us-west-2:111122223333:task/default/test' ,
487
+ Family : 'test-family' ,
488
+ Revision : '1' ,
489
+ Cluster : 'test-cluster' ,
490
+ LaunchType : 'FARGATE'
491
+ } ) ;
492
+
493
+ const resource = detectResources ( { detectors : [ awsEcsDetector ] } ) ;
494
+ await resource . waitForAsyncAttributes ?.( ) ;
495
+
496
+ sinon . assert . calledOnce ( readStub ) ;
497
+ assert . ok ( resource ) ;
498
+ assertEcsResource ( resource , { } ) ;
499
+ assertContainerResource ( resource , {
500
+ name : 'test-hostname' ,
501
+ id : `${ taskId } -${ containerId } ` , // Expected: full taskId-containerId, not truncated
502
+ } ) ;
503
+
504
+ nockScope . done ( ) ;
505
+ } ) ;
506
+
507
+ it ( 'should extract container ID from long cgroup path without truncation' , async ( ) => {
508
+ // Simulate the actual issue where the path is longer than 64 chars
509
+ const longTaskId = 'abcdefgh12345678abcdefgh12345678abcdefgh12345678' ;
510
+ const containerId = '1234567890abcdef' ;
511
+ const cgroupData = `/ecs/${ longTaskId } /${ longTaskId } -${ containerId } ` ;
512
+
513
+ sinon . stub ( os , 'hostname' ) . returns ( 'test-hostname' ) ;
514
+ readStub = sinon
515
+ . stub ( AwsEcsDetector , 'readFileAsync' as any )
516
+ . resolves ( cgroupData ) ;
517
+
518
+ // Mock the metadata requests
519
+ const nockScope = nock ( 'http://169.254.170.2:80' )
520
+ . persist ( false )
521
+ . get ( '/v4/test' )
522
+ . reply ( 200 , { ContainerARN : 'arn:aws:ecs:us-west-2:111122223333:container/test' } )
523
+ . get ( '/v4/test/task' )
524
+ . reply ( 200 , {
525
+ TaskARN : 'arn:aws:ecs:us-west-2:111122223333:task/default/test' ,
526
+ Family : 'test-family' ,
527
+ Revision : '1' ,
528
+ Cluster : 'test-cluster' ,
529
+ LaunchType : 'FARGATE'
530
+ } ) ;
531
+
532
+ const resource = detectResources ( { detectors : [ awsEcsDetector ] } ) ;
533
+ await resource . waitForAsyncAttributes ?.( ) ;
534
+
535
+ sinon . assert . calledOnce ( readStub ) ;
536
+ assert . ok ( resource ) ;
537
+ assertEcsResource ( resource , { } ) ;
538
+ assertContainerResource ( resource , {
539
+ name : 'test-hostname' ,
540
+ id : `${ longTaskId } -${ containerId } ` , // Should get full ID, not truncated
541
+ } ) ;
542
+
543
+ nockScope . done ( ) ;
544
+ } ) ;
545
+
546
+ it ( 'should handle multiple cgroup lines and pick the valid one' , async ( ) => {
547
+ const taskId = 'c23e5f76c09d438aa1824ca4058bdcab' ;
548
+ const containerId = '1234567890abcdef' ;
549
+ const cgroupData = [
550
+ '12:memory:/ecs' ,
551
+ '11:cpu:/ecs/task-id' ,
552
+ `10:devices:/ecs/${ taskId } /${ taskId } -${ containerId } ` ,
553
+ '9:freezer:/ecs'
554
+ ] . join ( '\n' ) ;
555
+
556
+ sinon . stub ( os , 'hostname' ) . returns ( 'test-hostname' ) ;
557
+ readStub = sinon
558
+ . stub ( AwsEcsDetector , 'readFileAsync' as any )
559
+ . resolves ( cgroupData ) ;
560
+
561
+ // Mock the metadata requests
562
+ const nockScope = nock ( 'http://169.254.170.2:80' )
563
+ . persist ( false )
564
+ . get ( '/v4/test' )
565
+ . reply ( 200 , { ContainerARN : 'arn:aws:ecs:us-west-2:111122223333:container/test' } )
566
+ . get ( '/v4/test/task' )
567
+ . reply ( 200 , {
568
+ TaskARN : 'arn:aws:ecs:us-west-2:111122223333:task/default/test' ,
569
+ Family : 'test-family' ,
570
+ Revision : '1' ,
571
+ Cluster : 'test-cluster' ,
572
+ LaunchType : 'FARGATE'
573
+ } ) ;
574
+
575
+ const resource = detectResources ( { detectors : [ awsEcsDetector ] } ) ;
576
+ await resource . waitForAsyncAttributes ?.( ) ;
577
+
578
+ sinon . assert . calledOnce ( readStub ) ;
579
+ assert . ok ( resource ) ;
580
+ assertEcsResource ( resource , { } ) ;
581
+ assertContainerResource ( resource , {
582
+ name : 'test-hostname' ,
583
+ id : `${ taskId } -${ containerId } ` ,
584
+ } ) ;
585
+
586
+ nockScope . done ( ) ;
587
+ } ) ;
588
+ } ) ;
589
+
590
+ describe ( 'Edge cases and format variations' , ( ) => {
591
+ it ( 'should handle containerd format with colon separators' , async ( ) => {
592
+ const taskId = 'c23e5f76c09d438aa1824ca4058bdcab' ;
593
+ const containerId = '1234567890abcdef' ;
594
+ const cgroupData = `0::/system.slice/containerd.service/kubepods-burstable-pod.slice:cri-containerd:${ taskId } -${ containerId } ` ;
595
+
596
+ sinon . stub ( os , 'hostname' ) . returns ( 'test-hostname' ) ;
597
+ readStub = sinon
598
+ . stub ( AwsEcsDetector , 'readFileAsync' as any )
599
+ . resolves ( cgroupData ) ;
600
+
601
+ // Mock the metadata requests
602
+ const nockScope = nock ( 'http://169.254.170.2:80' )
603
+ . persist ( false )
604
+ . get ( '/v4/test' )
605
+ . reply ( 200 , { ContainerARN : 'arn:aws:ecs:us-west-2:111122223333:container/test' } )
606
+ . get ( '/v4/test/task' )
607
+ . reply ( 200 , {
608
+ TaskARN : 'arn:aws:ecs:us-west-2:111122223333:task/default/test' ,
609
+ Family : 'test-family' ,
610
+ Revision : '1' ,
611
+ Cluster : 'test-cluster' ,
612
+ LaunchType : 'FARGATE'
613
+ } ) ;
614
+
615
+ const resource = detectResources ( { detectors : [ awsEcsDetector ] } ) ;
616
+ await resource . waitForAsyncAttributes ?.( ) ;
617
+
618
+ sinon . assert . calledOnce ( readStub ) ;
619
+ assert . ok ( resource ) ;
620
+ assertEcsResource ( resource , { } ) ;
621
+ assertContainerResource ( resource , {
622
+ name : 'test-hostname' ,
623
+ id : `${ taskId } -${ containerId } ` ,
624
+ } ) ;
625
+
626
+ nockScope . done ( ) ;
627
+ } ) ;
628
+
629
+ it ( 'should handle docker prefix and scope suffix' , async ( ) => {
630
+ const taskId = 'c23e5f76c09d438aa1824ca4058bdcab' ;
631
+ const containerId = '1234567890abcdef' ;
632
+ const cgroupData = `/docker/docker-${ taskId } -${ containerId } .scope` ;
633
+
634
+ sinon . stub ( os , 'hostname' ) . returns ( 'test-hostname' ) ;
635
+ readStub = sinon
636
+ . stub ( AwsEcsDetector , 'readFileAsync' as any )
637
+ . resolves ( cgroupData ) ;
638
+
639
+ // Mock the metadata requests
640
+ const nockScope = nock ( 'http://169.254.170.2:80' )
641
+ . persist ( false )
642
+ . get ( '/v4/test' )
643
+ . reply ( 200 , { ContainerARN : 'arn:aws:ecs:us-west-2:111122223333:container/test' } )
644
+ . get ( '/v4/test/task' )
645
+ . reply ( 200 , {
646
+ TaskARN : 'arn:aws:ecs:us-west-2:111122223333:task/default/test' ,
647
+ Family : 'test-family' ,
648
+ Revision : '1' ,
649
+ Cluster : 'test-cluster' ,
650
+ LaunchType : 'FARGATE'
651
+ } ) ;
652
+
653
+ const resource = detectResources ( { detectors : [ awsEcsDetector ] } ) ;
654
+ await resource . waitForAsyncAttributes ?.( ) ;
655
+
656
+ sinon . assert . calledOnce ( readStub ) ;
657
+ assert . ok ( resource ) ;
658
+ assertEcsResource ( resource , { } ) ;
659
+ assertContainerResource ( resource , {
660
+ name : 'test-hostname' ,
661
+ id : `${ taskId } -${ containerId } ` ,
662
+ } ) ;
663
+
664
+ nockScope . done ( ) ;
665
+ } ) ;
666
+
667
+ it ( 'should return undefined for invalid container ID formats' , async ( ) => {
668
+ const invalidCgroupData = '/invalid/path/with/non-hex-characters!!!' ;
669
+
670
+ sinon . stub ( os , 'hostname' ) . returns ( 'test-hostname' ) ;
671
+ readStub = sinon
672
+ . stub ( AwsEcsDetector , 'readFileAsync' as any )
673
+ . resolves ( invalidCgroupData ) ;
674
+
675
+ // Mock the metadata requests
676
+ const nockScope = nock ( 'http://169.254.170.2:80' )
677
+ . persist ( false )
678
+ . get ( '/v4/test' )
679
+ . reply ( 200 , { ContainerARN : 'arn:aws:ecs:us-west-2:111122223333:container/test' } )
680
+ . get ( '/v4/test/task' )
681
+ . reply ( 200 , {
682
+ TaskARN : 'arn:aws:ecs:us-west-2:111122223333:task/default/test' ,
683
+ Family : 'test-family' ,
684
+ Revision : '1' ,
685
+ Cluster : 'test-cluster' ,
686
+ LaunchType : 'FARGATE'
687
+ } ) ;
688
+
689
+ const resource = detectResources ( { detectors : [ awsEcsDetector ] } ) ;
690
+ await resource . waitForAsyncAttributes ?.( ) ;
691
+
692
+ sinon . assert . calledOnce ( readStub ) ;
693
+ assert . ok ( resource ) ;
694
+ assertEcsResource ( resource , { } ) ;
695
+ assertContainerResource ( resource , {
696
+ name : 'test-hostname' ,
697
+ // id should be undefined due to invalid format
698
+ } ) ;
699
+
700
+ nockScope . done ( ) ;
701
+ } ) ;
702
+ } ) ;
703
+
704
+ describe ( 'Backward compatibility' , ( ) => {
705
+ it ( 'should fallback to original logic for legacy format' , async ( ) => {
706
+ // Test backward compatibility with existing 64-char format
707
+ const legacyContainerId = 'abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklm' ;
708
+
709
+ sinon . stub ( os , 'hostname' ) . returns ( 'test-hostname' ) ;
710
+ readStub = sinon
711
+ . stub ( AwsEcsDetector , 'readFileAsync' as any )
712
+ . resolves ( legacyContainerId ) ;
713
+
714
+ // Mock the metadata requests
715
+ const nockScope = nock ( 'http://169.254.170.2:80' )
716
+ . persist ( false )
717
+ . get ( '/v4/test' )
718
+ . reply ( 200 , { ContainerARN : 'arn:aws:ecs:us-west-2:111122223333:container/test' } )
719
+ . get ( '/v4/test/task' )
720
+ . reply ( 200 , {
721
+ TaskARN : 'arn:aws:ecs:us-west-2:111122223333:task/default/test' ,
722
+ Family : 'test-family' ,
723
+ Revision : '1' ,
724
+ Cluster : 'test-cluster' ,
725
+ LaunchType : 'FARGATE'
726
+ } ) ;
727
+
728
+ const resource = detectResources ( { detectors : [ awsEcsDetector ] } ) ;
729
+ await resource . waitForAsyncAttributes ?.( ) ;
730
+
731
+ sinon . assert . calledOnce ( readStub ) ;
732
+ assert . ok ( resource ) ;
733
+ assertEcsResource ( resource , { } ) ;
734
+ assertContainerResource ( resource , {
735
+ name : 'test-hostname' ,
736
+ id : 'bcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklm' , // Last 64 chars
737
+ } ) ;
738
+
739
+ nockScope . done ( ) ;
740
+ } ) ;
741
+ } ) ;
742
+ } ) ;
743
+
0 commit comments