diff --git a/container.go b/container.go index 6a56626..e6d58ed 100644 --- a/container.go +++ b/container.go @@ -42,6 +42,43 @@ func NewContainer(root, id string, m Mount, s *specs.Spec, driver ExecutionDrive }, 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 diff --git a/example/main.go b/example/main.go index e0decd2..6b7ec0c 100644 --- a/example/main.go +++ b/example/main.go @@ -29,7 +29,11 @@ func getContainerRootfs() containerkit.Mount { func runContainer() error { // create a new runc runtime that implements the ExecutionDriver interface - driver, err := oci.New("/run/runc", "runc", "/tmp/runc") + driver, err := oci.New(oci.Opts{ + Root: "/run/runc", + Name: "runc", + LogFile: "/tmp/runc", + }) if err != nil { return err } @@ -89,6 +93,15 @@ func runContainer() error { logrus.Infof("process %d returned with %d", i, procStatus) } + container, err = containerkit.LoadContainer( + "/var/lib/containerkit", /* container root */ + "test", /* container id */ + driver, /* the exec driver to use for the container */ + ) + if err != nil { + return err + } + // wait for it to exit and get the exit status logrus.Info("wait container") status, err := container.Wait() @@ -151,7 +164,7 @@ func spec(id string) *specs.Spec { }, Process: specs.Process{ Env: env, - Args: []string{"sleep", "10"}, + Args: []string{"sleep", "30"}, Terminal: false, Cwd: "/", NoNewPrivileges: true, diff --git a/execution.go b/execution.go index 62a61e8..ee1aa7f 100644 --- a/execution.go +++ b/execution.go @@ -11,4 +11,5 @@ type ExecutionDriver interface { Start(*Container) error Delete(*Container) error Exec(*Container, *Process) (ProcessDelegate, error) + Load(id string) (ProcessDelegate, error) } diff --git a/oci/oci.go b/oci/oci.go index f5d2340..f88934b 100644 --- a/oci/oci.go +++ b/oci/oci.go @@ -9,18 +9,27 @@ import ( "path/filepath" "strconv" "syscall" + "time" "github.com/docker/containerkit" ) -func New(root, name, log string) (*OCIRuntime, error) { - if err := os.MkdirAll(root, 0711); err != nil { +type Opts struct { + Name string + Root string + Args []string + LogFile string +} + +func New(opts Opts) (*OCIRuntime, error) { + if err := os.MkdirAll(opts.Root, 0711); err != nil { return nil, err } return &OCIRuntime{ - root: root, - log: log, - name: name, + root: opts.Root, + log: opts.LogFile, + name: opts.Name, + args: opts.Args, }, nil } @@ -32,6 +41,8 @@ type OCIRuntime struct { name string // log is the path to the log files for the containers log string + // args specifies additional arguments to the OCI runtime + args []string } func (r *OCIRuntime) Create(c *containerkit.Container) (containerkit.ProcessDelegate, error) { @@ -88,11 +99,34 @@ func (r *OCIRuntime) Exec(c *containerkit.Container, p *containerkit.Process) (c return newProcess(i) } +type state struct { + ID string `json:"id"` + Pid int `json:"pid"` + Status string `json:"status"` + Bundle string `json:"bundle"` + Rootfs string `json:"rootfs"` + Created time.Time `json:"created"` + Annotations map[string]string `json:"annotations"` +} + +func (r *OCIRuntime) Load(id string) (containerkit.ProcessDelegate, error) { + data, err := r.command("state", id).Output() + if err != nil { + return nil, err + } + var s state + if err := json.Unmarshal(data, &s); err != nil { + return nil, err + } + return newProcess(s.Pid) +} + func (r *OCIRuntime) command(args ...string) *exec.Cmd { - return exec.Command(r.name, append([]string{ + baseArgs := append([]string{ "--root", r.root, "--log", r.log, - }, args...)...) + }, r.args...) + return exec.Command(r.name, append(baseArgs, args...)...) } func newProcess(pid int) (*process, error) {