1
0
Fork 0
mirror of https://github.com/moby/moby.git synced 2022-11-09 12:21:53 -05:00
moby--moby/execdriver/namespaces/driver.go

217 lines
4.7 KiB
Go
Raw Normal View History

package namespaces
import (
"encoding/json"
"errors"
"fmt"
"github.com/dotcloud/docker/execdriver"
"github.com/dotcloud/docker/execdriver/lxc"
"github.com/dotcloud/docker/pkg/libcontainer"
"github.com/dotcloud/docker/pkg/libcontainer/nsinit"
"io"
"io/ioutil"
"os"
"os/exec"
"path/filepath"
"strings"
"syscall"
)
const (
DriverName = "namespaces"
Version = "0.1"
)
var (
ErrNotSupported = errors.New("not supported")
)
func init() {
execdriver.RegisterInitFunc(DriverName, func(args *execdriver.InitArgs) error {
return nil
})
}
type driver struct {
}
func NewDriver() (*driver, error) {
return &driver{}, nil
}
func (d *driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, startCallback execdriver.StartCallback) (int, error) {
var (
term nsinit.Terminal
container = createContainer(c)
factory = &dockerCommandFactory{c}
stateWriter = &dockerStateWriter{
callback: startCallback,
c: c,
dsw: &nsinit.DefaultStateWriter{c.Rootfs},
}
)
if c.Tty {
term = &dockerTtyTerm{
pipes: pipes,
}
} else {
term = &dockerStdTerm{
pipes: pipes,
}
}
c.Terminal = term
if err := writeContainerFile(container, c.Rootfs); err != nil {
return -1, err
}
args := append([]string{c.Entrypoint}, c.Arguments...)
return nsinit.Exec(container, factory, stateWriter, term, "/nsinit.log", args)
}
func (d *driver) Kill(p *execdriver.Command, sig int) error {
return p.Process.Kill()
}
func (d *driver) Restore(c *execdriver.Command) error {
return ErrNotSupported
}
func (d *driver) Info(id string) execdriver.Info {
return nil
}
func (d *driver) Name() string {
return fmt.Sprintf("%s-%s", DriverName, Version)
}
func (d *driver) GetPidsForContainer(id string) ([]int, error) {
return nil, ErrNotSupported
}
func writeContainerFile(container *libcontainer.Container, rootfs string) error {
data, err := json.Marshal(container)
if err != nil {
return err
}
return ioutil.WriteFile(filepath.Join(rootfs, "container.json"), data, 0755)
}
func getEnv(key string, env []string) string {
for _, pair := range env {
parts := strings.Split(pair, "=")
if parts[0] == key {
return parts[1]
}
}
return ""
}
type dockerCommandFactory struct {
c *execdriver.Command
}
// createCommand will return an exec.Cmd with the Cloneflags set to the proper namespaces
// defined on the container's configuration and use the current binary as the init with the
// args provided
func (d *dockerCommandFactory) Create(container *libcontainer.Container,
console, logFile string, syncFd uintptr, args []string) *exec.Cmd {
c := d.c
aname, _ := exec.LookPath("nsinit")
c.Path = aname
c.Args = append([]string{
aname,
"-console", console,
"-pipe", fmt.Sprint(syncFd),
"-log", logFile,
"init",
}, args...)
c.SysProcAttr = &syscall.SysProcAttr{
Cloneflags: uintptr(nsinit.GetNamespaceFlags(container.Namespaces)),
}
c.Env = container.Env
c.Dir = c.Rootfs
return &c.Cmd
}
type dockerStateWriter struct {
dsw nsinit.StateWriter
c *execdriver.Command
callback execdriver.StartCallback
}
func (d *dockerStateWriter) WritePid(pid int) error {
err := d.dsw.WritePid(pid)
if d.callback != nil {
d.callback(d.c)
}
return err
}
func (d *dockerStateWriter) DeletePid() error {
return d.dsw.DeletePid()
}
func createContainer(c *execdriver.Command) *libcontainer.Container {
container := getDefaultTemplate()
container.Hostname = getEnv("HOSTNAME", c.Env)
container.Tty = c.Tty
container.User = c.User
container.WorkingDir = c.WorkingDir
container.Env = c.Env
container.Env = append(container.Env, "container=docker")
if c.Network != nil {
container.Network = &libcontainer.Network{
Mtu: c.Network.Mtu,
Address: fmt.Sprintf("%s/%d", c.Network.IPAddress, c.Network.IPPrefixLen),
Gateway: c.Network.Gateway,
Type: "veth",
Context: libcontainer.Context{
"prefix": "dock",
"bridge": c.Network.Bridge,
},
}
}
if c.Privileged {
container.Capabilities = nil
}
if c.Resources != nil {
container.Cgroups.CpuShares = c.Resources.CpuShares
container.Cgroups.Memory = c.Resources.Memory
container.Cgroups.MemorySwap = c.Resources.MemorySwap
}
return container
}
type dockerStdTerm struct {
lxc.StdConsole
pipes *execdriver.Pipes
}
func (d *dockerStdTerm) Attach(cmd *exec.Cmd) error {
return d.AttachPipes(cmd, d.pipes)
}
func (d *dockerStdTerm) SetMaster(master *os.File) {
// do nothing
}
type dockerTtyTerm struct {
lxc.TtyConsole
pipes *execdriver.Pipes
}
func (t *dockerTtyTerm) Attach(cmd *exec.Cmd) error {
go io.Copy(t.pipes.Stdout, t.MasterPty)
if t.pipes.Stdin != nil {
go io.Copy(t.MasterPty, t.pipes.Stdin)
}
return nil
}
func (t *dockerTtyTerm) SetMaster(master *os.File) {
t.MasterPty = master
}