github.com/apptainer/singularity@v3.1.1+incompatible/internal/app/singularity/oci_run_linux.go (about)

     1  // Copyright (c) 2018-2019, Sylabs Inc. All rights reserved.
     2  // This software is licensed under a 3-clause BSD license. Please consult the
     3  // LICENSE.md file distributed with the sources of this project regarding your
     4  // rights to use or distribute this software.
     5  
     6  package singularity
     7  
     8  import (
     9  	"encoding/json"
    10  	"fmt"
    11  	"os"
    12  	"path/filepath"
    13  
    14  	specs "github.com/opencontainers/runtime-spec/specs-go"
    15  	"github.com/sylabs/singularity/internal/pkg/instance"
    16  	"github.com/sylabs/singularity/internal/pkg/sylog"
    17  	"github.com/sylabs/singularity/pkg/ociruntime"
    18  	"github.com/sylabs/singularity/pkg/util/unix"
    19  )
    20  
    21  // OciRun runs a container (equivalent to create/start/delete)
    22  func OciRun(containerID string, args *OciArgs) error {
    23  	dir, err := instance.GetDirPrivileged(containerID, instance.OciSubDir)
    24  	if err != nil {
    25  		return err
    26  	}
    27  	if err := os.MkdirAll(dir, 0755); err != nil {
    28  		return err
    29  	}
    30  	args.SyncSocketPath = filepath.Join(dir, "run.sock")
    31  
    32  	l, err := unix.CreateSocket(args.SyncSocketPath)
    33  	if err != nil {
    34  		os.Remove(args.SyncSocketPath)
    35  		return err
    36  	}
    37  
    38  	defer l.Close()
    39  
    40  	status := make(chan string, 1)
    41  
    42  	if err := OciCreate(containerID, args); err != nil {
    43  		defer os.Remove(args.SyncSocketPath)
    44  		if _, err1 := getState(containerID); err1 != nil {
    45  			return err
    46  		}
    47  		if err := OciDelete(containerID); err != nil {
    48  			sylog.Warningf("can't delete container %s", containerID)
    49  		}
    50  		return err
    51  	}
    52  
    53  	defer exitContainer(containerID, true)
    54  	defer os.Remove(args.SyncSocketPath)
    55  
    56  	go func() {
    57  		var state specs.State
    58  
    59  		for {
    60  			c, err := l.Accept()
    61  			if err != nil {
    62  				status <- err.Error()
    63  				return
    64  			}
    65  
    66  			dec := json.NewDecoder(c)
    67  			if err := dec.Decode(&state); err != nil {
    68  				status <- err.Error()
    69  				return
    70  			}
    71  
    72  			c.Close()
    73  
    74  			switch state.Status {
    75  			case ociruntime.Created:
    76  				// ignore error there and wait for stopped status
    77  				OciStart(containerID)
    78  			case ociruntime.Running:
    79  				status <- state.Status
    80  			case ociruntime.Stopped:
    81  				status <- state.Status
    82  			}
    83  		}
    84  	}()
    85  
    86  	// wait running status
    87  	s := <-status
    88  	if s != ociruntime.Running {
    89  		return fmt.Errorf("%s", s)
    90  	}
    91  
    92  	engineConfig, err := getEngineConfig(containerID)
    93  	if err != nil {
    94  		return err
    95  	}
    96  
    97  	if err := attach(engineConfig, true); err != nil {
    98  		// kill container before deletion
    99  		sylog.Errorf("%s", err)
   100  		OciKill(containerID, "SIGKILL", 1)
   101  		return err
   102  	}
   103  
   104  	// wait stopped status
   105  	s = <-status
   106  	if s != ociruntime.Stopped {
   107  		return fmt.Errorf("%s", s)
   108  	}
   109  
   110  	return nil
   111  }