mirror of
https://github.com/clearlinux/docker.git
synced 2026-10-03 23:38:24 +00:00
Fix exec driver flag, rename new driver to 'native'
Docker-DCO-1.1-Signed-off-by: Michael Crosby <michael@crosbymichael.com> (github: crosbymichael)
This commit is contained in:
@@ -0,0 +1,41 @@
|
||||
package native
|
||||
|
||||
import (
|
||||
"github.com/dotcloud/docker/pkg/cgroups"
|
||||
"github.com/dotcloud/docker/pkg/libcontainer"
|
||||
)
|
||||
|
||||
// getDefaultTemplate returns the docker default for
|
||||
// the libcontainer configuration file
|
||||
func getDefaultTemplate() *libcontainer.Container {
|
||||
return &libcontainer.Container{
|
||||
Capabilities: libcontainer.Capabilities{
|
||||
libcontainer.CAP_SETPCAP,
|
||||
libcontainer.CAP_SYS_MODULE,
|
||||
libcontainer.CAP_SYS_RAWIO,
|
||||
libcontainer.CAP_SYS_PACCT,
|
||||
libcontainer.CAP_SYS_ADMIN,
|
||||
libcontainer.CAP_SYS_NICE,
|
||||
libcontainer.CAP_SYS_RESOURCE,
|
||||
libcontainer.CAP_SYS_TIME,
|
||||
libcontainer.CAP_SYS_TTY_CONFIG,
|
||||
libcontainer.CAP_MKNOD,
|
||||
libcontainer.CAP_AUDIT_WRITE,
|
||||
libcontainer.CAP_AUDIT_CONTROL,
|
||||
libcontainer.CAP_MAC_ADMIN,
|
||||
libcontainer.CAP_MAC_OVERRIDE,
|
||||
libcontainer.CAP_NET_ADMIN,
|
||||
},
|
||||
Namespaces: libcontainer.Namespaces{
|
||||
libcontainer.CLONE_NEWIPC,
|
||||
libcontainer.CLONE_NEWNET,
|
||||
libcontainer.CLONE_NEWNS,
|
||||
libcontainer.CLONE_NEWPID,
|
||||
libcontainer.CLONE_NEWUTS,
|
||||
},
|
||||
Cgroups: &cgroups.Cgroup{
|
||||
Parent: "docker",
|
||||
DeviceAccess: false,
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,315 @@
|
||||
package native
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/dotcloud/docker/execdriver"
|
||||
"github.com/dotcloud/docker/execdriver/lxc"
|
||||
"github.com/dotcloud/docker/pkg/cgroups"
|
||||
"github.com/dotcloud/docker/pkg/libcontainer"
|
||||
"github.com/dotcloud/docker/pkg/libcontainer/nsinit"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
const (
|
||||
DriverName = "namespaces"
|
||||
Version = "0.1"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrNotSupported = errors.New("not supported")
|
||||
noOpLog = log.New(ioutil.Discard, "[nsinit] ", log.LstdFlags)
|
||||
)
|
||||
|
||||
func init() {
|
||||
execdriver.RegisterInitFunc(DriverName, func(args *execdriver.InitArgs) error {
|
||||
var container *libcontainer.Container
|
||||
f, err := os.Open("container.json")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := json.NewDecoder(f).Decode(&container); err != nil {
|
||||
f.Close()
|
||||
return err
|
||||
}
|
||||
f.Close()
|
||||
|
||||
cwd, err := os.Getwd()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
syncPipe, err := nsinit.NewSyncPipeFromFd(0, uintptr(args.Pipe))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ns := nsinit.NewNsInit(noOpLog, "", &nsinit.DefaultCommandFactory{}, &nsinit.DefaultStateWriter{})
|
||||
if err := ns.Init(container, cwd, args.Console, syncPipe, args.Args); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
type driver struct {
|
||||
root string
|
||||
}
|
||||
|
||||
type info struct {
|
||||
ID string
|
||||
driver *driver
|
||||
}
|
||||
|
||||
func (i *info) IsRunning() bool {
|
||||
p := filepath.Join(i.driver.root, "containers", i.ID, "root", ".nspid")
|
||||
if _, err := os.Stat(p); err == nil {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func NewDriver(root string) (*driver, error) {
|
||||
return &driver{
|
||||
root: root,
|
||||
}, 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},
|
||||
}
|
||||
)
|
||||
ns := nsinit.NewNsInit(noOpLog, "", factory, stateWriter)
|
||||
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 ns.Exec(container, term, args)
|
||||
}
|
||||
|
||||
func (d *driver) Kill(p *execdriver.Command, sig int) error {
|
||||
return syscall.Kill(p.Process.Pid, syscall.Signal(sig))
|
||||
}
|
||||
|
||||
func (d *driver) Restore(c *execdriver.Command) error {
|
||||
var (
|
||||
nspid int
|
||||
p = filepath.Join(d.root, "containers", c.ID, "root", ".nspid")
|
||||
)
|
||||
f, err := os.Open(p)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer f.Close()
|
||||
if _, err := fmt.Fscanf(f, "%d", &nspid); err != nil {
|
||||
return err
|
||||
}
|
||||
proc, err := os.FindProcess(nspid)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = proc.Wait()
|
||||
return err
|
||||
}
|
||||
|
||||
func (d *driver) Info(id string) execdriver.Info {
|
||||
return &info{
|
||||
ID: id,
|
||||
driver: d,
|
||||
}
|
||||
}
|
||||
|
||||
func (d *driver) Name() string {
|
||||
return fmt.Sprintf("%s-%s", DriverName, Version)
|
||||
}
|
||||
|
||||
func (d *driver) GetPidsForContainer(id string) ([]int, error) {
|
||||
pids := []int{}
|
||||
|
||||
subsystem := "devices"
|
||||
cgroupRoot, err := cgroups.FindCgroupMountpoint(subsystem)
|
||||
if err != nil {
|
||||
return pids, err
|
||||
}
|
||||
cgroupDir, err := cgroups.GetThisCgroupDir(subsystem)
|
||||
if err != nil {
|
||||
return pids, err
|
||||
}
|
||||
|
||||
filename := filepath.Join(cgroupRoot, cgroupDir, id, "tasks")
|
||||
if _, err := os.Stat(filename); os.IsNotExist(err) {
|
||||
filename = filepath.Join(cgroupRoot, cgroupDir, "docker", id, "tasks")
|
||||
}
|
||||
|
||||
output, err := ioutil.ReadFile(filename)
|
||||
if err != nil {
|
||||
return pids, err
|
||||
}
|
||||
for _, p := range strings.Split(string(output), "\n") {
|
||||
if len(p) == 0 {
|
||||
continue
|
||||
}
|
||||
pid, err := strconv.Atoi(p)
|
||||
if err != nil {
|
||||
return pids, fmt.Errorf("Invalid pid '%s': %s", p, err)
|
||||
}
|
||||
pids = append(pids, pid)
|
||||
}
|
||||
return pids, nil
|
||||
}
|
||||
|
||||
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
|
||||
// we need to join the rootfs because nsinit will setup the rootfs and chroot
|
||||
initPath := filepath.Join(c.Rootfs, c.InitPath)
|
||||
|
||||
c.Path = initPath
|
||||
c.Args = append([]string{
|
||||
initPath,
|
||||
"-driver", DriverName,
|
||||
"-console", console,
|
||||
"-pipe", fmt.Sprint(syncFd),
|
||||
"-log", logFile,
|
||||
}, 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,
|
||||
},
|
||||
}
|
||||
}
|
||||
container.Cgroups.Name = c.ID
|
||||
if c.Privileged {
|
||||
container.Capabilities = nil
|
||||
container.Cgroups.DeviceAccess = true
|
||||
}
|
||||
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
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package native
|
||||
|
||||
import (
|
||||
"github.com/dotcloud/docker/execdriver"
|
||||
"github.com/dotcloud/docker/pkg/term"
|
||||
"os"
|
||||
)
|
||||
|
||||
type NsinitTerm struct {
|
||||
master *os.File
|
||||
}
|
||||
|
||||
func NewTerm(pipes *execdriver.Pipes, master *os.File) *NsinitTerm {
|
||||
return &NsinitTerm{master}
|
||||
}
|
||||
|
||||
func (t *NsinitTerm) Close() error {
|
||||
return t.master.Close()
|
||||
}
|
||||
|
||||
func (t *NsinitTerm) Resize(h, w int) error {
|
||||
if t.master != nil {
|
||||
return term.SetWinsize(t.master.Fd(), &term.Winsize{Height: uint16(h), Width: uint16(w)})
|
||||
}
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user