23adfe42f9
Signed-off-by: Michael Crosby <crosbymichael@gmail.com>
186 lines
3.9 KiB
Go
186 lines
3.9 KiB
Go
package containerkit
|
|
|
|
import (
|
|
"encoding/json"
|
|
"io"
|
|
"os"
|
|
"path/filepath"
|
|
"sync"
|
|
|
|
specs "github.com/opencontainers/runtime-spec/specs-go"
|
|
)
|
|
|
|
func NewContainer(root, id string, m Mount, s *specs.Spec, driver ExecutionDriver) (*Container, error) {
|
|
path := filepath.Join(root, id)
|
|
if err := os.MkdirAll(filepath.Join(path, s.Root.Path), 0711); err != nil {
|
|
return nil, err
|
|
}
|
|
// FIXME: find a better UI for this
|
|
s.Mounts = append([]specs.Mount{
|
|
{
|
|
Type: m.Type,
|
|
Source: m.Source,
|
|
Destination: "/",
|
|
Options: m.Options,
|
|
},
|
|
}, s.Mounts...)
|
|
f, err := os.Create(filepath.Join(path, "config.json"))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
// write the spec file to the container's directory
|
|
err = json.NewEncoder(f).Encode(s)
|
|
f.Close()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return &Container{
|
|
id: id,
|
|
path: path,
|
|
s: s,
|
|
driver: driver,
|
|
}, nil
|
|
}
|
|
|
|
func LoadContainer(root, id string, driver ExecutionDriver) (*Container, error) {
|
|
path := filepath.Join(root, id)
|
|
spec, err := loadSpec(path)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
process, err := driver.Load(id)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
// TODO: load exec processes
|
|
return &Container{
|
|
id: id,
|
|
path: path,
|
|
s: spec,
|
|
driver: driver,
|
|
init: &Process{
|
|
d: process,
|
|
driver: driver,
|
|
},
|
|
}, nil
|
|
}
|
|
|
|
func loadSpec(path string) (*specs.Spec, error) {
|
|
f, err := os.Open(filepath.Join(path, "config.json"))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
var s specs.Spec
|
|
err = json.NewDecoder(f).Decode(&s)
|
|
f.Close()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return &s, nil
|
|
}
|
|
|
|
type Container struct {
|
|
mu sync.Mutex
|
|
id string
|
|
path string
|
|
s *specs.Spec
|
|
|
|
driver ExecutionDriver
|
|
|
|
Stdin io.Reader
|
|
Stdout io.Writer
|
|
Stderr io.Writer
|
|
|
|
// init is the container's init processes
|
|
init *Process
|
|
// processes is a list of additional processes executed inside the container
|
|
// via the NewProcess method on the container
|
|
processes []*Process
|
|
}
|
|
|
|
// ID returns the id of the container
|
|
func (c *Container) ID() string {
|
|
return c.id
|
|
}
|
|
|
|
// Path returns the fully qualified path to the container on disk
|
|
func (c *Container) Path() string {
|
|
return c.path
|
|
}
|
|
|
|
// Create will create the container on the system by running the runtime's
|
|
// initial setup and process waiting for the user process to be started
|
|
func (c *Container) Create() error {
|
|
c.mu.Lock()
|
|
defer c.mu.Unlock()
|
|
d, err := c.driver.Create(c)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
c.init = &Process{
|
|
d: d,
|
|
driver: c.driver,
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// Start will start the container's user specified process
|
|
func (c *Container) Start() error {
|
|
c.mu.Lock()
|
|
defer c.mu.Unlock()
|
|
return c.driver.Start(c)
|
|
}
|
|
|
|
// NewProcess will create a new process that will be executed inside the
|
|
// container and tied to the init processes lifecycle
|
|
func (c *Container) NewProcess(spec *specs.Process) (*Process, error) {
|
|
c.mu.Lock()
|
|
defer c.mu.Unlock()
|
|
process := &Process{
|
|
s: spec,
|
|
c: c,
|
|
exec: true,
|
|
driver: c.driver,
|
|
}
|
|
c.processes = append(c.processes, process)
|
|
return process, nil
|
|
}
|
|
|
|
// Pid returns the pid of the init or main process hosted inside the container
|
|
func (c *Container) Pid() int {
|
|
c.mu.Lock()
|
|
if c.init == nil {
|
|
c.mu.Unlock()
|
|
return -1
|
|
}
|
|
pid := c.init.Pid()
|
|
c.mu.Unlock()
|
|
return pid
|
|
}
|
|
|
|
// Wait will perform a blocking wait on the init process of the container
|
|
func (c *Container) Wait() (uint32, error) {
|
|
c.mu.Lock()
|
|
proc := c.init
|
|
c.mu.Unlock()
|
|
return proc.Wait()
|
|
}
|
|
|
|
// Signal will send the provided signal to the init process of the container
|
|
func (c *Container) Signal(s os.Signal) error {
|
|
c.mu.Lock()
|
|
defer c.mu.Unlock()
|
|
return c.init.Signal(s)
|
|
}
|
|
|
|
// Delete will delete the container if it no long has any processes running
|
|
// inside the container and removes all state on disk for the container
|
|
func (c *Container) Delete() error {
|
|
c.mu.Lock()
|
|
defer c.mu.Unlock()
|
|
err := c.driver.Delete(c)
|
|
if rerr := os.RemoveAll(c.path); err == nil {
|
|
err = rerr
|
|
}
|
|
return err
|
|
}
|