Docker-DCO-1.1-Signed-off-by: Vishnu Kannan <vishnuk@google.com> (github: vishh)
Vishnu Kannan authored on 2014/10/31 08:06:54... | ... |
@@ -991,7 +991,7 @@ func (daemon *Daemon) Diff(container *Container) (archive.Archive, error) { |
991 | 991 |
return daemon.driver.Diff(container.ID, initID) |
992 | 992 |
} |
993 | 993 |
|
994 |
-func (daemon *Daemon) Run(c *Container, pipes *execdriver.Pipes, startCallback execdriver.StartCallback) (*execdriver.ExitStatus, error) { |
|
994 |
+func (daemon *Daemon) Run(c *Container, pipes *execdriver.Pipes, startCallback execdriver.StartCallback) (execdriver.ExitStatus, error) { |
|
995 | 995 |
return daemon.execDriver.Run(c.command, pipes, startCallback) |
996 | 996 |
} |
997 | 997 |
|
... | ... |
@@ -50,7 +50,7 @@ type ExitStatus struct { |
50 | 50 |
} |
51 | 51 |
|
52 | 52 |
type Driver interface { |
53 |
- Run(c *Command, pipes *Pipes, startCallback StartCallback) (int, error) // Run executes the process and blocks until the process exits and returns the exit code |
|
53 |
+ Run(c *Command, pipes *Pipes, startCallback StartCallback) (ExitStatus, error) // Run executes the process and blocks until the process exits and returns the exit code |
|
54 | 54 |
// Exec executes the process in an existing container, blocks until the process exits and returns the exit code |
55 | 55 |
Exec(c *Command, processConfig *ProcessConfig, pipes *Pipes, startCallback StartCallback) (int, error) |
56 | 56 |
Kill(c *Command, sig int) error |
... | ... |
@@ -55,7 +55,7 @@ func (d *driver) Name() string { |
55 | 55 |
return fmt.Sprintf("%s-%s", DriverName, version) |
56 | 56 |
} |
57 | 57 |
|
58 |
-func (d *driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, startCallback execdriver.StartCallback) (*execdriver.ExitStatus, error) { |
|
58 |
+func (d *driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, startCallback execdriver.StartCallback) (execdriver.ExitStatus, error) { |
|
59 | 59 |
var ( |
60 | 60 |
term execdriver.Terminal |
61 | 61 |
err error |
... | ... |
@@ -76,11 +76,11 @@ func (d *driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, startCallba |
76 | 76 |
}) |
77 | 77 |
|
78 | 78 |
if err := d.generateEnvConfig(c); err != nil { |
79 |
- return nil, err |
|
79 |
+ return execdriver.ExitStatus{-1, false}, err |
|
80 | 80 |
} |
81 | 81 |
configPath, err := d.generateLXCConfig(c) |
82 | 82 |
if err != nil { |
83 |
- return nil, err |
|
83 |
+ return execdriver.ExitStatus{-1, false}, err |
|
84 | 84 |
} |
85 | 85 |
params := []string{ |
86 | 86 |
"lxc-start", |
... | ... |
@@ -155,11 +155,11 @@ func (d *driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, startCallba |
155 | 155 |
c.ProcessConfig.Args = append([]string{name}, arg...) |
156 | 156 |
|
157 | 157 |
if err := nodes.CreateDeviceNodes(c.Rootfs, c.AutoCreatedDevices); err != nil { |
158 |
- return nil, err |
|
158 |
+ return execdriver.ExitStatus{-1, false}, err |
|
159 | 159 |
} |
160 | 160 |
|
161 | 161 |
if err := c.ProcessConfig.Start(); err != nil { |
162 |
- return nil, err |
|
162 |
+ return execdriver.ExitStatus{-1, false}, err |
|
163 | 163 |
} |
164 | 164 |
|
165 | 165 |
var ( |
... | ... |
@@ -183,7 +183,7 @@ func (d *driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, startCallba |
183 | 183 |
c.ProcessConfig.Process.Kill() |
184 | 184 |
c.ProcessConfig.Wait() |
185 | 185 |
} |
186 |
- return nil, err |
|
186 |
+ return execdriver.ExitStatus{-1, false}, err |
|
187 | 187 |
} |
188 | 188 |
|
189 | 189 |
c.ContainerPid = pid |
... | ... |
@@ -194,7 +194,7 @@ func (d *driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, startCallba |
194 | 194 |
|
195 | 195 |
<-waitLock |
196 | 196 |
|
197 |
- return &execdriver.ExitStatus{getExitCode(c), false}, waitErr |
|
197 |
+ return execdriver.ExitStatus{getExitCode(c), false}, waitErr |
|
198 | 198 |
} |
199 | 199 |
|
200 | 200 |
/// Return the exit code of the process |
... | ... |
@@ -70,11 +70,11 @@ type execOutput struct { |
70 | 70 |
err error |
71 | 71 |
} |
72 | 72 |
|
73 |
-func (d *driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, startCallback execdriver.StartCallback) (*execdriver.ExitStatus, error) { |
|
73 |
+func (d *driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, startCallback execdriver.StartCallback) (execdriver.ExitStatus, error) { |
|
74 | 74 |
// take the Command and populate the libcontainer.Config from it |
75 | 75 |
container, err := d.createContainer(c) |
76 | 76 |
if err != nil { |
77 |
- return nil, err |
|
77 |
+ return execdriver.ExitStatus{-1, false}, err |
|
78 | 78 |
} |
79 | 79 |
|
80 | 80 |
var term execdriver.Terminal |
... | ... |
@@ -85,7 +85,7 @@ func (d *driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, startCallba |
85 | 85 |
term, err = execdriver.NewStdConsole(&c.ProcessConfig, pipes) |
86 | 86 |
} |
87 | 87 |
if err != nil { |
88 |
- return nil, err |
|
88 |
+ return execdriver.ExitStatus{-1, false}, err |
|
89 | 89 |
} |
90 | 90 |
c.ProcessConfig.Terminal = term |
91 | 91 |
|
... | ... |
@@ -102,16 +102,16 @@ func (d *driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, startCallba |
102 | 102 |
) |
103 | 103 |
|
104 | 104 |
if err := d.createContainerRoot(c.ID); err != nil { |
105 |
- return nil, err |
|
105 |
+ return execdriver.ExitStatus{-1, false}, err |
|
106 | 106 |
} |
107 | 107 |
defer d.cleanContainer(c.ID) |
108 | 108 |
|
109 | 109 |
if err := d.writeContainerFile(container, c.ID); err != nil { |
110 |
- return nil, err |
|
110 |
+ return execdriver.ExitStatus{-1, false}, err |
|
111 | 111 |
} |
112 | 112 |
|
113 |
- execOutputChan := make(chan execOutput, 0) |
|
114 |
- waitForStart := make(chan struct{}, 0) |
|
113 |
+ execOutputChan := make(chan execOutput, 1) |
|
114 |
+ waitForStart := make(chan struct{}) |
|
115 | 115 |
|
116 | 116 |
go func() { |
117 | 117 |
exitCode, err := namespaces.Exec(container, c.ProcessConfig.Stdin, c.ProcessConfig.Stdout, c.ProcessConfig.Stderr, c.ProcessConfig.Console, dataPath, args, func(container *libcontainer.Config, console, dataPath, init string, child *os.File, args []string) *exec.Cmd { |
... | ... |
@@ -146,26 +146,22 @@ func (d *driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, startCallba |
146 | 146 |
|
147 | 147 |
select { |
148 | 148 |
case execOutput := <-execOutputChan: |
149 |
- return &execdriver.ExitStatus{execOutput.exitCode, false}, execOutput.err |
|
149 |
+ return execdriver.ExitStatus{execOutput.exitCode, false}, execOutput.err |
|
150 | 150 |
case <-waitForStart: |
151 | 151 |
break |
152 | 152 |
} |
153 | 153 |
|
154 | 154 |
oomKill := false |
155 |
- go func() { |
|
156 |
- oomKillNotification, err := d.notifyOnOOM(container) |
|
157 |
- if err == nil { |
|
158 |
- if _, ok := <-oomKillNotification; ok { |
|
159 |
- oomKill = true |
|
160 |
- } |
|
161 |
- } else { |
|
162 |
- log.Infof("WARNING: Your kernel does not support OOM notifications: %s", err) |
|
163 |
- } |
|
164 |
- }() |
|
155 |
+ oomKillNotification, err := d.notifyOnOOM(container) |
|
156 |
+ if err == nil { |
|
157 |
+ _, oomKill = <-oomKillNotification |
|
158 |
+ } else { |
|
159 |
+ log.Warnf("WARNING: Your kernel does not support OOM notifications: %s", err) |
|
160 |
+ } |
|
165 | 161 |
// wait for the container to exit. |
166 | 162 |
execOutput := <-execOutputChan |
167 | 163 |
|
168 |
- return &execdriver.ExitStatus{execOutput.exitCode, oomKill}, execOutput.err |
|
164 |
+ return execdriver.ExitStatus{execOutput.exitCode, oomKill}, execOutput.err |
|
169 | 165 |
} |
170 | 166 |
|
171 | 167 |
func (d *driver) Kill(p *execdriver.Command, sig int) error { |
... | ... |
@@ -100,7 +100,7 @@ func (m *containerMonitor) Close() error { |
100 | 100 |
func (m *containerMonitor) Start() error { |
101 | 101 |
var ( |
102 | 102 |
err error |
103 |
- exitStatus *execdriver.ExitStatus |
|
103 |
+ exitStatus execdriver.ExitStatus |
|
104 | 104 |
// this variable indicates where we in execution flow: |
105 | 105 |
// before Run or after |
106 | 106 |
afterRun bool |
... | ... |
@@ -110,7 +110,7 @@ func (m *containerMonitor) Start() error { |
110 | 110 |
defer func() { |
111 | 111 |
if afterRun { |
112 | 112 |
m.container.Lock() |
113 |
- m.container.setStopped(exitStatus) |
|
113 |
+ m.container.setStopped(&exitStatus) |
|
114 | 114 |
defer m.container.Unlock() |
115 | 115 |
} |
116 | 116 |
m.Close() |
... | ... |
@@ -138,7 +138,7 @@ func (m *containerMonitor) Start() error { |
138 | 138 |
// if we receive an internal error from the initial start of a container then lets |
139 | 139 |
// return it instead of entering the restart loop |
140 | 140 |
if m.container.RestartCount == 0 { |
141 |
- m.container.ExitCode = exitStatus |
|
141 |
+ m.container.ExitCode = -1 |
|
142 | 142 |
m.resetContainer(false) |
143 | 143 |
|
144 | 144 |
return err |
... | ... |
@@ -153,7 +153,7 @@ func (m *containerMonitor) Start() error { |
153 | 153 |
m.resetMonitor(err == nil && exitStatus.ExitCode == 0) |
154 | 154 |
|
155 | 155 |
if m.shouldRestart(exitStatus.ExitCode) { |
156 |
- m.container.SetRestarting(exitStatus) |
|
156 |
+ m.container.SetRestarting(&exitStatus) |
|
157 | 157 |
m.container.LogEvent("die") |
158 | 158 |
m.resetContainer(true) |
159 | 159 |
|
... | ... |
@@ -164,12 +164,12 @@ func (m *containerMonitor) Start() error { |
164 | 164 |
// we need to check this before reentering the loop because the waitForNextRestart could have |
165 | 165 |
// been terminated by a request from a user |
166 | 166 |
if m.shouldStop { |
167 |
- m.container.ExitCode = exitStatus |
|
167 |
+ m.container.ExitCode = exitStatus.ExitCode |
|
168 | 168 |
return err |
169 | 169 |
} |
170 | 170 |
continue |
171 | 171 |
} |
172 |
- m.container.ExitCode = exitStatus |
|
172 |
+ m.container.ExitCode = exitStatus.ExitCode |
|
173 | 173 |
m.container.LogEvent("die") |
174 | 174 |
m.resetContainer(true) |
175 | 175 |
return err |
... | ... |
@@ -31,16 +31,12 @@ func NewState() *State { |
31 | 31 |
|
32 | 32 |
// String returns a human-readable description of the state |
33 | 33 |
func (s *State) String() string { |
34 |
- oomInfo := "" |
|
35 |
- if s.OOMKilled { |
|
36 |
- oomInfo = "possibly due to lack of memory" |
|
37 |
- } |
|
38 | 34 |
if s.Running { |
39 | 35 |
if s.Paused { |
40 | 36 |
return fmt.Sprintf("Up %s (Paused)", units.HumanDuration(time.Now().UTC().Sub(s.StartedAt))) |
41 | 37 |
} |
42 | 38 |
if s.Restarting { |
43 |
- return fmt.Sprintf("Restarting (%d) %s ago %s", s.ExitCode, units.HumanDuration(time.Now().UTC().Sub(s.FinishedAt)), oomInfo) |
|
39 |
+ return fmt.Sprintf("Restarting (%d) %s ago", s.ExitCode, units.HumanDuration(time.Now().UTC().Sub(s.FinishedAt))) |
|
44 | 40 |
} |
45 | 41 |
|
46 | 42 |
return fmt.Sprintf("Up %s", units.HumanDuration(time.Now().UTC().Sub(s.StartedAt))) |
... | ... |
@@ -50,7 +46,7 @@ func (s *State) String() string { |
50 | 50 |
return "" |
51 | 51 |
} |
52 | 52 |
|
53 |
- return fmt.Sprintf("Exited (%d) %s ago %s", s.ExitCode, units.HumanDuration(time.Now().UTC().Sub(s.FinishedAt)), oomInfo) |
|
53 |
+ return fmt.Sprintf("Exited (%d) %s ago", s.ExitCode, units.HumanDuration(time.Now().UTC().Sub(s.FinishedAt))) |
|
54 | 54 |
} |
55 | 55 |
|
56 | 56 |
// StateString returns a single string to describe state |
... | ... |
@@ -167,10 +163,7 @@ func (s *State) setStopped(exitStatus *execdriver.ExitStatus) { |
167 | 167 |
s.Pid = 0 |
168 | 168 |
s.FinishedAt = time.Now().UTC() |
169 | 169 |
s.ExitCode = exitStatus.ExitCode |
170 |
- s.OOMKilled = false |
|
171 |
- if exitStatus.OOMKilled { |
|
172 |
- s.OOMKilled = true |
|
173 |
- } |
|
170 |
+ s.OOMKilled = exitStatus.OOMKilled |
|
174 | 171 |
close(s.waitChan) // fire waiters for stop |
175 | 172 |
s.waitChan = make(chan struct{}) |
176 | 173 |
} |
... | ... |
@@ -186,9 +179,7 @@ func (s *State) SetRestarting(exitStatus *execdriver.ExitStatus) { |
186 | 186 |
s.Pid = 0 |
187 | 187 |
s.FinishedAt = time.Now().UTC() |
188 | 188 |
s.ExitCode = exitStatus.ExitCode |
189 |
- if exitStatus.OOMKilled { |
|
190 |
- s.OOMKilled = true |
|
191 |
- } |
|
189 |
+ s.OOMKilled = exitStatus.OOMKilled |
|
192 | 190 |
close(s.waitChan) // fire waiters for stop |
193 | 191 |
s.waitChan = make(chan struct{}) |
194 | 192 |
s.Unlock() |