@@ -18,6 +18,7 @@ import (
1818 "context"
1919 "fmt"
2020 "io/ioutil"
21+ "os"
2122 "os/exec"
2223 "path/filepath"
2324 "strconv"
@@ -533,3 +534,123 @@ vdf 254:80 0 512B 0 disk`
533534 "context cancelled while waiting for container %s to exit, err: %v" , containerName , ctx .Err ())
534535 }
535536}
537+
538+ func startAndWaitTask (ctx context.Context , t * testing.T , c containerd.Container ) string {
539+ var stdout bytes.Buffer
540+ var stderr bytes.Buffer
541+
542+ task , err := c .NewTask (ctx , cio .NewCreator (cio .WithStreams (nil , & stdout , & stderr )))
543+ require .NoError (t , err , "failed to create task for container %s" , c .ID ())
544+
545+ exitCh , err := task .Wait (ctx )
546+ require .NoError (t , err , "failed to wait on task for container %s" , c .ID ())
547+
548+ err = task .Start (ctx )
549+ require .NoError (t , err , "failed to start task for container %s" , c .ID ())
550+ defer func () {
551+ status , err := task .Delete (ctx )
552+ require .NoError (t , status .Error ())
553+ require .NoError (t , err , "failed to delete task for container %s" , c .ID ())
554+ }()
555+
556+ select {
557+ case exitStatus := <- exitCh :
558+ require .NoError (t , exitStatus .Error (), "failed to retrieve exitStatus" )
559+ require .Equal (t , uint32 (0 ), exitStatus .ExitCode ())
560+ require .Equal (t , "" , stderr .String ())
561+ case <- ctx .Done ():
562+ require .Fail (t , "context cancelled" ,
563+ "context cancelled while waiting for container %s to exit, err: %v" , c .ID (), ctx .Err ())
564+ }
565+
566+ return stdout .String ()
567+ }
568+
569+ func testCreateContainerWithSameName (t * testing.T , vmID string ) {
570+ ctx := namespaces .WithNamespace (context .Background (), "default" )
571+
572+ pluginClient , err := ttrpcutil .NewClient (containerdSockPath + ".ttrpc" )
573+ require .NoError (t , err , "failed to create ttrpc client" )
574+
575+ // Explicitly specify Container Count = 2 to workaround #230
576+ if len (vmID ) != 0 {
577+ fcClient := fccontrol .NewFirecrackerClient (pluginClient .Client ())
578+ _ , err = fcClient .CreateVM (ctx , & proto.CreateVMRequest {
579+ VMID : vmID ,
580+ RootDrive : & proto.FirecrackerDrive {
581+ PathOnHost : defaultRootfsPath ,
582+ IsReadOnly : true ,
583+ IsRootDevice : true ,
584+ },
585+ ContainerCount : 2 ,
586+ })
587+ require .NoError (t , err )
588+ }
589+
590+ withNewSpec := containerd .WithNewSpec (oci .WithProcessArgs ("echo" , "hello" ), firecrackeroci .WithVMID (vmID ))
591+
592+ client , err := containerd .New (containerdSockPath , containerd .WithDefaultRuntime (firecrackerRuntime ))
593+ require .NoError (t , err , "unable to create client to containerd service at %s, is containerd running?" , containerdSockPath )
594+ defer client .Close ()
595+
596+ image , err := client .Pull (ctx , debianDockerImage , containerd .WithPullUnpack , containerd .WithPullSnapshotter (naiveSnapshotterName ))
597+ require .NoError (t , err , "failed to pull image %s, is the the %s snapshotter running?" , debianDockerImage , naiveSnapshotterName )
598+
599+ containerName := fmt .Sprintf ("%s-%d" , t .Name (), time .Now ().UnixNano ())
600+ snapshotName := fmt .Sprintf ("%s-snapshot" , containerName )
601+
602+ containerPath := fmt .Sprintf ("/run/containerd/io.containerd.runtime.v2.task/default/%s" , containerName )
603+
604+ c1 , err := client .NewContainer (ctx ,
605+ containerName ,
606+ containerd .WithSnapshotter (naiveSnapshotterName ),
607+ containerd .WithNewSnapshot (snapshotName , image ),
608+ withNewSpec ,
609+ )
610+ require .NoError (t , err , "failed to create container %s" , containerName )
611+ require .Equal (t , "hello\n " , startAndWaitTask (ctx , t , c1 ))
612+
613+ // All resources regarding the container will be deleted
614+ err = c1 .Delete (ctx , containerd .WithSnapshotCleanup )
615+ require .NoError (t , err , "failed to delete container %s" , containerName )
616+
617+ _ , err = os .Stat (containerPath )
618+ require .True (t , os .IsNotExist (err ))
619+
620+ if len (vmID ) != 0 {
621+ shimPath := fmt .Sprintf ("%s/default/%s/%s" , varRunDir , vmID , containerName )
622+ _ , err = os .Stat (shimPath )
623+ require .True (t , os .IsNotExist (err ))
624+ }
625+
626+ // So, we can launch a new container with the same name
627+ c2 , err := client .NewContainer (ctx ,
628+ containerName ,
629+ containerd .WithSnapshotter (naiveSnapshotterName ),
630+ containerd .WithNewSnapshot (snapshotName , image ),
631+ withNewSpec ,
632+ )
633+ require .NoError (t , err , "failed to create container %s" , containerName )
634+ require .Equal (t , "hello\n " , startAndWaitTask (ctx , t , c2 ))
635+
636+ err = c2 .Delete (ctx , containerd .WithSnapshotCleanup )
637+ require .NoError (t , err , "failed to delete container %s" , containerName )
638+
639+ _ , err = os .Stat (containerPath )
640+ require .True (t , os .IsNotExist (err ))
641+
642+ if len (vmID ) != 0 {
643+ shimPath := fmt .Sprintf ("%s/default/%s/%s" , varRunDir , vmID , containerName )
644+ _ , err = os .Stat (shimPath )
645+ require .True (t , os .IsNotExist (err ))
646+ }
647+ }
648+
649+ func TestCreateContainerWithSameName_Isolated (t * testing.T ) {
650+ internal .RequiresIsolation (t )
651+
652+ testCreateContainerWithSameName (t , "" )
653+
654+ vmID := fmt .Sprintf ("same-vm-%d" , time .Now ().UnixNano ())
655+ testCreateContainerWithSameName (t , vmID )
656+ }
0 commit comments