Refactoring execdriver.Command and Container structs to support 'docker exec' and other
similar features in the future. Docker-DCO-1.1-Signed-off-by: Vishnu Kannan <vishnuk@google.com> (github: vishh) Upstream-commit: 4aa5da278f49c889d43191f82ff42d3a95266d62 Component: engine
This commit is contained in:
committed by
Michael Crosby
parent
a4859208cd
commit
a7e2cb4124
@ -20,7 +20,7 @@ var (
|
||||
ErrDriverNotFound = errors.New("The requested docker init has not been found")
|
||||
)
|
||||
|
||||
type StartCallback func(*Command)
|
||||
type StartCallback func(*ProcessConfig)
|
||||
|
||||
// Driver specific information based on
|
||||
// processes registered with the driver
|
||||
@ -80,20 +80,27 @@ type Mount struct {
|
||||
Private bool `json:"private"`
|
||||
}
|
||||
|
||||
// Process wrapps an os/exec.Cmd to add more metadata
|
||||
type Command struct {
|
||||
// Describes a process that will be run inside a container.
|
||||
type ProcessConfig struct {
|
||||
exec.Cmd `json:"-"`
|
||||
|
||||
Privileged bool `json:"privileged"`
|
||||
User string `json:"user"`
|
||||
Tty bool `json:"tty"`
|
||||
Entrypoint string `json:"entrypoint"`
|
||||
Arguments []string `json:"arguments"`
|
||||
Terminal Terminal `json:"-"` // standard or tty terminal
|
||||
ContainerPid int `json:"container_pid"` // the pid for the process inside a container
|
||||
Console string `json:"-"` // dev/console path
|
||||
}
|
||||
|
||||
// Process wrapps an os/exec.Cmd to add more metadata
|
||||
type Command struct {
|
||||
ID string `json:"id"`
|
||||
Privileged bool `json:"privileged"`
|
||||
User string `json:"user"`
|
||||
Rootfs string `json:"rootfs"` // root fs of the container
|
||||
InitPath string `json:"initpath"` // dockerinit
|
||||
Entrypoint string `json:"entrypoint"`
|
||||
Arguments []string `json:"arguments"`
|
||||
WorkingDir string `json:"working_dir"`
|
||||
ConfigPath string `json:"config_path"` // this should be able to be removed when the lxc template is moved into the driver
|
||||
Tty bool `json:"tty"`
|
||||
Network *Network `json:"network"`
|
||||
Config map[string][]string `json:"config"` // generic values that specific drivers can consume
|
||||
Resources *Resources `json:"resources"`
|
||||
@ -103,13 +110,11 @@ type Command struct {
|
||||
CapAdd []string `json:"cap_add"`
|
||||
CapDrop []string `json:"cap_drop"`
|
||||
|
||||
Terminal Terminal `json:"-"` // standard or tty terminal
|
||||
Console string `json:"-"` // dev/console path
|
||||
ContainerPid int `json:"container_pid"` // the pid for the process inside a container
|
||||
ProcessConfig ProcessConfig `json:"process_config"` // Describes the init process of the container.
|
||||
}
|
||||
|
||||
// Return the pid of the process
|
||||
// If the process is nil -1 will be returned
|
||||
func (c *Command) Pid() int {
|
||||
return c.ContainerPid
|
||||
func (processConfig *ProcessConfig) Pid() int {
|
||||
return processConfig.ContainerPid
|
||||
}
|
||||
|
||||
@ -59,12 +59,12 @@ func (d *driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, startCallba
|
||||
err error
|
||||
)
|
||||
|
||||
if c.Tty {
|
||||
term, err = NewTtyConsole(c, pipes)
|
||||
if c.ProcessConfig.Tty {
|
||||
term, err = NewTtyConsole(&c.ProcessConfig, pipes)
|
||||
} else {
|
||||
term, err = execdriver.NewStdConsole(c, pipes)
|
||||
term, err = execdriver.NewStdConsole(&c.ProcessConfig, pipes)
|
||||
}
|
||||
c.Terminal = term
|
||||
c.ProcessConfig.Terminal = term
|
||||
|
||||
c.Mounts = append(c.Mounts, execdriver.Mount{
|
||||
Source: d.initPath,
|
||||
@ -98,11 +98,11 @@ func (d *driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, startCallba
|
||||
"-mtu", strconv.Itoa(c.Network.Mtu),
|
||||
)
|
||||
|
||||
if c.User != "" {
|
||||
params = append(params, "-u", c.User)
|
||||
if c.ProcessConfig.User != "" {
|
||||
params = append(params, "-u", c.ProcessConfig.User)
|
||||
}
|
||||
|
||||
if c.Privileged {
|
||||
if c.ProcessConfig.Privileged {
|
||||
if d.apparmor {
|
||||
params[0] = path.Join(d.root, "lxc-start-unconfined")
|
||||
|
||||
@ -122,8 +122,8 @@ func (d *driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, startCallba
|
||||
params = append(params, fmt.Sprintf("-cap-drop=%s", strings.Join(c.CapDrop, ":")))
|
||||
}
|
||||
|
||||
params = append(params, "--", c.Entrypoint)
|
||||
params = append(params, c.Arguments...)
|
||||
params = append(params, "--", c.ProcessConfig.Entrypoint)
|
||||
params = append(params, c.ProcessConfig.Arguments...)
|
||||
|
||||
if d.sharedRoot {
|
||||
// lxc-start really needs / to be non-shared, or all kinds of stuff break
|
||||
@ -149,14 +149,14 @@ func (d *driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, startCallba
|
||||
if err != nil {
|
||||
aname = name
|
||||
}
|
||||
c.Path = aname
|
||||
c.Args = append([]string{name}, arg...)
|
||||
c.ProcessConfig.Path = aname
|
||||
c.ProcessConfig.Args = append([]string{name}, arg...)
|
||||
|
||||
if err := nodes.CreateDeviceNodes(c.Rootfs, c.AutoCreatedDevices); err != nil {
|
||||
return -1, err
|
||||
}
|
||||
|
||||
if err := c.Start(); err != nil {
|
||||
if err := c.ProcessConfig.Start(); err != nil {
|
||||
return -1, err
|
||||
}
|
||||
|
||||
@ -166,7 +166,7 @@ func (d *driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, startCallba
|
||||
)
|
||||
|
||||
go func() {
|
||||
if err := c.Wait(); err != nil {
|
||||
if err := c.ProcessConfig.Wait(); err != nil {
|
||||
if _, ok := err.(*exec.ExitError); !ok { // Do not propagate the error if it's simply a status code != 0
|
||||
waitErr = err
|
||||
}
|
||||
@ -177,17 +177,17 @@ func (d *driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, startCallba
|
||||
// Poll lxc for RUNNING status
|
||||
pid, err := d.waitForStart(c, waitLock)
|
||||
if err != nil {
|
||||
if c.Process != nil {
|
||||
c.Process.Kill()
|
||||
c.Wait()
|
||||
if c.ProcessConfig.Process != nil {
|
||||
c.ProcessConfig.Process.Kill()
|
||||
c.ProcessConfig.Wait()
|
||||
}
|
||||
return -1, err
|
||||
}
|
||||
|
||||
c.ContainerPid = pid
|
||||
c.ProcessConfig.ContainerPid = pid
|
||||
|
||||
if startCallback != nil {
|
||||
startCallback(c)
|
||||
startCallback(&c.ProcessConfig)
|
||||
}
|
||||
|
||||
<-waitLock
|
||||
@ -198,10 +198,10 @@ func (d *driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, startCallba
|
||||
/// Return the exit code of the process
|
||||
// if the process has not exited -1 will be returned
|
||||
func getExitCode(c *execdriver.Command) int {
|
||||
if c.ProcessState == nil {
|
||||
if c.ProcessConfig.ProcessState == nil {
|
||||
return -1
|
||||
}
|
||||
return c.ProcessState.Sys().(syscall.WaitStatus).ExitStatus()
|
||||
return c.ProcessConfig.ProcessState.Sys().(syscall.WaitStatus).ExitStatus()
|
||||
}
|
||||
|
||||
func (d *driver) Kill(c *execdriver.Command, sig int) error {
|
||||
@ -442,7 +442,7 @@ func (d *driver) generateLXCConfig(c *execdriver.Command) (string, error) {
|
||||
}
|
||||
|
||||
func (d *driver) generateEnvConfig(c *execdriver.Command) error {
|
||||
data, err := json.Marshal(c.Env)
|
||||
data, err := json.Marshal(c.ProcessConfig.Env)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -462,7 +462,7 @@ type TtyConsole struct {
|
||||
SlavePty *os.File
|
||||
}
|
||||
|
||||
func NewTtyConsole(command *execdriver.Command, pipes *execdriver.Pipes) (*TtyConsole, error) {
|
||||
func NewTtyConsole(processConfig *execdriver.ProcessConfig, pipes *execdriver.Pipes) (*TtyConsole, error) {
|
||||
// lxc is special in that we cannot create the master outside of the container without
|
||||
// opening the slave because we have nothing to provide to the cmd. We have to open both then do
|
||||
// the crazy setup on command right now instead of passing the console path to lxc and telling it
|
||||
@ -478,12 +478,12 @@ func NewTtyConsole(command *execdriver.Command, pipes *execdriver.Pipes) (*TtyCo
|
||||
SlavePty: ptySlave,
|
||||
}
|
||||
|
||||
if err := tty.AttachPipes(&command.Cmd, pipes); err != nil {
|
||||
if err := tty.AttachPipes(&processConfig.Cmd, pipes); err != nil {
|
||||
tty.Close()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
command.Console = tty.SlavePty.Name()
|
||||
processConfig.Console = tty.SlavePty.Name()
|
||||
|
||||
return tty, nil
|
||||
}
|
||||
|
||||
@ -42,7 +42,7 @@ lxc.se_context = {{ .ProcessLabel}}
|
||||
# no controlling tty at all
|
||||
lxc.tty = 1
|
||||
|
||||
{{if .Privileged}}
|
||||
{{if .ProcessConfig.Privileged}}
|
||||
lxc.cgroup.devices.allow = a
|
||||
{{else}}
|
||||
# no implicit access to devices
|
||||
@ -66,7 +66,7 @@ lxc.pivotdir = lxc_putold
|
||||
lxc.mount.entry = proc {{escapeFstabSpaces $ROOTFS}}/proc proc nosuid,nodev,noexec 0 0
|
||||
lxc.mount.entry = sysfs {{escapeFstabSpaces $ROOTFS}}/sys sysfs nosuid,nodev,noexec 0 0
|
||||
|
||||
{{if .Tty}}
|
||||
{{if .ProcessConfig.Tty}}
|
||||
lxc.mount.entry = {{.Console}} {{escapeFstabSpaces $ROOTFS}}/dev/console none bind,rw 0 0
|
||||
{{end}}
|
||||
|
||||
@ -81,7 +81,7 @@ lxc.mount.entry = {{$value.Source}} {{escapeFstabSpaces $ROOTFS}}/{{escapeFstabS
|
||||
{{end}}
|
||||
{{end}}
|
||||
|
||||
{{if .Privileged}}
|
||||
{{if .ProcessConfig.Privileged}}
|
||||
{{if .AppArmor}}
|
||||
lxc.aa_profile = unconfined
|
||||
{{else}}
|
||||
|
||||
@ -77,9 +77,11 @@ func TestCustomLxcConfig(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
command := &execdriver.Command{
|
||||
ID: "1",
|
||||
processConfig := execdriver.ProcessConfig{
|
||||
Privileged: false,
|
||||
}
|
||||
command := &execdriver.Command{
|
||||
ID: "1",
|
||||
Config: map[string][]string{
|
||||
"lxc": {
|
||||
"lxc.utsname = docker",
|
||||
@ -90,6 +92,7 @@ func TestCustomLxcConfig(t *testing.T) {
|
||||
Mtu: 1500,
|
||||
Interface: nil,
|
||||
},
|
||||
ProcessConfig: processConfig,
|
||||
}
|
||||
|
||||
p, err := driver.generateLXCConfig(command)
|
||||
|
||||
@ -23,11 +23,11 @@ import (
|
||||
func (d *driver) createContainer(c *execdriver.Command) (*libcontainer.Config, error) {
|
||||
container := template.New()
|
||||
|
||||
container.Hostname = getEnv("HOSTNAME", c.Env)
|
||||
container.Tty = c.Tty
|
||||
container.User = c.User
|
||||
container.Hostname = getEnv("HOSTNAME", c.ProcessConfig.Env)
|
||||
container.Tty = c.ProcessConfig.Tty
|
||||
container.User = c.ProcessConfig.User
|
||||
container.WorkingDir = c.WorkingDir
|
||||
container.Env = c.Env
|
||||
container.Env = c.ProcessConfig.Env
|
||||
container.Cgroups.Name = c.ID
|
||||
container.Cgroups.AllowedDevices = c.AllowedDevices
|
||||
container.MountConfig.DeviceNodes = c.AutoCreatedDevices
|
||||
@ -40,7 +40,7 @@ func (d *driver) createContainer(c *execdriver.Command) (*libcontainer.Config, e
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if c.Privileged {
|
||||
if c.ProcessConfig.Privileged {
|
||||
if err := d.setPrivileged(container); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@ -68,26 +68,26 @@ func (d *driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, startCallba
|
||||
|
||||
var term execdriver.Terminal
|
||||
|
||||
if c.Tty {
|
||||
term, err = NewTtyConsole(c, pipes)
|
||||
if c.ProcessConfig.Tty {
|
||||
term, err = NewTtyConsole(&c.ProcessConfig, pipes)
|
||||
} else {
|
||||
term, err = execdriver.NewStdConsole(c, pipes)
|
||||
term, err = execdriver.NewStdConsole(&c.ProcessConfig, pipes)
|
||||
}
|
||||
if err != nil {
|
||||
return -1, err
|
||||
}
|
||||
c.Terminal = term
|
||||
c.ProcessConfig.Terminal = term
|
||||
|
||||
d.Lock()
|
||||
d.activeContainers[c.ID] = &activeContainer{
|
||||
container: container,
|
||||
cmd: &c.Cmd,
|
||||
cmd: &c.ProcessConfig.Cmd,
|
||||
}
|
||||
d.Unlock()
|
||||
|
||||
var (
|
||||
dataPath = filepath.Join(d.root, c.ID)
|
||||
args = append([]string{c.Entrypoint}, c.Arguments...)
|
||||
args = append([]string{c.ProcessConfig.Entrypoint}, c.ProcessConfig.Arguments...)
|
||||
)
|
||||
|
||||
if err := d.createContainerRoot(c.ID); err != nil {
|
||||
@ -99,9 +99,9 @@ func (d *driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, startCallba
|
||||
return -1, err
|
||||
}
|
||||
|
||||
return namespaces.Exec(container, c.Stdin, c.Stdout, c.Stderr, c.Console, c.Rootfs, dataPath, args, func(container *libcontainer.Config, console, rootfs, dataPath, init string, child *os.File, args []string) *exec.Cmd {
|
||||
c.Path = d.initPath
|
||||
c.Args = append([]string{
|
||||
return namespaces.Exec(container, c.ProcessConfig.Stdin, c.ProcessConfig.Stdout, c.ProcessConfig.Stderr, c.ProcessConfig.Console, c.Rootfs, dataPath, args, func(container *libcontainer.Config, console, rootfs, dataPath, init string, child *os.File, args []string) *exec.Cmd {
|
||||
c.ProcessConfig.Path = d.initPath
|
||||
c.ProcessConfig.Args = append([]string{
|
||||
DriverName,
|
||||
"-console", console,
|
||||
"-pipe", "3",
|
||||
@ -110,25 +110,25 @@ func (d *driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, startCallba
|
||||
}, args...)
|
||||
|
||||
// set this to nil so that when we set the clone flags anything else is reset
|
||||
c.SysProcAttr = &syscall.SysProcAttr{
|
||||
c.ProcessConfig.SysProcAttr = &syscall.SysProcAttr{
|
||||
Cloneflags: uintptr(namespaces.GetNamespaceFlags(container.Namespaces)),
|
||||
}
|
||||
c.ExtraFiles = []*os.File{child}
|
||||
c.ProcessConfig.ExtraFiles = []*os.File{child}
|
||||
|
||||
c.Env = container.Env
|
||||
c.Dir = c.Rootfs
|
||||
c.ProcessConfig.Env = container.Env
|
||||
c.ProcessConfig.Dir = c.Rootfs
|
||||
|
||||
return &c.Cmd
|
||||
return &c.ProcessConfig.Cmd
|
||||
}, func() {
|
||||
if startCallback != nil {
|
||||
c.ContainerPid = c.Process.Pid
|
||||
startCallback(c)
|
||||
c.ProcessConfig.ContainerPid = c.ProcessConfig.Process.Pid
|
||||
startCallback(&c.ProcessConfig)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func (d *driver) Kill(p *execdriver.Command, sig int) error {
|
||||
return syscall.Kill(p.Process.Pid, syscall.Signal(sig))
|
||||
return syscall.Kill(p.ProcessConfig.Process.Pid, syscall.Signal(sig))
|
||||
}
|
||||
|
||||
func (d *driver) Pause(c *execdriver.Command) error {
|
||||
@ -176,14 +176,14 @@ func (d *driver) Terminate(p *execdriver.Command) error {
|
||||
state = &libcontainer.State{InitStartTime: string(data)}
|
||||
}
|
||||
|
||||
currentStartTime, err := system.GetProcessStartTime(p.Process.Pid)
|
||||
currentStartTime, err := system.GetProcessStartTime(p.ProcessConfig.Process.Pid)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if state.InitStartTime == currentStartTime {
|
||||
err = syscall.Kill(p.Process.Pid, 9)
|
||||
syscall.Wait4(p.Process.Pid, nil, 0, nil)
|
||||
err = syscall.Kill(p.ProcessConfig.Process.Pid, 9)
|
||||
syscall.Wait4(p.ProcessConfig.Process.Pid, nil, 0, nil)
|
||||
}
|
||||
d.removeContainerRoot(p.ID)
|
||||
|
||||
@ -252,7 +252,7 @@ type TtyConsole struct {
|
||||
MasterPty *os.File
|
||||
}
|
||||
|
||||
func NewTtyConsole(command *execdriver.Command, pipes *execdriver.Pipes) (*TtyConsole, error) {
|
||||
func NewTtyConsole(processConfig *execdriver.ProcessConfig, pipes *execdriver.Pipes) (*TtyConsole, error) {
|
||||
ptyMaster, console, err := consolepkg.CreateMasterAndConsole()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -262,12 +262,12 @@ func NewTtyConsole(command *execdriver.Command, pipes *execdriver.Pipes) (*TtyCo
|
||||
MasterPty: ptyMaster,
|
||||
}
|
||||
|
||||
if err := tty.AttachPipes(&command.Cmd, pipes); err != nil {
|
||||
if err := tty.AttachPipes(&processConfig.Cmd, pipes); err != nil {
|
||||
tty.Close()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
command.Console = console
|
||||
processConfig.Console = console
|
||||
|
||||
return tty, nil
|
||||
}
|
||||
|
||||
@ -8,10 +8,10 @@ import (
|
||||
type StdConsole struct {
|
||||
}
|
||||
|
||||
func NewStdConsole(command *Command, pipes *Pipes) (*StdConsole, error) {
|
||||
func NewStdConsole(processConfig *ProcessConfig, pipes *Pipes) (*StdConsole, error) {
|
||||
std := &StdConsole{}
|
||||
|
||||
if err := std.AttachPipes(&command.Cmd, pipes); err != nil {
|
||||
if err := std.AttachPipes(&processConfig.Cmd, pipes); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return std, nil
|
||||
|
||||
Reference in New Issue
Block a user