@@ -431,3 +431,213 @@ func TestDockerHealthState(t *testing.T) {
431431 return getHealth () == "healthy"
432432 }, 10 * time .Second , 100 * time .Millisecond )
433433}
434+
435+ // Check that restart count is captured in labels.
436+ func TestDockerContainerRestartCount (t * testing.T ) {
437+ fm := framework .New (t )
438+ defer fm .Cleanup ()
439+
440+ containerName := fmt .Sprintf ("test-restart-count-%d" , os .Getpid ())
441+ // Run a container that runs briefly then exits with failure, with restart policy
442+ // The sleep gives cAdvisor time to detect the container between restarts
443+ fm .Docker ().Run (framework.DockerRunArgs {
444+ Image : "registry.k8s.io/busybox:1.27" ,
445+ Args : []string {
446+ "--name" , containerName ,
447+ "--restart" , "on-failure:5" ,
448+ },
449+ }, "sh" , "-c" , "sleep 3 && exit 1" )
450+
451+ // Wait for container to show up initially
452+ waitForContainer (containerName , fm )
453+
454+ // Wait for at least one restart to occur
455+ time .Sleep (5 * time .Second )
456+
457+ request := & info.ContainerInfoRequest {
458+ NumStats : 1 ,
459+ }
460+
461+ // Query the container - it should still be running or restarting
462+ containerInfo , err := fm .Cadvisor ().Client ().DockerContainer (containerName , request )
463+ require .NoError (t , err , "Container should still be available during restart cycle" )
464+ sanityCheck (containerName , containerInfo , t )
465+
466+ // Check that restart count label is present and greater than 0
467+ restartCount , ok := containerInfo .Spec .Labels ["restartcount" ]
468+ require .True (t , ok , "restartcount label should be present" )
469+ count , err := strconv .Atoi (restartCount )
470+ require .NoError (t , err )
471+ assert .GreaterOrEqual (t , count , 1 , "Restart count should be at least 1" )
472+ }
473+
474+ // Check the DiskIo ContainerStats.
475+ func TestDockerContainerDiskIoStats (t * testing.T ) {
476+ fm := framework .New (t )
477+ defer fm .Cleanup ()
478+
479+ // Run a container that does disk I/O and stays running
480+ containerID := fm .Docker ().RunBusybox ("sh" , "-c" , "dd if=/dev/zero of=/tmp/testfile bs=1024 count=1000 && sync && sleep 30" )
481+
482+ // Wait for the container to show up and do some I/O
483+ waitForContainer (containerID , fm )
484+ time .Sleep (3 * time .Second )
485+
486+ request := & info.ContainerInfoRequest {
487+ NumStats : 1 ,
488+ }
489+ containerInfo , err := fm .Cadvisor ().Client ().DockerContainer (containerID , request )
490+ require .NoError (t , err )
491+ sanityCheck (containerID , containerInfo , t )
492+
493+ // Check that DiskIo stats are present
494+ assert .True (t , containerInfo .Spec .HasDiskIo , "Container should have DiskIo isolation" )
495+ }
496+
497+ // Check container with --network none.
498+ func TestDockerContainerNetworkNone (t * testing.T ) {
499+ fm := framework .New (t )
500+ defer fm .Cleanup ()
501+
502+ containerName := fmt .Sprintf ("test-network-none-%d" , os .Getpid ())
503+ containerID := fm .Docker ().Run (framework.DockerRunArgs {
504+ Image : "registry.k8s.io/pause" ,
505+ Args : []string {
506+ "--name" , containerName ,
507+ "--network" , "none" ,
508+ },
509+ })
510+
511+ // Wait for the container to show up
512+ waitForContainer (containerID , fm )
513+
514+ request := & info.ContainerInfoRequest {
515+ NumStats : 1 ,
516+ }
517+ containerInfo , err := fm .Cadvisor ().Client ().DockerContainer (containerID , request )
518+ require .NoError (t , err )
519+ sanityCheck (containerID , containerInfo , t )
520+
521+ // Container with network none should still be monitored
522+ assert .NotEmpty (t , containerInfo .Stats , "Container should have stats even with --network none" )
523+ }
524+
525+ // Check container with --network host.
526+ func TestDockerContainerNetworkHost (t * testing.T ) {
527+ fm := framework .New (t )
528+ defer fm .Cleanup ()
529+
530+ containerName := fmt .Sprintf ("test-network-host-%d" , os .Getpid ())
531+ containerID := fm .Docker ().Run (framework.DockerRunArgs {
532+ Image : "registry.k8s.io/pause" ,
533+ Args : []string {
534+ "--name" , containerName ,
535+ "--network" , "host" ,
536+ },
537+ })
538+
539+ // Wait for the container to show up
540+ waitForContainer (containerID , fm )
541+
542+ request := & info.ContainerInfoRequest {
543+ NumStats : 1 ,
544+ }
545+ containerInfo , err := fm .Cadvisor ().Client ().DockerContainer (containerID , request )
546+ require .NoError (t , err )
547+ sanityCheck (containerID , containerInfo , t )
548+
549+ // Container with host network should be monitored
550+ assert .NotEmpty (t , containerInfo .Stats , "Container should have stats with --network host" )
551+ }
552+
553+ // Check container with shared network namespace (--network container:X).
554+ // This exercises the code path where we need to inspect another container for IP address.
555+ func TestDockerContainerSharedNetwork (t * testing.T ) {
556+ fm := framework .New (t )
557+ defer fm .Cleanup ()
558+
559+ // First, create a container that will share its network namespace
560+ networkContainerName := fmt .Sprintf ("test-network-provider-%d" , os .Getpid ())
561+ networkContainerID := fm .Docker ().Run (framework.DockerRunArgs {
562+ Image : "registry.k8s.io/pause" ,
563+ Args : []string {
564+ "--name" , networkContainerName ,
565+ },
566+ })
567+ waitForContainer (networkContainerID , fm )
568+
569+ // Now create a container that shares the network namespace of the first container
570+ sharedNetworkContainerName := fmt .Sprintf ("test-network-consumer-%d" , os .Getpid ())
571+ sharedNetworkContainerID := fm .Docker ().Run (framework.DockerRunArgs {
572+ Image : "registry.k8s.io/pause" ,
573+ Args : []string {
574+ "--name" , sharedNetworkContainerName ,
575+ "--network" , fmt .Sprintf ("container:%s" , networkContainerName ),
576+ },
577+ })
578+ waitForContainer (sharedNetworkContainerID , fm )
579+
580+ request := & info.ContainerInfoRequest {
581+ NumStats : 1 ,
582+ }
583+
584+ // Both containers should be accessible
585+ containerInfo1 , err := fm .Cadvisor ().Client ().DockerContainer (networkContainerID , request )
586+ require .NoError (t , err )
587+ sanityCheck (networkContainerID , containerInfo1 , t )
588+
589+ containerInfo2 , err := fm .Cadvisor ().Client ().DockerContainer (sharedNetworkContainerID , request )
590+ require .NoError (t , err )
591+ sanityCheck (sharedNetworkContainerID , containerInfo2 , t )
592+
593+ // The container with shared network should have stats
594+ assert .NotEmpty (t , containerInfo2 .Stats , "Container with shared network should have stats" )
595+ }
596+
597+ // Check that container image information is captured.
598+ func TestDockerContainerImageInfo (t * testing.T ) {
599+ fm := framework .New (t )
600+ defer fm .Cleanup ()
601+
602+ expectedImage := "registry.k8s.io/pause"
603+ containerID := fm .Docker ().Run (framework.DockerRunArgs {
604+ Image : expectedImage ,
605+ })
606+
607+ waitForContainer (containerID , fm )
608+
609+ request := & info.ContainerInfoRequest {
610+ NumStats : 1 ,
611+ }
612+ containerInfo , err := fm .Cadvisor ().Client ().DockerContainer (containerID , request )
613+ require .NoError (t , err )
614+ sanityCheck (containerID , containerInfo , t )
615+
616+ // Check image name is captured
617+ assert .Contains (t , containerInfo .Spec .Image , "pause" , "Container image should contain 'pause'" )
618+ }
619+
620+ // Check that container creation time is valid.
621+ func TestDockerContainerCreationTime (t * testing.T ) {
622+ fm := framework .New (t )
623+ defer fm .Cleanup ()
624+
625+ beforeCreation := time .Now ().Add (- 1 * time .Second )
626+
627+ containerID := fm .Docker ().RunPause ()
628+ waitForContainer (containerID , fm )
629+
630+ afterCreation := time .Now ().Add (1 * time .Second )
631+
632+ request := & info.ContainerInfoRequest {
633+ NumStats : 1 ,
634+ }
635+ containerInfo , err := fm .Cadvisor ().Client ().DockerContainer (containerID , request )
636+ require .NoError (t , err )
637+ sanityCheck (containerID , containerInfo , t )
638+
639+ // Check creation time is within expected range
640+ creationTime := containerInfo .Spec .CreationTime
641+ assert .True (t , creationTime .After (beforeCreation ), "Creation time %v should be after %v" , creationTime , beforeCreation )
642+ assert .True (t , creationTime .Before (afterCreation ), "Creation time %v should be before %v" , creationTime , afterCreation )
643+ }
0 commit comments