linux_container: execute an init process in a new CT
Here is a first step to implement a new API. Currently the init processes is executed without namespaces and cgroups. Signed-off-by: Andrew Vagin <avagin@openvz.org>
This commit is contained in:
parent
2441babc48
commit
8e9a6d28d2
18
factory.go
18
factory.go
|
@ -28,13 +28,13 @@ type Factory interface {
|
|||
// System error
|
||||
Load(id string) (Container, error)
|
||||
|
||||
// StartInitialization is an internal API to libcontainer used during the rexec of the
|
||||
// container. pipefd is the fd to the child end of the pipe used to syncronize the
|
||||
// parent and child process providing state and configuration to the child process and
|
||||
// returning any errors during the init of the container
|
||||
//
|
||||
// Errors:
|
||||
// pipe connection error
|
||||
// system error
|
||||
StartInitialization(pipefd uintptr) error
|
||||
// StartInitialization is an internal API to libcontainer used during the rexec of the
|
||||
// container. pipefd is the fd to the child end of the pipe used to syncronize the
|
||||
// parent and child process providing state and configuration to the child process and
|
||||
// returning any errors during the init of the container
|
||||
//
|
||||
// Errors:
|
||||
// pipe connection error
|
||||
// system error
|
||||
StartInitialization(pipefd uintptr) error
|
||||
}
|
||||
|
|
|
@ -3,6 +3,13 @@
|
|||
package libcontainer
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"syscall"
|
||||
|
||||
"github.com/docker/libcontainer/network"
|
||||
"github.com/golang/glog"
|
||||
)
|
||||
|
@ -13,6 +20,7 @@ type linuxContainer struct {
|
|||
config *Config
|
||||
state *State
|
||||
cgroupManager CgroupManager
|
||||
initArgs []string
|
||||
}
|
||||
|
||||
func (c *linuxContainer) ID() string {
|
||||
|
@ -24,7 +32,7 @@ func (c *linuxContainer) Config() *Config {
|
|||
}
|
||||
|
||||
func (c *linuxContainer) RunState() (RunState, error) {
|
||||
panic("not implemented")
|
||||
return Destroyed, nil // FIXME return a real state
|
||||
}
|
||||
|
||||
func (c *linuxContainer) Processes() ([]int, error) {
|
||||
|
@ -53,8 +61,77 @@ func (c *linuxContainer) Stats() (*ContainerStats, error) {
|
|||
}
|
||||
|
||||
func (c *linuxContainer) StartProcess(config *ProcessConfig) (int, error) {
|
||||
glog.Info("start new container process")
|
||||
panic("not implemented")
|
||||
state, err := c.RunState()
|
||||
if err != nil {
|
||||
return -1, err
|
||||
}
|
||||
|
||||
if state != Destroyed {
|
||||
glog.Info("start new container process")
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
if err := c.startInitProcess(config); err != nil {
|
||||
return -1, err
|
||||
}
|
||||
|
||||
return c.state.InitPid, nil
|
||||
}
|
||||
|
||||
func (c *linuxContainer) updateStateFile() error {
|
||||
data, err := json.MarshalIndent(c.state, "", "\t")
|
||||
if err != nil {
|
||||
return newGenericError(err, SystemError)
|
||||
}
|
||||
|
||||
fnew := filepath.Join(c.root, fmt.Sprintf("%s.new", stateFilename))
|
||||
f, err := os.Create(fnew)
|
||||
if err != nil {
|
||||
return newGenericError(err, SystemError)
|
||||
}
|
||||
|
||||
_, err = f.Write(data)
|
||||
if err != nil {
|
||||
f.Close()
|
||||
return newGenericError(err, SystemError)
|
||||
}
|
||||
f.Close()
|
||||
|
||||
fname := filepath.Join(c.root, stateFilename)
|
||||
if err := os.Rename(fnew, fname); err != nil {
|
||||
return newGenericError(err, SystemError)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *linuxContainer) startInitProcess(config *ProcessConfig) error {
|
||||
cmd := exec.Command(c.initArgs[0], append(c.initArgs[1:], config.Args...)...)
|
||||
cmd.Stdin = config.Stdin
|
||||
cmd.Stdout = config.Stdout
|
||||
cmd.Stderr = config.Stderr
|
||||
|
||||
cmd.Env = config.Env
|
||||
cmd.Dir = c.config.RootFs
|
||||
|
||||
if cmd.SysProcAttr == nil {
|
||||
cmd.SysProcAttr = &syscall.SysProcAttr{}
|
||||
}
|
||||
|
||||
cmd.SysProcAttr.Pdeathsig = syscall.SIGKILL
|
||||
|
||||
//FIXME call namespaces.Exec()
|
||||
if err := cmd.Start(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
c.state.InitPid = cmd.Process.Pid
|
||||
err := c.updateStateFile()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *linuxContainer) Destroy() error {
|
||||
|
@ -67,8 +144,8 @@ func (c *linuxContainer) Destroy() error {
|
|||
return newGenericError(nil, ContainerNotStopped)
|
||||
}
|
||||
|
||||
glog.Info("destroy container")
|
||||
panic("not implemented")
|
||||
os.RemoveAll(c.root)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *linuxContainer) Pause() error {
|
||||
|
|
|
@ -23,23 +23,30 @@ var (
|
|||
)
|
||||
|
||||
// New returns a linux based container factory based in the root directory.
|
||||
func New(root string) (Factory, error) {
|
||||
if err := os.MkdirAll(root, 0700); err != nil {
|
||||
return nil, newGenericError(err, SystemError)
|
||||
func New(root string, initArgs []string) (Factory, error) {
|
||||
if root != "" {
|
||||
if err := os.MkdirAll(root, 0700); err != nil {
|
||||
return nil, newGenericError(err, SystemError)
|
||||
}
|
||||
}
|
||||
|
||||
return &linuxFactory{
|
||||
root: root,
|
||||
root: root,
|
||||
initArgs: initArgs,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// linuxFactory implements the default factory interface for linux based systems.
|
||||
type linuxFactory struct {
|
||||
// root is the root directory
|
||||
root string
|
||||
root string
|
||||
initArgs []string
|
||||
}
|
||||
|
||||
func (l *linuxFactory) Create(id string, config *Config) (Container, error) {
|
||||
if l.root == "" {
|
||||
return nil, newGenericError(fmt.Errorf("invalid root"), ConfigInvalid)
|
||||
}
|
||||
if !idRegex.MatchString(id) {
|
||||
return nil, newGenericError(fmt.Errorf("Invalid id format: %v", id), InvalidIdFormat)
|
||||
}
|
||||
|
@ -56,10 +63,43 @@ func (l *linuxFactory) Create(id string, config *Config) (Container, error) {
|
|||
return nil, newGenericError(err, SystemError)
|
||||
}
|
||||
|
||||
panic("not implemented")
|
||||
data, err := json.MarshalIndent(config, "", "\t")
|
||||
if err != nil {
|
||||
return nil, newGenericError(err, SystemError)
|
||||
}
|
||||
|
||||
if err := os.MkdirAll(containerRoot, 0700); err != nil {
|
||||
return nil, newGenericError(err, SystemError)
|
||||
}
|
||||
|
||||
f, err := os.Create(filepath.Join(containerRoot, configFilename))
|
||||
if err != nil {
|
||||
os.RemoveAll(containerRoot)
|
||||
return nil, newGenericError(err, SystemError)
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
_, err = f.Write(data)
|
||||
if err != nil {
|
||||
os.RemoveAll(containerRoot)
|
||||
return nil, newGenericError(err, SystemError)
|
||||
}
|
||||
|
||||
cgroupManager := NewCgroupManager()
|
||||
return &linuxContainer{
|
||||
id: id,
|
||||
root: containerRoot,
|
||||
config: config,
|
||||
initArgs: l.initArgs,
|
||||
state: &State{},
|
||||
cgroupManager: cgroupManager,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (l *linuxFactory) Load(id string) (Container, error) {
|
||||
if l.root == "" {
|
||||
return nil, newGenericError(fmt.Errorf("invalid root"), ConfigInvalid)
|
||||
}
|
||||
containerRoot := filepath.Join(l.root, id)
|
||||
glog.Infof("loading container config from %s", containerRoot)
|
||||
config, err := l.loadContainerConfig(containerRoot)
|
||||
|
@ -81,6 +121,7 @@ func (l *linuxFactory) Load(id string) (Container, error) {
|
|||
config: config,
|
||||
state: state,
|
||||
cgroupManager: cgroupManager,
|
||||
initArgs: l.initArgs,
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
@ -117,3 +158,11 @@ func (l *linuxFactory) loadContainerState(root string) (*State, error) {
|
|||
}
|
||||
return state, nil
|
||||
}
|
||||
|
||||
// StartInitialization loads a container by opening the pipe fd from the parent to read the configuration and state
|
||||
// This is a low level implementation detail of the reexec and should not be consumed externally
|
||||
func (f *linuxFactory) StartInitialization(pipefd uintptr) (err error) {
|
||||
|
||||
/* FIXME call namespaces.Init() */
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -28,7 +28,7 @@ func TestFactoryNew(t *testing.T) {
|
|||
}
|
||||
defer os.RemoveAll(root)
|
||||
|
||||
factory, err := New(root)
|
||||
factory, err := New(root, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -54,7 +54,7 @@ func TestFactoryLoadNotExists(t *testing.T) {
|
|||
}
|
||||
defer os.RemoveAll(root)
|
||||
|
||||
factory, err := New(root)
|
||||
factory, err := New(root, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -101,7 +101,7 @@ func TestFactoryLoadContainer(t *testing.T) {
|
|||
t.Fatal(err)
|
||||
}
|
||||
|
||||
factory, err := New(root)
|
||||
factory, err := New(root, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue