@@ -18,6 +18,7 @@ import (
18
18
"context"
19
19
"fmt"
20
20
"io/ioutil"
21
+ "os"
21
22
"os/exec"
22
23
"path/filepath"
23
24
"strconv"
@@ -533,3 +534,123 @@ vdf 254:80 0 512B 0 disk`
533
534
"context cancelled while waiting for container %s to exit, err: %v" , containerName , ctx .Err ())
534
535
}
535
536
}
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