github.com/mgoltzsche/ctnr@v0.7.1-alpha/run/types.go (about)

     1  package run
     2  
     3  import (
     4  	"fmt"
     5  	"io"
     6  	"os"
     7  	"os/exec"
     8  	"syscall"
     9  
    10  	"github.com/opencontainers/runtime-spec/specs-go"
    11  	"github.com/pkg/errors"
    12  )
    13  
    14  type ContainerBundle interface {
    15  	ID() string
    16  	Dir() string
    17  	Spec() (*specs.Spec, error)
    18  	Close() error
    19  }
    20  
    21  type ContainerConfig struct {
    22  	Id             string
    23  	Bundle         ContainerBundle
    24  	Io             ContainerIO
    25  	NoPivotRoot    bool
    26  	NoNewKeyring   bool
    27  	DestroyOnClose bool
    28  }
    29  
    30  type ContainerIO struct {
    31  	Stdin  io.Reader
    32  	Stdout io.Writer
    33  	Stderr io.Writer
    34  }
    35  
    36  func NewStdContainerIO() ContainerIO {
    37  	return ContainerIO{
    38  		Stdout: os.Stdout,
    39  		Stderr: os.Stderr,
    40  	}
    41  }
    42  
    43  type ContainerManager interface {
    44  	NewContainer(cfg *ContainerConfig) (Container, error)
    45  	Get(id string) (Container, error)
    46  	List() ([]ContainerInfo, error)
    47  	Kill(id string, signal os.Signal, all bool) error
    48  	Exist(id string) (bool, error)
    49  }
    50  
    51  type Container interface {
    52  	ID() string
    53  	Rootfs() string
    54  	Start() error
    55  	// TODO: expose process
    56  	Exec(*specs.Process, ContainerIO) (Process, error)
    57  	Destroy() error
    58  	Process
    59  }
    60  
    61  type Process interface {
    62  	Wait() error
    63  	Stop()
    64  	Close() error
    65  }
    66  
    67  type ContainerInfo struct {
    68  	ID     string
    69  	Status string
    70  }
    71  
    72  type ExitError struct {
    73  	containerId string
    74  	code        int
    75  	cause       error
    76  }
    77  
    78  func (e *ExitError) Code() int {
    79  	return e.code
    80  }
    81  
    82  func (e *ExitError) ContainerID() string {
    83  	return e.containerId
    84  }
    85  
    86  func (e *ExitError) Error() string {
    87  	return e.cause.Error()
    88  }
    89  
    90  func (e *ExitError) Format(s fmt.State, verb rune) {
    91  	type formatter interface {
    92  		Format(s fmt.State, verb rune)
    93  	}
    94  	e.cause.(formatter).Format(s, verb)
    95  }
    96  
    97  func NewExitError(err error, containerId string) error {
    98  	if err == nil {
    99  		return nil
   100  	}
   101  	if exiterr, ok := err.(*exec.ExitError); ok {
   102  		if status, ok := exiterr.Sys().(syscall.WaitStatus); ok {
   103  			code := status.ExitStatus()
   104  			return &ExitError{containerId, code, errors.New(fmt.Sprintf("%s terminated: exit code %d", containerId, code))}
   105  		}
   106  	}
   107  	return errors.New(err.Error())
   108  }
   109  
   110  func FindExitError(err error) *ExitError {
   111  	if err != nil {
   112  		type causer interface {
   113  			Cause() error
   114  		}
   115  		if e, ok := err.(*ExitError); ok {
   116  			return e
   117  		}
   118  		if e, ok := err.(causer); ok && e.Cause() != nil {
   119  			return FindExitError(e.Cause())
   120  		}
   121  	}
   122  	return nil
   123  }