@@ -368,53 +368,26 @@ func (d *LocalRunner) ExitErr() <-chan error {
368368}
369369
370370func (d * LocalRunner ) Stop () error {
371- // only stop the containers that belong to this session
372- containers , err := d .client .ContainerList (context .Background (), container.ListOptions {
373- Filters : filters .NewArgs (filters .Arg ("label" , fmt .Sprintf ("playground.session=%s" , d .manifest .ID ))),
374- })
375- if err != nil {
376- return fmt .Errorf ("error getting container list: %w" , err )
377- }
378-
379- var wg sync.WaitGroup
380- wg .Add (len (containers ))
381-
382- var errCh chan error
383- errCh = make (chan error , len (containers ))
384-
385- for _ , cont := range containers {
386- go func (contID string ) {
387- defer wg .Done ()
388- if err := d .client .ContainerRemove (context .Background (), contID , container.RemoveOptions {
389- RemoveVolumes : true ,
390- RemoveLinks : false ,
391- Force : true ,
392- }); err != nil {
393- errCh <- fmt .Errorf ("error removing container: %w" , err )
394- }
395- }(cont .ID )
396- }
397-
398- wg .Wait ()
399-
400371 // stop all the handles
401372 for _ , handle := range d .handles {
402373 handle .Process .Kill ()
403374 }
404375
405- close (errCh )
376+ // stop the docker-compose
377+ cmd := exec .CommandContext (
378+ context .Background (), "docker" , "compose" ,
379+ "-p" , d .manifest .ID ,
380+ "down" ,
381+ "-v" , // removes containers and volumes
382+ )
383+ var outBuf bytes.Buffer
384+ cmd .Stdout = & outBuf
385+ cmd .Stderr = & outBuf
406386
407- for err := range errCh {
408- if err != nil {
409- return err
410- }
387+ if err := cmd .Run (); err != nil {
388+ return fmt .Errorf ("error taking docker-compose down: %w\n %s" , err , outBuf .String ())
411389 }
412390
413- if d .cleanupNetwork {
414- if err := d .client .NetworkRemove (context .Background (), d .config .NetworkName ); err != nil {
415- return err
416- }
417- }
418391 return nil
419392}
420393
@@ -586,26 +559,26 @@ func (d *LocalRunner) validateImageExists(image string) error {
586559 return fmt .Errorf ("image %s not found" , image )
587560}
588561
589- func (d * LocalRunner ) toDockerComposeService (s * Service ) (map [string ]interface {}, error ) {
562+ func (d * LocalRunner ) toDockerComposeService (s * Service ) (map [string ]interface {}, [] string , error ) {
590563 // apply the template again on the arguments to figure out the connections
591564 // at this point all of them are valid, we just have to resolve them again. We assume for now
592565 // everyone is going to be on docker at the same network.
593566 args , envs , err := d .applyTemplate (s )
594567 if err != nil {
595- return nil , fmt .Errorf ("failed to apply template, err: %w" , err )
568+ return nil , nil , fmt .Errorf ("failed to apply template, err: %w" , err )
596569 }
597570
598571 // The containers have access to the full set of artifacts on the /artifacts folder
599572 // so, we have to bind it as a volume on the container.
600573 outputFolder , err := d .out .AbsoluteDstPath ()
601574 if err != nil {
602- return nil , fmt .Errorf ("failed to get absolute path for output folder: %w" , err )
575+ return nil , nil , fmt .Errorf ("failed to get absolute path for output folder: %w" , err )
603576 }
604577
605578 // Validate that the image exists
606579 imageName := fmt .Sprintf ("%s:%s" , s .Image , s .Tag )
607580 if err := d .validateImageExists (imageName ); err != nil {
608- return nil , fmt .Errorf ("failed to validate image %s: %w" , imageName , err )
581+ return nil , nil , fmt .Errorf ("failed to validate image %s: %w" , imageName , err )
609582 }
610583
611584 labels := map [string ]string {
@@ -635,12 +608,11 @@ func (d *LocalRunner) toDockerComposeService(s *Service) (map[string]interface{}
635608 }
636609
637610 // create the bind volumes
611+ var createdVolumes []string
638612 for localPath , volumeName := range s .VolumesMapped {
639- volumeDirAbsPath , err := d .createVolume (s .Name , volumeName )
640- if err != nil {
641- return nil , err
642- }
643- volumes [volumeDirAbsPath ] = localPath
613+ dockerVolumeName := d .createVolumeName (s .Name , volumeName )
614+ volumes [dockerVolumeName ] = localPath
615+ createdVolumes = append (createdVolumes , dockerVolumeName )
644616 }
645617
646618 volumesInLine := []string {}
@@ -674,7 +646,7 @@ func (d *LocalRunner) toDockerComposeService(s *Service) (map[string]interface{}
674646 if s .ReadyCheck .UseNC {
675647 u , err := url .Parse (s .ReadyCheck .QueryURL )
676648 if err != nil {
677- return nil , fmt .Errorf ("failed to parse ready check url '%s': %v" , s .ReadyCheck .QueryURL , err )
649+ return nil , nil , fmt .Errorf ("failed to parse ready check url '%s': %v" , s .ReadyCheck .QueryURL , err )
678650 }
679651 test = []string {"CMD-SHELL" , "nc -z localhost " + u .Port ()}
680652 } else {
@@ -739,7 +711,7 @@ func (d *LocalRunner) toDockerComposeService(s *Service) (map[string]interface{}
739711 service ["ports" ] = ports
740712 }
741713
742- return service , nil
714+ return service , createdVolumes , nil
743715}
744716
745717func (d * LocalRunner ) isHostService (name string ) bool {
@@ -769,18 +741,27 @@ func (d *LocalRunner) generateDockerCompose() ([]byte, error) {
769741 }
770742 }
771743
744+ volumes := map [string ]struct {}{}
772745 for _ , svc := range d .manifest .Services {
773746 if d .isHostService (svc .Name ) {
774747 // skip services that are going to be launched on host
775748 continue
776749 }
777- var err error
778- if services [svc .Name ], err = d .toDockerComposeService (svc ); err != nil {
750+ var (
751+ err error
752+ dockerVolumes []string
753+ )
754+ services [svc .Name ], dockerVolumes , err = d .toDockerComposeService (svc )
755+ if err != nil {
779756 return nil , fmt .Errorf ("failed to convert service %s to docker compose service: %w" , svc .Name , err )
780757 }
758+ for _ , volumeName := range dockerVolumes {
759+ volumes [volumeName ] = struct {}{}
760+ }
781761 }
782762
783763 compose ["services" ] = services
764+ compose ["volumes" ] = volumes
784765 yamlData , err := yaml .Marshal (compose )
785766 if err != nil {
786767 return nil , fmt .Errorf ("failed to marshal docker compose: %w" , err )
@@ -789,7 +770,11 @@ func (d *LocalRunner) generateDockerCompose() ([]byte, error) {
789770 return yamlData , nil
790771}
791772
792- func (d * LocalRunner ) createVolume (service , volumeName string ) (string , error ) {
773+ func (d * LocalRunner ) createVolumeName (service , volumeName string ) string {
774+ return fmt .Sprintf ("volume-%s-%s" , service , volumeName )
775+ }
776+
777+ func (d * LocalRunner ) createVolumeDir (service , volumeName string ) (string , error ) {
793778 // create the volume in the output folder
794779 volumeDirAbsPath , err := d .out .CreateDir (fmt .Sprintf ("volume-%s-%s" , service , volumeName ))
795780 if err != nil {
@@ -809,7 +794,7 @@ func (d *LocalRunner) runOnHost(ss *Service) error {
809794 // Create the volumes for this service
810795 volumesMapped := map [string ]string {}
811796 for pathInDocker , volumeName := range ss .VolumesMapped {
812- volumeDirAbsPath , err := d .createVolume (ss .Name , volumeName )
797+ volumeDirAbsPath , err := d .createVolumeDir (ss .Name , volumeName )
813798 if err != nil {
814799 return err
815800 }
@@ -1069,7 +1054,13 @@ func (d *LocalRunner) Run(ctx context.Context) error {
10691054 }
10701055
10711056 // First start the services that are running in docker-compose
1072- cmd := exec .CommandContext (ctx , "docker" , "compose" , "-f" , d .out .dst + "/docker-compose.yaml" , "up" , "-d" )
1057+ cmd := exec .CommandContext (
1058+ ctx , "docker" , "compose" ,
1059+ "-p" , d .manifest .ID , // identify project with id for doing "docker compose down" on it later
1060+ "-f" , d .out .dst + "/docker-compose.yaml" ,
1061+ "up" ,
1062+ "-d" ,
1063+ )
10731064
10741065 var errOut bytes.Buffer
10751066 cmd .Stderr = & errOut
@@ -1083,24 +1074,16 @@ func (d *LocalRunner) Run(ctx context.Context) error {
10831074 }
10841075
10851076 // Second, start the services that are running on the host machine
1086- errCh := make (chan error )
1087- go func () {
1088- for _ , svc := range d .manifest .Services {
1089- if d .isHostService (svc .Name ) {
1090- if err := d .runOnHost (svc ); err != nil {
1091- errCh <- err
1092- }
1093- }
1094- }
1095- close (errCh )
1096- }()
1097-
1098- for err := range errCh {
1099- if err != nil {
1100- return err
1077+ g := new (errgroup.Group )
1078+ for _ , svc := range d .manifest .Services {
1079+ if d .isHostService (svc .Name ) {
1080+ g .Go (func () error {
1081+ return d .runOnHost (svc )
1082+ })
11011083 }
11021084 }
1103- return nil
1085+
1086+ return g .Wait ()
11041087}
11051088
11061089// StopContainersBySessionID removes all Docker containers associated with a specific playground session ID.
0 commit comments