Using @mavenugo's patch for enabling the libcontainer pre-start hook to
be used for network namespace initialization (correcting the conflict
with user namespaces); updated the boolean check to the more generic
SupportsHooks() name, and fixed the hook state function signature.
Signed-off-by: Madhu Venugopal <madhu@docker.com>
Docker-DCO-1.1-Signed-off-by: Phil Estes <estesp@linux.vnet.ibm.com> (github: estesp)
| ... | ... |
@@ -811,7 +811,7 @@ func (container *Container) exec(ExecConfig *ExecConfig) error {
|
| 811 | 811 |
container.Lock() |
| 812 | 812 |
defer container.Unlock() |
| 813 | 813 |
|
| 814 |
- callback := func(processConfig *execdriver.ProcessConfig, pid int) {
|
|
| 814 |
+ callback := func(processConfig *execdriver.ProcessConfig, pid int) error {
|
|
| 815 | 815 |
if processConfig.Tty {
|
| 816 | 816 |
// The callback is called after the process Start() |
| 817 | 817 |
// so we are in the parent process. In TTY mode, stdin/out/err is the PtySlave |
| ... | ... |
@@ -821,6 +821,7 @@ func (container *Container) exec(ExecConfig *ExecConfig) error {
|
| 821 | 821 |
} |
| 822 | 822 |
} |
| 823 | 823 |
close(ExecConfig.waitStart) |
| 824 |
+ return nil |
|
| 824 | 825 |
} |
| 825 | 826 |
|
| 826 | 827 |
// We use a callback here instead of a goroutine and an chan for |
| ... | ... |
@@ -837,7 +838,7 @@ func (container *Container) exec(ExecConfig *ExecConfig) error {
|
| 837 | 837 |
return nil |
| 838 | 838 |
} |
| 839 | 839 |
|
| 840 |
-func (container *Container) monitorExec(ExecConfig *ExecConfig, callback execdriver.StartCallback) error {
|
|
| 840 |
+func (container *Container) monitorExec(ExecConfig *ExecConfig, callback execdriver.DriverCallback) error {
|
|
| 841 | 841 |
var ( |
| 842 | 842 |
err error |
| 843 | 843 |
exitCode int |
| ... | ... |
@@ -174,8 +174,9 @@ func getDevicesFromPath(deviceMapping runconfig.DeviceMapping) (devs []*configs. |
| 174 | 174 |
func populateCommand(c *Container, env []string) error {
|
| 175 | 175 |
var en *execdriver.Network |
| 176 | 176 |
if !c.Config.NetworkDisabled {
|
| 177 |
- en = &execdriver.Network{
|
|
| 178 |
- NamespacePath: c.NetworkSettings.SandboxKey, |
|
| 177 |
+ en = &execdriver.Network{}
|
|
| 178 |
+ if !c.daemon.execDriver.SupportsHooks() || c.hostConfig.NetworkMode.IsHost() {
|
|
| 179 |
+ en.NamespacePath = c.NetworkSettings.SandboxKey |
|
| 179 | 180 |
} |
| 180 | 181 |
|
| 181 | 182 |
parts := strings.SplitN(string(c.hostConfig.NetworkMode), ":", 2) |
| ... | ... |
@@ -405,6 +406,10 @@ func (container *Container) buildSandboxOptions() ([]libnetwork.SandboxOption, e |
| 405 | 405 |
sboxOptions = append(sboxOptions, libnetwork.OptionUseDefaultSandbox()) |
| 406 | 406 |
sboxOptions = append(sboxOptions, libnetwork.OptionOriginHostsPath("/etc/hosts"))
|
| 407 | 407 |
sboxOptions = append(sboxOptions, libnetwork.OptionOriginResolvConfPath("/etc/resolv.conf"))
|
| 408 |
+ } else if container.daemon.execDriver.SupportsHooks() {
|
|
| 409 |
+ // OptionUseExternalKey is mandatory for userns support. |
|
| 410 |
+ // But optional for non-userns support |
|
| 411 |
+ sboxOptions = append(sboxOptions, libnetwork.OptionUseExternalKey()) |
|
| 408 | 412 |
} |
| 409 | 413 |
|
| 410 | 414 |
container.HostsPath, err = container.getRootResourcePath("hosts")
|
| ... | ... |
@@ -947,6 +952,20 @@ func (container *Container) initializeNetworking() error {
|
| 947 | 947 |
return container.buildHostnameFile() |
| 948 | 948 |
} |
| 949 | 949 |
|
| 950 |
+// called from the libcontainer pre-start hook to set the network |
|
| 951 |
+// namespace configuration linkage to the libnetwork "sandbox" entity |
|
| 952 |
+func (container *Container) setNetworkNamespaceKey(pid int) error {
|
|
| 953 |
+ path := fmt.Sprintf("/proc/%d/ns/net", pid)
|
|
| 954 |
+ var sandbox libnetwork.Sandbox |
|
| 955 |
+ search := libnetwork.SandboxContainerWalker(&sandbox, container.ID) |
|
| 956 |
+ container.daemon.netController.WalkSandboxes(search) |
|
| 957 |
+ if sandbox == nil {
|
|
| 958 |
+ return fmt.Errorf("no sandbox present for %s", container.ID)
|
|
| 959 |
+ } |
|
| 960 |
+ |
|
| 961 |
+ return sandbox.SetKey(path) |
|
| 962 |
+} |
|
| 963 |
+ |
|
| 950 | 964 |
func (container *Container) getIpcContainer() (*Container, error) {
|
| 951 | 965 |
containerID := container.hostConfig.IpcMode.Container() |
| 952 | 966 |
c, err := container.daemon.Get(containerID) |
| ... | ... |
@@ -138,6 +138,11 @@ func (container *Container) getSize() (int64, int64) {
|
| 138 | 138 |
return 0, 0 |
| 139 | 139 |
} |
| 140 | 140 |
|
| 141 |
+// setNetworkNamespaceKey is a no-op on Windows. |
|
| 142 |
+func (container *Container) setNetworkNamespaceKey(pid int) error {
|
|
| 143 |
+ return nil |
|
| 144 |
+} |
|
| 145 |
+ |
|
| 141 | 146 |
// allocateNetwork is a no-op on Windows. |
| 142 | 147 |
func (container *Container) allocateNetwork() error {
|
| 143 | 148 |
return nil |
| ... | ... |
@@ -875,8 +875,14 @@ func (daemon *Daemon) unmount(container *Container) error {
|
| 875 | 875 |
return nil |
| 876 | 876 |
} |
| 877 | 877 |
|
| 878 |
-func (daemon *Daemon) run(c *Container, pipes *execdriver.Pipes, startCallback execdriver.StartCallback) (execdriver.ExitStatus, error) {
|
|
| 879 |
- return daemon.execDriver.Run(c.command, pipes, startCallback) |
|
| 878 |
+func (daemon *Daemon) run(c *Container, pipes *execdriver.Pipes, startCallback execdriver.DriverCallback) (execdriver.ExitStatus, error) {
|
|
| 879 |
+ hooks := execdriver.Hooks{
|
|
| 880 |
+ Start: startCallback, |
|
| 881 |
+ } |
|
| 882 |
+ hooks.PreStart = append(hooks.PreStart, func(processConfig *execdriver.ProcessConfig, pid int) error {
|
|
| 883 |
+ return c.setNetworkNamespaceKey(pid) |
|
| 884 |
+ }) |
|
| 885 |
+ return daemon.execDriver.Run(c.command, pipes, hooks) |
|
| 880 | 886 |
} |
| 881 | 887 |
|
| 882 | 888 |
func (daemon *Daemon) kill(c *Container, sig int) error {
|
| ... | ... |
@@ -267,8 +267,11 @@ func (d *Daemon) ContainerExecStart(execName string, stdin io.ReadCloser, stdout |
| 267 | 267 |
} |
| 268 | 268 |
|
| 269 | 269 |
// Exec calls the underlying exec driver to run |
| 270 |
-func (d *Daemon) Exec(c *Container, ExecConfig *ExecConfig, pipes *execdriver.Pipes, startCallback execdriver.StartCallback) (int, error) {
|
|
| 271 |
- exitStatus, err := d.execDriver.Exec(c.command, ExecConfig.ProcessConfig, pipes, startCallback) |
|
| 270 |
+func (d *Daemon) Exec(c *Container, ExecConfig *ExecConfig, pipes *execdriver.Pipes, startCallback execdriver.DriverCallback) (int, error) {
|
|
| 271 |
+ hooks := execdriver.Hooks{
|
|
| 272 |
+ Start: startCallback, |
|
| 273 |
+ } |
|
| 274 |
+ exitStatus, err := d.execDriver.Exec(c.command, ExecConfig.ProcessConfig, pipes, hooks) |
|
| 272 | 275 |
|
| 273 | 276 |
// On err, make sure we don't leave ExitCode at zero |
| 274 | 277 |
if err != nil && exitStatus == 0 {
|
| ... | ... |
@@ -24,10 +24,22 @@ var ( |
| 24 | 24 |
ErrDriverNotFound = errors.New("The requested docker init has not been found")
|
| 25 | 25 |
) |
| 26 | 26 |
|
| 27 |
-// StartCallback defines a callback function. |
|
| 28 |
-// It's used by 'Run' and 'Exec', does some work in parent process |
|
| 29 |
-// after child process is started. |
|
| 30 |
-type StartCallback func(*ProcessConfig, int) |
|
| 27 |
+// DriverCallback defines a callback function which is used in "Run" and "Exec". |
|
| 28 |
+// This allows work to be done in the parent process when the child is passing |
|
| 29 |
+// through PreStart, Start and PostStop events. |
|
| 30 |
+// Callbacks are provided a processConfig pointer and the pid of the child |
|
| 31 |
+type DriverCallback func(processConfig *ProcessConfig, pid int) error |
|
| 32 |
+ |
|
| 33 |
+// Hooks is a struct containing function pointers to callbacks |
|
| 34 |
+// used by any execdriver implementation exploiting hooks capabilities |
|
| 35 |
+type Hooks struct {
|
|
| 36 |
+ // PreStart is called before container's CMD/ENTRYPOINT is executed |
|
| 37 |
+ PreStart []DriverCallback |
|
| 38 |
+ // Start is called after the container's process is full started |
|
| 39 |
+ Start DriverCallback |
|
| 40 |
+ // PostStop is called after the container process exits |
|
| 41 |
+ PostStop []DriverCallback |
|
| 42 |
+} |
|
| 31 | 43 |
|
| 32 | 44 |
// Info is driver specific information based on |
| 33 | 45 |
// processes registered with the driver |
| ... | ... |
@@ -56,11 +68,11 @@ type ExitStatus struct {
|
| 56 | 56 |
type Driver interface {
|
| 57 | 57 |
// Run executes the process, blocks until the process exits and returns |
| 58 | 58 |
// the exit code. It's the last stage on Docker side for running a container. |
| 59 |
- Run(c *Command, pipes *Pipes, startCallback StartCallback) (ExitStatus, error) |
|
| 59 |
+ Run(c *Command, pipes *Pipes, hooks Hooks) (ExitStatus, error) |
|
| 60 | 60 |
|
| 61 | 61 |
// Exec executes the process in an existing container, blocks until the |
| 62 | 62 |
// process exits and returns the exit code. |
| 63 |
- Exec(c *Command, processConfig *ProcessConfig, pipes *Pipes, startCallback StartCallback) (int, error) |
|
| 63 |
+ Exec(c *Command, processConfig *ProcessConfig, pipes *Pipes, hooks Hooks) (int, error) |
|
| 64 | 64 |
|
| 65 | 65 |
// Kill sends signals to process in container. |
| 66 | 66 |
Kill(c *Command, sig int) error |
| ... | ... |
@@ -89,6 +101,9 @@ type Driver interface {
|
| 89 | 89 |
|
| 90 | 90 |
// Stats returns resource stats for a running container |
| 91 | 91 |
Stats(id string) (*ResourceStats, error) |
| 92 |
+ |
|
| 93 |
+ // SupportsHooks refers to the driver capability to exploit pre/post hook functionality |
|
| 94 |
+ SupportsHooks() bool |
|
| 92 | 95 |
} |
| 93 | 96 |
|
| 94 | 97 |
// Ipc settings of the container |
| ... | ... |
@@ -125,7 +125,7 @@ func killNetNsProc(proc *os.Process) {
|
| 125 | 125 |
|
| 126 | 126 |
// Run implements the exec driver Driver interface, |
| 127 | 127 |
// it calls 'exec.Cmd' to launch lxc commands to run a container. |
| 128 |
-func (d *Driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, startCallback execdriver.StartCallback) (execdriver.ExitStatus, error) {
|
|
| 128 |
+func (d *Driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, hooks execdriver.Hooks) (execdriver.ExitStatus, error) {
|
|
| 129 | 129 |
var ( |
| 130 | 130 |
term execdriver.Terminal |
| 131 | 131 |
err error |
| ... | ... |
@@ -324,9 +324,9 @@ func (d *Driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, startCallba |
| 324 | 324 |
|
| 325 | 325 |
c.ContainerPid = pid |
| 326 | 326 |
|
| 327 |
- if startCallback != nil {
|
|
| 327 |
+ if hooks.Start != nil {
|
|
| 328 | 328 |
logrus.Debugf("Invoking startCallback")
|
| 329 |
- startCallback(&c.ProcessConfig, pid) |
|
| 329 |
+ hooks.Start(&c.ProcessConfig, pid) |
|
| 330 | 330 |
} |
| 331 | 331 |
|
| 332 | 332 |
oomKill := false |
| ... | ... |
@@ -870,7 +870,7 @@ func (t *TtyConsole) Close() error {
|
| 870 | 870 |
|
| 871 | 871 |
// Exec implements the exec driver Driver interface, |
| 872 | 872 |
// it is not implemented by lxc. |
| 873 |
-func (d *Driver) Exec(c *execdriver.Command, processConfig *execdriver.ProcessConfig, pipes *execdriver.Pipes, startCallback execdriver.StartCallback) (int, error) {
|
|
| 873 |
+func (d *Driver) Exec(c *execdriver.Command, processConfig *execdriver.ProcessConfig, pipes *execdriver.Pipes, hooks execdriver.Hooks) (int, error) {
|
|
| 874 | 874 |
return -1, ErrExec |
| 875 | 875 |
} |
| 876 | 876 |
|
| ... | ... |
@@ -883,3 +883,9 @@ func (d *Driver) Stats(id string) (*execdriver.ResourceStats, error) {
|
| 883 | 883 |
} |
| 884 | 884 |
return execdriver.Stats(d.containerDir(id), d.activeContainers[id].container.Cgroups.Memory, d.machineMemory) |
| 885 | 885 |
} |
| 886 |
+ |
|
| 887 |
+// SupportsHooks implements the execdriver Driver interface. |
|
| 888 |
+// The LXC execdriver does not support the hook mechanism, which is currently unique to runC/libcontainer. |
|
| 889 |
+func (d *Driver) SupportsHooks() bool {
|
|
| 890 |
+ return false |
|
| 891 |
+} |
| ... | ... |
@@ -18,7 +18,7 @@ import ( |
| 18 | 18 |
|
| 19 | 19 |
// createContainer populates and configures the container type with the |
| 20 | 20 |
// data provided by the execdriver.Command |
| 21 |
-func (d *Driver) createContainer(c *execdriver.Command) (*configs.Config, error) {
|
|
| 21 |
+func (d *Driver) createContainer(c *execdriver.Command, hooks execdriver.Hooks) (*configs.Config, error) {
|
|
| 22 | 22 |
container := execdriver.InitContainer(c) |
| 23 | 23 |
|
| 24 | 24 |
if err := d.createIpc(container, c); err != nil {
|
| ... | ... |
@@ -33,7 +33,7 @@ func (d *Driver) createContainer(c *execdriver.Command) (*configs.Config, error) |
| 33 | 33 |
return nil, err |
| 34 | 34 |
} |
| 35 | 35 |
|
| 36 |
- if err := d.createNetwork(container, c); err != nil {
|
|
| 36 |
+ if err := d.createNetwork(container, c, hooks); err != nil {
|
|
| 37 | 37 |
return nil, err |
| 38 | 38 |
} |
| 39 | 39 |
|
| ... | ... |
@@ -113,7 +113,7 @@ func generateIfaceName() (string, error) {
|
| 113 | 113 |
return "", errors.New("Failed to find name for new interface")
|
| 114 | 114 |
} |
| 115 | 115 |
|
| 116 |
-func (d *Driver) createNetwork(container *configs.Config, c *execdriver.Command) error {
|
|
| 116 |
+func (d *Driver) createNetwork(container *configs.Config, c *execdriver.Command, hooks execdriver.Hooks) error {
|
|
| 117 | 117 |
if c.Network == nil {
|
| 118 | 118 |
return nil |
| 119 | 119 |
} |
| ... | ... |
@@ -135,11 +135,26 @@ func (d *Driver) createNetwork(container *configs.Config, c *execdriver.Command) |
| 135 | 135 |
return nil |
| 136 | 136 |
} |
| 137 | 137 |
|
| 138 |
- if c.Network.NamespacePath == "" {
|
|
| 139 |
- return fmt.Errorf("network namespace path is empty")
|
|
| 138 |
+ if c.Network.NamespacePath != "" {
|
|
| 139 |
+ container.Namespaces.Add(configs.NEWNET, c.Network.NamespacePath) |
|
| 140 |
+ return nil |
|
| 141 |
+ } |
|
| 142 |
+ // only set up prestart hook if the namespace path is not set (this should be |
|
| 143 |
+ // all cases *except* for --net=host shared networking) |
|
| 144 |
+ container.Hooks = &configs.Hooks{
|
|
| 145 |
+ Prestart: []configs.Hook{
|
|
| 146 |
+ configs.NewFunctionHook(func(s configs.HookState) error {
|
|
| 147 |
+ if len(hooks.PreStart) > 0 {
|
|
| 148 |
+ for _, fnHook := range hooks.PreStart {
|
|
| 149 |
+ if err := fnHook(&c.ProcessConfig, s.Pid); err != nil {
|
|
| 150 |
+ return err |
|
| 151 |
+ } |
|
| 152 |
+ } |
|
| 153 |
+ } |
|
| 154 |
+ return nil |
|
| 155 |
+ }), |
|
| 156 |
+ }, |
|
| 140 | 157 |
} |
| 141 |
- |
|
| 142 |
- container.Namespaces.Add(configs.NEWNET, c.Network.NamespacePath) |
|
| 143 | 158 |
return nil |
| 144 | 159 |
} |
| 145 | 160 |
|
| ... | ... |
@@ -131,9 +131,9 @@ type execOutput struct {
|
| 131 | 131 |
|
| 132 | 132 |
// Run implements the exec driver Driver interface, |
| 133 | 133 |
// it calls libcontainer APIs to run a container. |
| 134 |
-func (d *Driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, startCallback execdriver.StartCallback) (execdriver.ExitStatus, error) {
|
|
| 134 |
+func (d *Driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, hooks execdriver.Hooks) (execdriver.ExitStatus, error) {
|
|
| 135 | 135 |
// take the Command and populate the libcontainer.Config from it |
| 136 |
- container, err := d.createContainer(c) |
|
| 136 |
+ container, err := d.createContainer(c, hooks) |
|
| 137 | 137 |
if err != nil {
|
| 138 | 138 |
return execdriver.ExitStatus{ExitCode: -1}, err
|
| 139 | 139 |
} |
| ... | ... |
@@ -165,14 +165,14 @@ func (d *Driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, startCallba |
| 165 | 165 |
return execdriver.ExitStatus{ExitCode: -1}, err
|
| 166 | 166 |
} |
| 167 | 167 |
|
| 168 |
- if startCallback != nil {
|
|
| 168 |
+ if hooks.Start != nil {
|
|
| 169 | 169 |
pid, err := p.Pid() |
| 170 | 170 |
if err != nil {
|
| 171 | 171 |
p.Signal(os.Kill) |
| 172 | 172 |
p.Wait() |
| 173 | 173 |
return execdriver.ExitStatus{ExitCode: -1}, err
|
| 174 | 174 |
} |
| 175 |
- startCallback(&c.ProcessConfig, pid) |
|
| 175 |
+ hooks.Start(&c.ProcessConfig, pid) |
|
| 176 | 176 |
} |
| 177 | 177 |
|
| 178 | 178 |
oom := notifyOnOOM(cont) |
| ... | ... |
@@ -477,3 +477,9 @@ func setupPipes(container *configs.Config, processConfig *execdriver.ProcessConf |
| 477 | 477 |
processConfig.Terminal = term |
| 478 | 478 |
return nil |
| 479 | 479 |
} |
| 480 |
+ |
|
| 481 |
+// SupportsHooks implements the execdriver Driver interface. |
|
| 482 |
+// The libcontainer/runC-based native execdriver does exploit the hook mechanism |
|
| 483 |
+func (d *Driver) SupportsHooks() bool {
|
|
| 484 |
+ return true |
|
| 485 |
+} |
| ... | ... |
@@ -19,7 +19,7 @@ import ( |
| 19 | 19 |
|
| 20 | 20 |
// Exec implements the exec driver Driver interface, |
| 21 | 21 |
// it calls libcontainer APIs to execute a container. |
| 22 |
-func (d *Driver) Exec(c *execdriver.Command, processConfig *execdriver.ProcessConfig, pipes *execdriver.Pipes, startCallback execdriver.StartCallback) (int, error) {
|
|
| 22 |
+func (d *Driver) Exec(c *execdriver.Command, processConfig *execdriver.ProcessConfig, pipes *execdriver.Pipes, hooks execdriver.Hooks) (int, error) {
|
|
| 23 | 23 |
active := d.activeContainers[c.ID] |
| 24 | 24 |
if active == nil {
|
| 25 | 25 |
return -1, fmt.Errorf("No active container exists with ID %s", c.ID)
|
| ... | ... |
@@ -45,14 +45,14 @@ func (d *Driver) Exec(c *execdriver.Command, processConfig *execdriver.ProcessCo |
| 45 | 45 |
return -1, err |
| 46 | 46 |
} |
| 47 | 47 |
|
| 48 |
- if startCallback != nil {
|
|
| 48 |
+ if hooks.Start != nil {
|
|
| 49 | 49 |
pid, err := p.Pid() |
| 50 | 50 |
if err != nil {
|
| 51 | 51 |
p.Signal(os.Kill) |
| 52 | 52 |
p.Wait() |
| 53 | 53 |
return -1, err |
| 54 | 54 |
} |
| 55 |
- startCallback(&c.ProcessConfig, pid) |
|
| 55 |
+ hooks.Start(&c.ProcessConfig, pid) |
|
| 56 | 56 |
} |
| 57 | 57 |
|
| 58 | 58 |
ps, err := p.Wait() |
| ... | ... |
@@ -12,7 +12,7 @@ import ( |
| 12 | 12 |
) |
| 13 | 13 |
|
| 14 | 14 |
// Exec implements the exec driver Driver interface. |
| 15 |
-func (d *Driver) Exec(c *execdriver.Command, processConfig *execdriver.ProcessConfig, pipes *execdriver.Pipes, startCallback execdriver.StartCallback) (int, error) {
|
|
| 15 |
+func (d *Driver) Exec(c *execdriver.Command, processConfig *execdriver.ProcessConfig, pipes *execdriver.Pipes, hooks execdriver.Hooks) (int, error) {
|
|
| 16 | 16 |
|
| 17 | 17 |
var ( |
| 18 | 18 |
term execdriver.Terminal |
| ... | ... |
@@ -69,8 +69,8 @@ func (d *Driver) Exec(c *execdriver.Command, processConfig *execdriver.ProcessCo |
| 69 | 69 |
processConfig.Terminal = term |
| 70 | 70 |
|
| 71 | 71 |
// Invoke the start callback |
| 72 |
- if startCallback != nil {
|
|
| 73 |
- startCallback(&c.ProcessConfig, int(pid)) |
|
| 72 |
+ if hooks.Start != nil {
|
|
| 73 |
+ hooks.Start(&c.ProcessConfig, int(pid)) |
|
| 74 | 74 |
} |
| 75 | 75 |
|
| 76 | 76 |
if exitCode, err = hcsshim.WaitForProcessInComputeSystem(c.ID, pid); err != nil {
|
| ... | ... |
@@ -77,7 +77,7 @@ type containerInit struct {
|
| 77 | 77 |
const defaultOwner = "docker" |
| 78 | 78 |
|
| 79 | 79 |
// Run implements the exec driver Driver interface |
| 80 |
-func (d *Driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, startCallback execdriver.StartCallback) (execdriver.ExitStatus, error) {
|
|
| 80 |
+func (d *Driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, hooks execdriver.Hooks) (execdriver.ExitStatus, error) {
|
|
| 81 | 81 |
|
| 82 | 82 |
var ( |
| 83 | 83 |
term execdriver.Terminal |
| ... | ... |
@@ -290,9 +290,8 @@ func (d *Driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, startCallba |
| 290 | 290 |
} |
| 291 | 291 |
d.Unlock() |
| 292 | 292 |
|
| 293 |
- // Invoke the start callback |
|
| 294 |
- if startCallback != nil {
|
|
| 295 |
- startCallback(&c.ProcessConfig, int(pid)) |
|
| 293 |
+ if hooks.Start != nil {
|
|
| 294 |
+ hooks.Start(&c.ProcessConfig, int(pid)) |
|
| 296 | 295 |
} |
| 297 | 296 |
|
| 298 | 297 |
var exitCode int32 |
| ... | ... |
@@ -305,3 +304,9 @@ func (d *Driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, startCallba |
| 305 | 305 |
logrus.Debugf("Exiting Run() exitCode %d id=%s", exitCode, c.ID)
|
| 306 | 306 |
return execdriver.ExitStatus{ExitCode: int(exitCode)}, nil
|
| 307 | 307 |
} |
| 308 |
+ |
|
| 309 |
+// SupportsHooks implements the execdriver Driver interface. |
|
| 310 |
+// The windows driver does not support the hook mechanism |
|
| 311 |
+func (d *Driver) SupportsHooks() bool {
|
|
| 312 |
+ return false |
|
| 313 |
+} |
| ... | ... |
@@ -250,7 +250,7 @@ func (m *containerMonitor) shouldRestart(exitCode int) bool {
|
| 250 | 250 |
|
| 251 | 251 |
// callback ensures that the container's state is properly updated after we |
| 252 | 252 |
// received ack from the execution drivers |
| 253 |
-func (m *containerMonitor) callback(processConfig *execdriver.ProcessConfig, pid int) {
|
|
| 253 |
+func (m *containerMonitor) callback(processConfig *execdriver.ProcessConfig, pid int) error {
|
|
| 254 | 254 |
if processConfig.Tty {
|
| 255 | 255 |
// The callback is called after the process Start() |
| 256 | 256 |
// so we are in the parent process. In TTY mode, stdin/out/err is the PtySlave |
| ... | ... |
@@ -273,6 +273,7 @@ func (m *containerMonitor) callback(processConfig *execdriver.ProcessConfig, pid |
| 273 | 273 |
if err := m.container.toDiskLocking(); err != nil {
|
| 274 | 274 |
logrus.Errorf("Error saving container to disk: %v", err)
|
| 275 | 275 |
} |
| 276 |
+ return nil |
|
| 276 | 277 |
} |
| 277 | 278 |
|
| 278 | 279 |
// resetContainer resets the container's IO and ensures that the command is able to be executed again |