Browse code

Execdriver implementation on new libcontainer API

Signed-off-by: Alexander Morozov <lk4d4@docker.com>

Alexander Morozov authored on 2015/03/06 02:55:14
Showing 16 changed files
... ...
@@ -14,6 +14,8 @@ import (
14 14
 	"syscall"
15 15
 	"time"
16 16
 
17
+	"github.com/docker/libcontainer"
18
+	"github.com/docker/libcontainer/configs"
17 19
 	"github.com/docker/libcontainer/devices"
18 20
 	"github.com/docker/libcontainer/label"
19 21
 
... ...
@@ -259,18 +261,18 @@ func populateCommand(c *Container, env []string) error {
259 259
 	pid.HostPid = c.hostConfig.PidMode.IsHost()
260 260
 
261 261
 	// Build lists of devices allowed and created within the container.
262
-	userSpecifiedDevices := make([]*devices.Device, len(c.hostConfig.Devices))
262
+	userSpecifiedDevices := make([]*configs.Device, len(c.hostConfig.Devices))
263 263
 	for i, deviceMapping := range c.hostConfig.Devices {
264
-		device, err := devices.GetDevice(deviceMapping.PathOnHost, deviceMapping.CgroupPermissions)
264
+		device, err := devices.DeviceFromPath(deviceMapping.PathOnHost, deviceMapping.CgroupPermissions)
265 265
 		if err != nil {
266 266
 			return fmt.Errorf("error gathering device information while adding custom device %q: %s", deviceMapping.PathOnHost, err)
267 267
 		}
268 268
 		device.Path = deviceMapping.PathInContainer
269 269
 		userSpecifiedDevices[i] = device
270 270
 	}
271
-	allowedDevices := append(devices.DefaultAllowedDevices, userSpecifiedDevices...)
271
+	allowedDevices := append(configs.DefaultAllowedDevices, userSpecifiedDevices...)
272 272
 
273
-	autoCreatedDevices := append(devices.DefaultAutoCreatedDevices, userSpecifiedDevices...)
273
+	autoCreatedDevices := append(configs.DefaultAutoCreatedDevices, userSpecifiedDevices...)
274 274
 
275 275
 	// TODO: this can be removed after lxc-conf is fully deprecated
276 276
 	lxcConfig, err := mergeLxcConfIntoOptions(c.hostConfig)
... ...
@@ -972,7 +974,7 @@ func (container *Container) Exposes(p nat.Port) bool {
972 972
 	return exists
973 973
 }
974 974
 
975
-func (container *Container) GetPtyMaster() (*os.File, error) {
975
+func (container *Container) GetPtyMaster() (libcontainer.Console, error) {
976 976
 	ttyConsole, ok := container.command.ProcessConfig.Terminal.(execdriver.TtyTerminal)
977 977
 	if !ok {
978 978
 		return nil, ErrNoTTY
... ...
@@ -1,17 +1,22 @@
1 1
 package execdriver
2 2
 
3 3
 import (
4
+	"encoding/json"
4 5
 	"errors"
5 6
 	"io"
7
+	"io/ioutil"
6 8
 	"os"
7 9
 	"os/exec"
10
+	"path/filepath"
11
+	"strconv"
8 12
 	"strings"
9 13
 	"time"
10 14
 
11 15
 	"github.com/docker/docker/daemon/execdriver/native/template"
12 16
 	"github.com/docker/docker/pkg/ulimit"
13 17
 	"github.com/docker/libcontainer"
14
-	"github.com/docker/libcontainer/devices"
18
+	"github.com/docker/libcontainer/cgroups/fs"
19
+	"github.com/docker/libcontainer/configs"
15 20
 )
16 21
 
17 22
 // Context is a generic key value pair that allows
... ...
@@ -42,7 +47,7 @@ type Terminal interface {
42 42
 }
43 43
 
44 44
 type TtyTerminal interface {
45
-	Master() *os.File
45
+	Master() libcontainer.Console
46 46
 }
47 47
 
48 48
 // ExitStatus provides exit reasons for a container.
... ...
@@ -109,7 +114,7 @@ type Resources struct {
109 109
 }
110 110
 
111 111
 type ResourceStats struct {
112
-	*libcontainer.ContainerStats
112
+	*libcontainer.Stats
113 113
 	Read        time.Time `json:"read"`
114 114
 	MemoryLimit int64     `json:"memory_limit"`
115 115
 	SystemUsage uint64    `json:"system_usage"`
... ...
@@ -149,8 +154,8 @@ type Command struct {
149 149
 	Pid                *Pid              `json:"pid"`
150 150
 	Resources          *Resources        `json:"resources"`
151 151
 	Mounts             []Mount           `json:"mounts"`
152
-	AllowedDevices     []*devices.Device `json:"allowed_devices"`
153
-	AutoCreatedDevices []*devices.Device `json:"autocreated_devices"`
152
+	AllowedDevices     []*configs.Device `json:"allowed_devices"`
153
+	AutoCreatedDevices []*configs.Device `json:"autocreated_devices"`
154 154
 	CapAdd             []string          `json:"cap_add"`
155 155
 	CapDrop            []string          `json:"cap_drop"`
156 156
 	ContainerPid       int               `json:"container_pid"`  // the pid for the process inside a container
... ...
@@ -161,23 +166,19 @@ type Command struct {
161 161
 	AppArmorProfile    string            `json:"apparmor_profile"`
162 162
 }
163 163
 
164
-func InitContainer(c *Command) *libcontainer.Config {
164
+func InitContainer(c *Command) *configs.Config {
165 165
 	container := template.New()
166 166
 
167 167
 	container.Hostname = getEnv("HOSTNAME", c.ProcessConfig.Env)
168
-	container.Tty = c.ProcessConfig.Tty
169
-	container.User = c.ProcessConfig.User
170
-	container.WorkingDir = c.WorkingDir
171
-	container.Env = c.ProcessConfig.Env
172 168
 	container.Cgroups.Name = c.ID
173 169
 	container.Cgroups.AllowedDevices = c.AllowedDevices
174
-	container.MountConfig.DeviceNodes = c.AutoCreatedDevices
175
-	container.RootFs = c.Rootfs
176
-	container.MountConfig.ReadonlyFs = c.ReadonlyRootfs
170
+	container.Readonlyfs = c.ReadonlyRootfs
171
+	container.Devices = c.AutoCreatedDevices
172
+	container.Rootfs = c.Rootfs
173
+	container.Readonlyfs = c.ReadonlyRootfs
177 174
 
178 175
 	// check to see if we are running in ramdisk to disable pivot root
179
-	container.MountConfig.NoPivotRoot = os.Getenv("DOCKER_RAMDISK") != ""
180
-	container.RestrictSys = true
176
+	container.NoPivotRoot = os.Getenv("DOCKER_RAMDISK") != ""
181 177
 	return container
182 178
 }
183 179
 
... ...
@@ -191,7 +192,7 @@ func getEnv(key string, env []string) string {
191 191
 	return ""
192 192
 }
193 193
 
194
-func SetupCgroups(container *libcontainer.Config, c *Command) error {
194
+func SetupCgroups(container *configs.Config, c *Command) error {
195 195
 	if c.Resources != nil {
196 196
 		container.Cgroups.CpuShares = c.Resources.CpuShares
197 197
 		container.Cgroups.Memory = c.Resources.Memory
... ...
@@ -203,28 +204,98 @@ func SetupCgroups(container *libcontainer.Config, c *Command) error {
203 203
 	return nil
204 204
 }
205 205
 
206
-func Stats(stateFile string, containerMemoryLimit int64, machineMemory int64) (*ResourceStats, error) {
207
-	state, err := libcontainer.GetState(stateFile)
208
-	if err != nil {
209
-		if os.IsNotExist(err) {
210
-			return nil, ErrNotRunning
206
+// Returns the network statistics for the network interfaces represented by the NetworkRuntimeInfo.
207
+func getNetworkInterfaceStats(interfaceName string) (*libcontainer.NetworkInterface, error) {
208
+	out := &libcontainer.NetworkInterface{Name: interfaceName}
209
+	// This can happen if the network runtime information is missing - possible if the
210
+	// container was created by an old version of libcontainer.
211
+	if interfaceName == "" {
212
+		return out, nil
213
+	}
214
+	type netStatsPair struct {
215
+		// Where to write the output.
216
+		Out *uint64
217
+		// The network stats file to read.
218
+		File string
219
+	}
220
+	// Ingress for host veth is from the container. Hence tx_bytes stat on the host veth is actually number of bytes received by the container.
221
+	netStats := []netStatsPair{
222
+		{Out: &out.RxBytes, File: "tx_bytes"},
223
+		{Out: &out.RxPackets, File: "tx_packets"},
224
+		{Out: &out.RxErrors, File: "tx_errors"},
225
+		{Out: &out.RxDropped, File: "tx_dropped"},
226
+
227
+		{Out: &out.TxBytes, File: "rx_bytes"},
228
+		{Out: &out.TxPackets, File: "rx_packets"},
229
+		{Out: &out.TxErrors, File: "rx_errors"},
230
+		{Out: &out.TxDropped, File: "rx_dropped"},
231
+	}
232
+	for _, netStat := range netStats {
233
+		data, err := readSysfsNetworkStats(interfaceName, netStat.File)
234
+		if err != nil {
235
+			return nil, err
211 236
 		}
237
+		*(netStat.Out) = data
238
+	}
239
+	return out, nil
240
+}
241
+
242
+// Reads the specified statistics available under /sys/class/net/<EthInterface>/statistics
243
+func readSysfsNetworkStats(ethInterface, statsFile string) (uint64, error) {
244
+	data, err := ioutil.ReadFile(filepath.Join("/sys/class/net", ethInterface, "statistics", statsFile))
245
+	if err != nil {
246
+		return 0, err
247
+	}
248
+	return strconv.ParseUint(strings.TrimSpace(string(data)), 10, 64)
249
+}
250
+
251
+func Stats(containerDir string, containerMemoryLimit int64, machineMemory int64) (*ResourceStats, error) {
252
+	f, err := os.Open(filepath.Join(containerDir, "state.json"))
253
+	if err != nil {
254
+		return nil, err
255
+	}
256
+	defer f.Close()
257
+
258
+	type network struct {
259
+		Type              string
260
+		HostInterfaceName string
261
+	}
262
+
263
+	state := struct {
264
+		CgroupPaths map[string]string `json:"cgroup_paths"`
265
+		Networks    []network
266
+	}{}
267
+
268
+	if err := json.NewDecoder(f).Decode(&state); err != nil {
212 269
 		return nil, err
213 270
 	}
214 271
 	now := time.Now()
215
-	stats, err := libcontainer.GetStats(nil, state)
272
+
273
+	mgr := fs.Manager{Paths: state.CgroupPaths}
274
+	cstats, err := mgr.GetStats()
216 275
 	if err != nil {
217 276
 		return nil, err
218 277
 	}
278
+	stats := &libcontainer.Stats{CgroupStats: cstats}
219 279
 	// if the container does not have any memory limit specified set the
220 280
 	// limit to the machines memory
221 281
 	memoryLimit := containerMemoryLimit
222 282
 	if memoryLimit == 0 {
223 283
 		memoryLimit = machineMemory
224 284
 	}
285
+	for _, iface := range state.Networks {
286
+		switch iface.Type {
287
+		case "veth":
288
+			istats, err := getNetworkInterfaceStats(iface.HostInterfaceName)
289
+			if err != nil {
290
+				return nil, err
291
+			}
292
+			stats.Interfaces = append(stats.Interfaces, istats)
293
+		}
294
+	}
225 295
 	return &ResourceStats{
226
-		Read:           now,
227
-		ContainerStats: stats,
228
-		MemoryLimit:    memoryLimit,
296
+		Stats:       stats,
297
+		Read:        now,
298
+		MemoryLimit: memoryLimit,
229 299
 	}, nil
230 300
 }
... ...
@@ -23,7 +23,9 @@ import (
23 23
 	"github.com/docker/docker/utils"
24 24
 	"github.com/docker/libcontainer"
25 25
 	"github.com/docker/libcontainer/cgroups"
26
-	"github.com/docker/libcontainer/mount/nodes"
26
+	"github.com/docker/libcontainer/configs"
27
+	"github.com/docker/libcontainer/system"
28
+	"github.com/docker/libcontainer/user"
27 29
 	"github.com/kr/pty"
28 30
 )
29 31
 
... ...
@@ -42,7 +44,7 @@ type driver struct {
42 42
 }
43 43
 
44 44
 type activeContainer struct {
45
-	container *libcontainer.Config
45
+	container *configs.Config
46 46
 	cmd       *exec.Cmd
47 47
 }
48 48
 
... ...
@@ -190,7 +192,7 @@ func (d *driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, startCallba
190 190
 	c.ProcessConfig.Path = aname
191 191
 	c.ProcessConfig.Args = append([]string{name}, arg...)
192 192
 
193
-	if err := nodes.CreateDeviceNodes(c.Rootfs, c.AutoCreatedDevices); err != nil {
193
+	if err := createDeviceNodes(c.Rootfs, c.AutoCreatedDevices); err != nil {
194 194
 		return execdriver.ExitStatus{ExitCode: -1}, err
195 195
 	}
196 196
 
... ...
@@ -231,11 +233,17 @@ func (d *driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, startCallba
231 231
 	}
232 232
 
233 233
 	state := &libcontainer.State{
234
-		InitPid:     pid,
235
-		CgroupPaths: cgroupPaths,
234
+		InitProcessPid: pid,
235
+		CgroupPaths:    cgroupPaths,
236 236
 	}
237 237
 
238
-	if err := libcontainer.SaveState(dataPath, state); err != nil {
238
+	f, err := os.Create(filepath.Join(dataPath, "state.json"))
239
+	if err != nil {
240
+		return terminate(err)
241
+	}
242
+	defer f.Close()
243
+
244
+	if err := json.NewEncoder(f).Encode(state); err != nil {
239 245
 		return terminate(err)
240 246
 	}
241 247
 
... ...
@@ -245,8 +253,9 @@ func (d *driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, startCallba
245 245
 		log.Debugf("Invoking startCallback")
246 246
 		startCallback(&c.ProcessConfig, pid)
247 247
 	}
248
+
248 249
 	oomKill := false
249
-	oomKillNotification, err := libcontainer.NotifyOnOOM(state)
250
+	oomKillNotification, err := notifyOnOOM(cgroupPaths)
250 251
 	if err == nil {
251 252
 		_, oomKill = <-oomKillNotification
252 253
 		log.Debugf("oomKill error %s waitErr %s", oomKill, waitErr)
... ...
@@ -265,9 +274,57 @@ func (d *driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, startCallba
265 265
 	return execdriver.ExitStatus{ExitCode: exitCode, OOMKilled: oomKill}, waitErr
266 266
 }
267 267
 
268
+// copy from libcontainer
269
+func notifyOnOOM(paths map[string]string) (<-chan struct{}, error) {
270
+	dir := paths["memory"]
271
+	if dir == "" {
272
+		return nil, fmt.Errorf("There is no path for %q in state", "memory")
273
+	}
274
+	oomControl, err := os.Open(filepath.Join(dir, "memory.oom_control"))
275
+	if err != nil {
276
+		return nil, err
277
+	}
278
+	fd, _, syserr := syscall.RawSyscall(syscall.SYS_EVENTFD2, 0, syscall.FD_CLOEXEC, 0)
279
+	if syserr != 0 {
280
+		oomControl.Close()
281
+		return nil, syserr
282
+	}
283
+
284
+	eventfd := os.NewFile(fd, "eventfd")
285
+
286
+	eventControlPath := filepath.Join(dir, "cgroup.event_control")
287
+	data := fmt.Sprintf("%d %d", eventfd.Fd(), oomControl.Fd())
288
+	if err := ioutil.WriteFile(eventControlPath, []byte(data), 0700); err != nil {
289
+		eventfd.Close()
290
+		oomControl.Close()
291
+		return nil, err
292
+	}
293
+	ch := make(chan struct{})
294
+	go func() {
295
+		defer func() {
296
+			close(ch)
297
+			eventfd.Close()
298
+			oomControl.Close()
299
+		}()
300
+		buf := make([]byte, 8)
301
+		for {
302
+			if _, err := eventfd.Read(buf); err != nil {
303
+				return
304
+			}
305
+			// When a cgroup is destroyed, an event is sent to eventfd.
306
+			// So if the control path is gone, return instead of notifying.
307
+			if _, err := os.Lstat(eventControlPath); os.IsNotExist(err) {
308
+				return
309
+			}
310
+			ch <- struct{}{}
311
+		}
312
+	}()
313
+	return ch, nil
314
+}
315
+
268 316
 // createContainer populates and configures the container type with the
269 317
 // data provided by the execdriver.Command
270
-func (d *driver) createContainer(c *execdriver.Command) (*libcontainer.Config, error) {
318
+func (d *driver) createContainer(c *execdriver.Command) (*configs.Config, error) {
271 319
 	container := execdriver.InitContainer(c)
272 320
 	if err := execdriver.SetupCgroups(container, c); err != nil {
273 321
 		return nil, err
... ...
@@ -297,6 +354,87 @@ func cgroupPaths(containerId string) (map[string]string, error) {
297 297
 	return paths, nil
298 298
 }
299 299
 
300
+// this is copy from old libcontainer nodes.go
301
+func createDeviceNodes(rootfs string, nodesToCreate []*configs.Device) error {
302
+	oldMask := syscall.Umask(0000)
303
+	defer syscall.Umask(oldMask)
304
+
305
+	for _, node := range nodesToCreate {
306
+		if err := createDeviceNode(rootfs, node); err != nil {
307
+			return err
308
+		}
309
+	}
310
+	return nil
311
+}
312
+
313
+// Creates the device node in the rootfs of the container.
314
+func createDeviceNode(rootfs string, node *configs.Device) error {
315
+	var (
316
+		dest   = filepath.Join(rootfs, node.Path)
317
+		parent = filepath.Dir(dest)
318
+	)
319
+
320
+	if err := os.MkdirAll(parent, 0755); err != nil {
321
+		return err
322
+	}
323
+
324
+	fileMode := node.FileMode
325
+	switch node.Type {
326
+	case 'c':
327
+		fileMode |= syscall.S_IFCHR
328
+	case 'b':
329
+		fileMode |= syscall.S_IFBLK
330
+	default:
331
+		return fmt.Errorf("%c is not a valid device type for device %s", node.Type, node.Path)
332
+	}
333
+
334
+	if err := syscall.Mknod(dest, uint32(fileMode), node.Mkdev()); err != nil && !os.IsExist(err) {
335
+		return fmt.Errorf("mknod %s %s", node.Path, err)
336
+	}
337
+
338
+	if err := syscall.Chown(dest, int(node.Uid), int(node.Gid)); err != nil {
339
+		return fmt.Errorf("chown %s to %d:%d", node.Path, node.Uid, node.Gid)
340
+	}
341
+
342
+	return nil
343
+}
344
+
345
+// setupUser changes the groups, gid, and uid for the user inside the container
346
+// copy from libcontainer, cause not it's private
347
+func setupUser(userSpec string) error {
348
+	// Set up defaults.
349
+	defaultExecUser := user.ExecUser{
350
+		Uid:  syscall.Getuid(),
351
+		Gid:  syscall.Getgid(),
352
+		Home: "/",
353
+	}
354
+	passwdPath, err := user.GetPasswdPath()
355
+	if err != nil {
356
+		return err
357
+	}
358
+	groupPath, err := user.GetGroupPath()
359
+	if err != nil {
360
+		return err
361
+	}
362
+	execUser, err := user.GetExecUserPath(userSpec, &defaultExecUser, passwdPath, groupPath)
363
+	if err != nil {
364
+		return err
365
+	}
366
+	if err := system.Setgid(execUser.Gid); err != nil {
367
+		return err
368
+	}
369
+	if err := system.Setuid(execUser.Uid); err != nil {
370
+		return err
371
+	}
372
+	// if we didn't get HOME already, set it based on the user's HOME
373
+	if envHome := os.Getenv("HOME"); envHome == "" {
374
+		if err := os.Setenv("HOME", execUser.Home); err != nil {
375
+			return err
376
+		}
377
+	}
378
+	return nil
379
+}
380
+
300 381
 /// Return the exit code of the process
301 382
 // if the process has not exited -1 will be returned
302 383
 func getExitCode(c *execdriver.Command) int {
... ...
@@ -3,8 +3,6 @@ package lxc
3 3
 import (
4 4
 	"fmt"
5 5
 
6
-	"github.com/docker/libcontainer"
7
-	"github.com/docker/libcontainer/namespaces"
8 6
 	"github.com/docker/libcontainer/utils"
9 7
 )
10 8
 
... ...
@@ -12,9 +10,7 @@ func finalizeNamespace(args *InitArgs) error {
12 12
 	if err := utils.CloseExecFrom(3); err != nil {
13 13
 		return err
14 14
 	}
15
-	if err := namespaces.SetupUser(&libcontainer.Config{
16
-		User: args.User,
17
-	}); err != nil {
15
+	if err := setupUser(args.User); err != nil {
18 16
 		return fmt.Errorf("setup user %s", err)
19 17
 	}
20 18
 	if err := setupWorkingDirectory(args); err != nil {
... ...
@@ -11,7 +11,6 @@ import (
11 11
 	nativeTemplate "github.com/docker/docker/daemon/execdriver/native/template"
12 12
 	"github.com/docker/docker/utils"
13 13
 	"github.com/docker/libcontainer/label"
14
-	"github.com/docker/libcontainer/security/capabilities"
15 14
 )
16 15
 
17 16
 const LxcTemplate = `
... ...
@@ -169,7 +168,7 @@ func keepCapabilities(adds []string, drops []string) ([]string, error) {
169 169
 	var newCaps []string
170 170
 	for _, cap := range caps {
171 171
 		log.Debugf("cap %s\n", cap)
172
-		realCap := capabilities.GetCapability(cap)
172
+		realCap := execdriver.GetCapability(cap)
173 173
 		numCap := fmt.Sprintf("%d", realCap.Value)
174 174
 		newCaps = append(newCaps, numCap)
175 175
 	}
... ...
@@ -180,13 +179,10 @@ func keepCapabilities(adds []string, drops []string) ([]string, error) {
180 180
 func dropList(drops []string) ([]string, error) {
181 181
 	if utils.StringsContainsNoCase(drops, "all") {
182 182
 		var newCaps []string
183
-		for _, cap := range capabilities.GetAllCapabilities() {
184
-			log.Debugf("drop cap %s\n", cap)
185
-			realCap := capabilities.GetCapability(cap)
186
-			if realCap == nil {
187
-				return nil, fmt.Errorf("Invalid capability '%s'", cap)
188
-			}
189
-			numCap := fmt.Sprintf("%d", realCap.Value)
183
+		for _, capName := range execdriver.GetAllCapabilities() {
184
+			cap := execdriver.GetCapability(capName)
185
+			log.Debugf("drop cap %s\n", cap.Key)
186
+			numCap := fmt.Sprintf("%d", cap.Value)
190 187
 			newCaps = append(newCaps, numCap)
191 188
 		}
192 189
 		return newCaps, nil
... ...
@@ -5,11 +5,6 @@ package lxc
5 5
 import (
6 6
 	"bufio"
7 7
 	"fmt"
8
-	"github.com/docker/docker/daemon/execdriver"
9
-	nativeTemplate "github.com/docker/docker/daemon/execdriver/native/template"
10
-	"github.com/docker/libcontainer/devices"
11
-	"github.com/docker/libcontainer/security/capabilities"
12
-	"github.com/syndtr/gocapability/capability"
13 8
 	"io/ioutil"
14 9
 	"math/rand"
15 10
 	"os"
... ...
@@ -17,6 +12,11 @@ import (
17 17
 	"strings"
18 18
 	"testing"
19 19
 	"time"
20
+
21
+	"github.com/docker/docker/daemon/execdriver"
22
+	nativeTemplate "github.com/docker/docker/daemon/execdriver/native/template"
23
+	"github.com/docker/libcontainer/configs"
24
+	"github.com/syndtr/gocapability/capability"
20 25
 )
21 26
 
22 27
 func TestLXCConfig(t *testing.T) {
... ...
@@ -53,7 +53,7 @@ func TestLXCConfig(t *testing.T) {
53 53
 			Mtu:       1500,
54 54
 			Interface: nil,
55 55
 		},
56
-		AllowedDevices: make([]*devices.Device, 0),
56
+		AllowedDevices: make([]*configs.Device, 0),
57 57
 		ProcessConfig:  execdriver.ProcessConfig{},
58 58
 	}
59 59
 	p, err := driver.generateLXCConfig(command)
... ...
@@ -295,7 +295,7 @@ func TestCustomLxcConfigMisc(t *testing.T) {
295 295
 	grepFile(t, p, "lxc.cgroup.cpuset.cpus = 0,1")
296 296
 	container := nativeTemplate.New()
297 297
 	for _, cap := range container.Capabilities {
298
-		realCap := capabilities.GetCapability(cap)
298
+		realCap := execdriver.GetCapability(cap)
299 299
 		numCap := fmt.Sprintf("%d", realCap.Value)
300 300
 		if cap != "MKNOD" && cap != "KILL" {
301 301
 			grepFile(t, p, fmt.Sprintf("lxc.cap.keep = %s", numCap))
... ...
@@ -359,7 +359,7 @@ func TestCustomLxcConfigMiscOverride(t *testing.T) {
359 359
 	grepFile(t, p, "lxc.cgroup.cpuset.cpus = 0,1")
360 360
 	container := nativeTemplate.New()
361 361
 	for _, cap := range container.Capabilities {
362
-		realCap := capabilities.GetCapability(cap)
362
+		realCap := execdriver.GetCapability(cap)
363 363
 		numCap := fmt.Sprintf("%d", realCap.Value)
364 364
 		if cap != "MKNOD" && cap != "KILL" {
365 365
 			grepFile(t, p, fmt.Sprintf("lxc.cap.keep = %s", numCap))
... ...
@@ -3,21 +3,24 @@
3 3
 package native
4 4
 
5 5
 import (
6
+	"errors"
6 7
 	"fmt"
7
-	"os/exec"
8
+	"net"
8 9
 	"path/filepath"
10
+	"strings"
11
+	"syscall"
9 12
 
10 13
 	"github.com/docker/docker/daemon/execdriver"
11
-	"github.com/docker/libcontainer"
14
+	"github.com/docker/docker/pkg/symlink"
12 15
 	"github.com/docker/libcontainer/apparmor"
16
+	"github.com/docker/libcontainer/configs"
13 17
 	"github.com/docker/libcontainer/devices"
14
-	"github.com/docker/libcontainer/mount"
15
-	"github.com/docker/libcontainer/security/capabilities"
18
+	"github.com/docker/libcontainer/utils"
16 19
 )
17 20
 
18 21
 // createContainer populates and configures the container type with the
19 22
 // data provided by the execdriver.Command
20
-func (d *driver) createContainer(c *execdriver.Command) (*libcontainer.Config, error) {
23
+func (d *driver) createContainer(c *execdriver.Command) (*configs.Config, error) {
21 24
 	container := execdriver.InitContainer(c)
22 25
 
23 26
 	if err := d.createIpc(container, c); err != nil {
... ...
@@ -33,6 +36,13 @@ func (d *driver) createContainer(c *execdriver.Command) (*libcontainer.Config, e
33 33
 	}
34 34
 
35 35
 	if c.ProcessConfig.Privileged {
36
+		// clear readonly for /sys
37
+		for i := range container.Mounts {
38
+			if container.Mounts[i].Destination == "/sys" {
39
+				container.Mounts[i].Flags &= ^syscall.MS_RDONLY
40
+			}
41
+		}
42
+		container.ReadonlyPaths = nil
36 43
 		if err := d.setPrivileged(container); err != nil {
37 44
 			return nil, err
38 45
 		}
... ...
@@ -57,43 +67,52 @@ func (d *driver) createContainer(c *execdriver.Command) (*libcontainer.Config, e
57 57
 	if err := d.setupLabels(container, c); err != nil {
58 58
 		return nil, err
59 59
 	}
60
-
61 60
 	d.setupRlimits(container, c)
61
+	return container, nil
62
+}
62 63
 
63
-	cmds := make(map[string]*exec.Cmd)
64
-	d.Lock()
65
-	for k, v := range d.activeContainers {
66
-		cmds[k] = v.cmd
64
+func generateIfaceName() (string, error) {
65
+	for i := 0; i < 10; i++ {
66
+		name, err := utils.GenerateRandomName("veth", 7)
67
+		if err != nil {
68
+			continue
69
+		}
70
+		if _, err := net.InterfaceByName(name); err != nil {
71
+			if strings.Contains(err.Error(), "no such") {
72
+				return name, nil
73
+			}
74
+			return "", err
75
+		}
67 76
 	}
68
-	d.Unlock()
69
-
70
-	return container, nil
77
+	return "", errors.New("Failed to find name for new interface")
71 78
 }
72 79
 
73
-func (d *driver) createNetwork(container *libcontainer.Config, c *execdriver.Command) error {
80
+func (d *driver) createNetwork(container *configs.Config, c *execdriver.Command) error {
74 81
 	if c.Network.HostNetworking {
75
-		container.Namespaces.Remove(libcontainer.NEWNET)
82
+		container.Namespaces.Remove(configs.NEWNET)
76 83
 		return nil
77 84
 	}
78 85
 
79
-	container.Networks = []*libcontainer.Network{
86
+	container.Networks = []*configs.Network{
80 87
 		{
81
-			Mtu:     c.Network.Mtu,
82
-			Address: fmt.Sprintf("%s/%d", "127.0.0.1", 0),
83
-			Gateway: "localhost",
84
-			Type:    "loopback",
88
+			Type: "loopback",
85 89
 		},
86 90
 	}
87 91
 
92
+	iName, err := generateIfaceName()
93
+	if err != nil {
94
+		return err
95
+	}
88 96
 	if c.Network.Interface != nil {
89
-		vethNetwork := libcontainer.Network{
90
-			Mtu:        c.Network.Mtu,
91
-			Address:    fmt.Sprintf("%s/%d", c.Network.Interface.IPAddress, c.Network.Interface.IPPrefixLen),
92
-			MacAddress: c.Network.Interface.MacAddress,
93
-			Gateway:    c.Network.Interface.Gateway,
94
-			Type:       "veth",
95
-			Bridge:     c.Network.Interface.Bridge,
96
-			VethPrefix: "veth",
97
+		vethNetwork := configs.Network{
98
+			Name:              "eth0",
99
+			HostInterfaceName: iName,
100
+			Mtu:               c.Network.Mtu,
101
+			Address:           fmt.Sprintf("%s/%d", c.Network.Interface.IPAddress, c.Network.Interface.IPPrefixLen),
102
+			MacAddress:        c.Network.Interface.MacAddress,
103
+			Gateway:           c.Network.Interface.Gateway,
104
+			Type:              "veth",
105
+			Bridge:            c.Network.Interface.Bridge,
97 106
 		}
98 107
 		if c.Network.Interface.GlobalIPv6Address != "" {
99 108
 			vethNetwork.IPv6Address = fmt.Sprintf("%s/%d", c.Network.Interface.GlobalIPv6Address, c.Network.Interface.GlobalIPv6PrefixLen)
... ...
@@ -107,21 +126,24 @@ func (d *driver) createNetwork(container *libcontainer.Config, c *execdriver.Com
107 107
 		active := d.activeContainers[c.Network.ContainerID]
108 108
 		d.Unlock()
109 109
 
110
-		if active == nil || active.cmd.Process == nil {
110
+		if active == nil {
111 111
 			return fmt.Errorf("%s is not a valid running container to join", c.Network.ContainerID)
112 112
 		}
113
-		cmd := active.cmd
114 113
 
115
-		nspath := filepath.Join("/proc", fmt.Sprint(cmd.Process.Pid), "ns", "net")
116
-		container.Namespaces.Add(libcontainer.NEWNET, nspath)
114
+		state, err := active.State()
115
+		if err != nil {
116
+			return err
117
+		}
118
+
119
+		container.Namespaces.Add(configs.NEWNET, state.NamespacePaths[configs.NEWNET])
117 120
 	}
118 121
 
119 122
 	return nil
120 123
 }
121 124
 
122
-func (d *driver) createIpc(container *libcontainer.Config, c *execdriver.Command) error {
125
+func (d *driver) createIpc(container *configs.Config, c *execdriver.Command) error {
123 126
 	if c.Ipc.HostIpc {
124
-		container.Namespaces.Remove(libcontainer.NEWIPC)
127
+		container.Namespaces.Remove(configs.NEWIPC)
125 128
 		return nil
126 129
 	}
127 130
 
... ...
@@ -130,37 +152,38 @@ func (d *driver) createIpc(container *libcontainer.Config, c *execdriver.Command
130 130
 		active := d.activeContainers[c.Ipc.ContainerID]
131 131
 		d.Unlock()
132 132
 
133
-		if active == nil || active.cmd.Process == nil {
133
+		if active == nil {
134 134
 			return fmt.Errorf("%s is not a valid running container to join", c.Ipc.ContainerID)
135 135
 		}
136
-		cmd := active.cmd
137 136
 
138
-		container.Namespaces.Add(libcontainer.NEWIPC, filepath.Join("/proc", fmt.Sprint(cmd.Process.Pid), "ns", "ipc"))
137
+		state, err := active.State()
138
+		if err != nil {
139
+			return err
140
+		}
141
+		container.Namespaces.Add(configs.NEWIPC, state.NamespacePaths[configs.NEWIPC])
139 142
 	}
140 143
 
141 144
 	return nil
142 145
 }
143 146
 
144
-func (d *driver) createPid(container *libcontainer.Config, c *execdriver.Command) error {
147
+func (d *driver) createPid(container *configs.Config, c *execdriver.Command) error {
145 148
 	if c.Pid.HostPid {
146
-		container.Namespaces.Remove(libcontainer.NEWPID)
149
+		container.Namespaces.Remove(configs.NEWPID)
147 150
 		return nil
148 151
 	}
149 152
 
150 153
 	return nil
151 154
 }
152 155
 
153
-func (d *driver) setPrivileged(container *libcontainer.Config) (err error) {
154
-	container.Capabilities = capabilities.GetAllCapabilities()
156
+func (d *driver) setPrivileged(container *configs.Config) (err error) {
157
+	container.Capabilities = execdriver.GetAllCapabilities()
155 158
 	container.Cgroups.AllowAllDevices = true
156 159
 
157
-	hostDeviceNodes, err := devices.GetHostDeviceNodes()
160
+	hostDevices, err := devices.HostDevices()
158 161
 	if err != nil {
159 162
 		return err
160 163
 	}
161
-	container.MountConfig.DeviceNodes = hostDeviceNodes
162
-
163
-	container.RestrictSys = false
164
+	container.Devices = hostDevices
164 165
 
165 166
 	if apparmor.IsEnabled() {
166 167
 		container.AppArmorProfile = "unconfined"
... ...
@@ -169,39 +192,52 @@ func (d *driver) setPrivileged(container *libcontainer.Config) (err error) {
169 169
 	return nil
170 170
 }
171 171
 
172
-func (d *driver) setCapabilities(container *libcontainer.Config, c *execdriver.Command) (err error) {
172
+func (d *driver) setCapabilities(container *configs.Config, c *execdriver.Command) (err error) {
173 173
 	container.Capabilities, err = execdriver.TweakCapabilities(container.Capabilities, c.CapAdd, c.CapDrop)
174 174
 	return err
175 175
 }
176 176
 
177
-func (d *driver) setupRlimits(container *libcontainer.Config, c *execdriver.Command) {
177
+func (d *driver) setupRlimits(container *configs.Config, c *execdriver.Command) {
178 178
 	if c.Resources == nil {
179 179
 		return
180 180
 	}
181 181
 
182 182
 	for _, rlimit := range c.Resources.Rlimits {
183
-		container.Rlimits = append(container.Rlimits, libcontainer.Rlimit((*rlimit)))
183
+		container.Rlimits = append(container.Rlimits, configs.Rlimit{
184
+			Type: rlimit.Type,
185
+			Hard: rlimit.Hard,
186
+			Soft: rlimit.Soft,
187
+		})
184 188
 	}
185 189
 }
186 190
 
187
-func (d *driver) setupMounts(container *libcontainer.Config, c *execdriver.Command) error {
191
+func (d *driver) setupMounts(container *configs.Config, c *execdriver.Command) error {
188 192
 	for _, m := range c.Mounts {
189
-		container.MountConfig.Mounts = append(container.MountConfig.Mounts, &mount.Mount{
190
-			Type:        "bind",
193
+		dest, err := symlink.FollowSymlinkInScope(filepath.Join(c.Rootfs, m.Destination), c.Rootfs)
194
+		if err != nil {
195
+			return err
196
+		}
197
+		flags := syscall.MS_BIND | syscall.MS_REC
198
+		if !m.Writable {
199
+			flags |= syscall.MS_RDONLY
200
+		}
201
+		if m.Slave {
202
+			flags |= syscall.MS_SLAVE
203
+		}
204
+
205
+		container.Mounts = append(container.Mounts, &configs.Mount{
191 206
 			Source:      m.Source,
192
-			Destination: m.Destination,
193
-			Writable:    m.Writable,
194
-			Private:     m.Private,
195
-			Slave:       m.Slave,
207
+			Destination: dest,
208
+			Device:      "bind",
209
+			Flags:       flags,
196 210
 		})
197 211
 	}
198
-
199 212
 	return nil
200 213
 }
201 214
 
202
-func (d *driver) setupLabels(container *libcontainer.Config, c *execdriver.Command) error {
215
+func (d *driver) setupLabels(container *configs.Config, c *execdriver.Command) error {
203 216
 	container.ProcessLabel = c.ProcessLabel
204
-	container.MountConfig.MountLabel = c.MountLabel
217
+	container.MountLabel = c.MountLabel
205 218
 
206 219
 	return nil
207 220
 }
... ...
@@ -4,28 +4,28 @@ package native
4 4
 
5 5
 import (
6 6
 	"encoding/json"
7
-	"errors"
8 7
 	"fmt"
9 8
 	"io"
10 9
 	"io/ioutil"
11 10
 	"os"
12 11
 	"os/exec"
13 12
 	"path/filepath"
13
+	"strings"
14 14
 	"sync"
15 15
 	"syscall"
16
+	"time"
16 17
 
17 18
 	log "github.com/Sirupsen/logrus"
18 19
 	"github.com/docker/docker/daemon/execdriver"
20
+	"github.com/docker/docker/pkg/reexec"
19 21
 	sysinfo "github.com/docker/docker/pkg/system"
20 22
 	"github.com/docker/docker/pkg/term"
21 23
 	"github.com/docker/libcontainer"
22 24
 	"github.com/docker/libcontainer/apparmor"
23
-	"github.com/docker/libcontainer/cgroups/fs"
24 25
 	"github.com/docker/libcontainer/cgroups/systemd"
25
-	consolepkg "github.com/docker/libcontainer/console"
26
-	"github.com/docker/libcontainer/namespaces"
27
-	_ "github.com/docker/libcontainer/namespaces/nsenter"
26
+	"github.com/docker/libcontainer/configs"
28 27
 	"github.com/docker/libcontainer/system"
28
+	"github.com/docker/libcontainer/utils"
29 29
 )
30 30
 
31 31
 const (
... ...
@@ -33,16 +33,12 @@ const (
33 33
 	Version    = "0.2"
34 34
 )
35 35
 
36
-type activeContainer struct {
37
-	container *libcontainer.Config
38
-	cmd       *exec.Cmd
39
-}
40
-
41 36
 type driver struct {
42 37
 	root             string
43 38
 	initPath         string
44
-	activeContainers map[string]*activeContainer
39
+	activeContainers map[string]libcontainer.Container
45 40
 	machineMemory    int64
41
+	factory          libcontainer.Factory
46 42
 	sync.Mutex
47 43
 }
48 44
 
... ...
@@ -59,11 +55,22 @@ func NewDriver(root, initPath string) (*driver, error) {
59 59
 	if err := apparmor.InstallDefaultProfile(); err != nil {
60 60
 		return nil, err
61 61
 	}
62
+	cgm := libcontainer.Cgroupfs
63
+	if systemd.UseSystemd() {
64
+		cgm = libcontainer.SystemdCgroups
65
+	}
66
+
67
+	f, err := libcontainer.New(root, cgm, libcontainer.InitPath(reexec.Self(), DriverName))
68
+	if err != nil {
69
+		return nil, err
70
+	}
71
+
62 72
 	return &driver{
63 73
 		root:             root,
64 74
 		initPath:         initPath,
65
-		activeContainers: make(map[string]*activeContainer),
75
+		activeContainers: make(map[string]libcontainer.Container),
66 76
 		machineMemory:    meminfo.MemTotal,
77
+		factory:          f,
67 78
 	}, nil
68 79
 }
69 80
 
... ...
@@ -81,101 +88,141 @@ func (d *driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, startCallba
81 81
 
82 82
 	var term execdriver.Terminal
83 83
 
84
+	p := &libcontainer.Process{
85
+		Args: append([]string{c.ProcessConfig.Entrypoint}, c.ProcessConfig.Arguments...),
86
+		Env:  c.ProcessConfig.Env,
87
+		Cwd:  c.WorkingDir,
88
+		User: c.ProcessConfig.User,
89
+	}
90
+
84 91
 	if c.ProcessConfig.Tty {
85
-		term, err = NewTtyConsole(&c.ProcessConfig, pipes)
92
+		rootuid, err := container.HostUID()
93
+		if err != nil {
94
+			return execdriver.ExitStatus{ExitCode: -1}, err
95
+		}
96
+		cons, err := p.NewConsole(rootuid)
97
+		if err != nil {
98
+			return execdriver.ExitStatus{ExitCode: -1}, err
99
+		}
100
+		term, err = NewTtyConsole(cons, pipes, rootuid)
86 101
 	} else {
87
-		term, err = execdriver.NewStdConsole(&c.ProcessConfig, pipes)
102
+		p.Stdout = pipes.Stdout
103
+		p.Stderr = pipes.Stderr
104
+		r, w, err := os.Pipe()
105
+		if err != nil {
106
+			return execdriver.ExitStatus{ExitCode: -1}, err
107
+		}
108
+		if pipes.Stdin != nil {
109
+			go func() {
110
+				io.Copy(w, pipes.Stdin)
111
+				w.Close()
112
+			}()
113
+			p.Stdin = r
114
+		}
115
+		term = &execdriver.StdConsole{}
88 116
 	}
89 117
 	if err != nil {
90 118
 		return execdriver.ExitStatus{ExitCode: -1}, err
91 119
 	}
92 120
 	c.ProcessConfig.Terminal = term
93 121
 
94
-	d.Lock()
95
-	d.activeContainers[c.ID] = &activeContainer{
96
-		container: container,
97
-		cmd:       &c.ProcessConfig.Cmd,
122
+	cont, err := d.factory.Create(c.ID, container)
123
+	if err != nil {
124
+		return execdriver.ExitStatus{ExitCode: -1}, err
98 125
 	}
126
+	d.Lock()
127
+	d.activeContainers[c.ID] = cont
99 128
 	d.Unlock()
129
+	defer func() {
130
+		cont.Destroy()
131
+		d.cleanContainer(c.ID)
132
+	}()
100 133
 
101
-	var (
102
-		dataPath = filepath.Join(d.root, c.ID)
103
-		args     = append([]string{c.ProcessConfig.Entrypoint}, c.ProcessConfig.Arguments...)
104
-	)
105
-
106
-	if err := d.createContainerRoot(c.ID); err != nil {
134
+	if err := cont.Start(p); err != nil {
107 135
 		return execdriver.ExitStatus{ExitCode: -1}, err
108 136
 	}
109
-	defer d.cleanContainer(c.ID)
110 137
 
111
-	if err := d.writeContainerFile(container, c.ID); err != nil {
112
-		return execdriver.ExitStatus{ExitCode: -1}, err
138
+	if startCallback != nil {
139
+		pid, err := p.Pid()
140
+		if err != nil {
141
+			p.Signal(os.Kill)
142
+			p.Wait()
143
+			return execdriver.ExitStatus{ExitCode: -1}, err
144
+		}
145
+		startCallback(&c.ProcessConfig, pid)
146
+	}
147
+
148
+	oomKillNotification, err := cont.NotifyOOM()
149
+	if err != nil {
150
+		oomKillNotification = nil
151
+		log.Warnf("WARNING: Your kernel does not support OOM notifications: %s", err)
152
+	}
153
+	waitF := p.Wait
154
+	if nss := cont.Config().Namespaces; nss.Contains(configs.NEWPID) {
155
+		// we need such hack for tracking processes with inerited fds,
156
+		// because cmd.Wait() waiting for all streams to be copied
157
+		waitF = waitInPIDHost(p, cont)
158
+	}
159
+	ps, err := waitF()
160
+	if err != nil {
161
+		if err, ok := err.(*exec.ExitError); !ok {
162
+			return execdriver.ExitStatus{ExitCode: -1}, err
163
+		} else {
164
+			ps = err.ProcessState
165
+		}
113 166
 	}
167
+	cont.Destroy()
114 168
 
115
-	execOutputChan := make(chan execOutput, 1)
116
-	waitForStart := make(chan struct{})
169
+	_, oomKill := <-oomKillNotification
117 170
 
118
-	go func() {
119
-		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 {
120
-			c.ProcessConfig.Path = d.initPath
121
-			c.ProcessConfig.Args = append([]string{
122
-				DriverName,
123
-				"-console", console,
124
-				"-pipe", "3",
125
-				"-root", filepath.Join(d.root, c.ID),
126
-				"--",
127
-			}, args...)
128
-
129
-			// set this to nil so that when we set the clone flags anything else is reset
130
-			c.ProcessConfig.SysProcAttr = &syscall.SysProcAttr{
131
-				Cloneflags: uintptr(namespaces.GetNamespaceFlags(container.Namespaces)),
132
-			}
133
-			c.ProcessConfig.ExtraFiles = []*os.File{child}
171
+	return execdriver.ExitStatus{ExitCode: utils.ExitStatus(ps.Sys().(syscall.WaitStatus)), OOMKilled: oomKill}, nil
172
+}
134 173
 
135
-			c.ProcessConfig.Env = container.Env
136
-			c.ProcessConfig.Dir = container.RootFs
174
+func waitInPIDHost(p *libcontainer.Process, c libcontainer.Container) func() (*os.ProcessState, error) {
175
+	return func() (*os.ProcessState, error) {
176
+		pid, err := p.Pid()
177
+		if err != nil {
178
+			return nil, err
179
+		}
137 180
 
138
-			return &c.ProcessConfig.Cmd
139
-		}, func() {
140
-			close(waitForStart)
141
-			if startCallback != nil {
142
-				c.ContainerPid = c.ProcessConfig.Process.Pid
143
-				startCallback(&c.ProcessConfig, c.ContainerPid)
181
+		process, err := os.FindProcess(pid)
182
+		s, err := process.Wait()
183
+		if err != nil {
184
+			if err, ok := err.(*exec.ExitError); !ok {
185
+				return s, err
186
+			} else {
187
+				s = err.ProcessState
144 188
 			}
145
-		})
146
-		execOutputChan <- execOutput{exitCode, err}
147
-	}()
148
-
149
-	select {
150
-	case execOutput := <-execOutputChan:
151
-		return execdriver.ExitStatus{ExitCode: execOutput.exitCode}, execOutput.err
152
-	case <-waitForStart:
153
-		break
154
-	}
189
+		}
190
+		processes, err := c.Processes()
191
+		if err != nil {
192
+			return s, err
193
+		}
155 194
 
156
-	oomKill := false
157
-	state, err := libcontainer.GetState(filepath.Join(d.root, c.ID))
158
-	if err == nil {
159
-		oomKillNotification, err := libcontainer.NotifyOnOOM(state)
160
-		if err == nil {
161
-			_, oomKill = <-oomKillNotification
162
-		} else {
163
-			log.Warnf("WARNING: Your kernel does not support OOM notifications: %s", err)
195
+		for _, pid := range processes {
196
+			process, err := os.FindProcess(pid)
197
+			if err != nil {
198
+				log.Errorf("Failed to kill process: %d", pid)
199
+				continue
200
+			}
201
+			process.Kill()
164 202
 		}
165
-	} else {
166
-		log.Warnf("Failed to get container state, oom notify will not work: %s", err)
167
-	}
168
-	// wait for the container to exit.
169
-	execOutput := <-execOutputChan
170 203
 
171
-	return execdriver.ExitStatus{ExitCode: execOutput.exitCode, OOMKilled: oomKill}, execOutput.err
204
+		p.Wait()
205
+		return s, err
206
+	}
172 207
 }
173 208
 
174
-func (d *driver) Kill(p *execdriver.Command, sig int) error {
175
-	if p.ProcessConfig.Process == nil {
176
-		return errors.New("exec: not started")
209
+func (d *driver) Kill(c *execdriver.Command, sig int) error {
210
+	active := d.activeContainers[c.ID]
211
+	if active == nil {
212
+		return fmt.Errorf("active container for %s does not exist", c.ID)
177 213
 	}
178
-	return syscall.Kill(p.ProcessConfig.Process.Pid, syscall.Signal(sig))
214
+	state, err := active.State()
215
+	if err != nil {
216
+		return err
217
+	}
218
+	return syscall.Kill(state.InitProcessPid, syscall.Signal(sig))
179 219
 }
180 220
 
181 221
 func (d *driver) Pause(c *execdriver.Command) error {
... ...
@@ -183,11 +230,7 @@ func (d *driver) Pause(c *execdriver.Command) error {
183 183
 	if active == nil {
184 184
 		return fmt.Errorf("active container for %s does not exist", c.ID)
185 185
 	}
186
-	active.container.Cgroups.Freezer = "FROZEN"
187
-	if systemd.UseSystemd() {
188
-		return systemd.Freeze(active.container.Cgroups, active.container.Cgroups.Freezer)
189
-	}
190
-	return fs.Freeze(active.container.Cgroups, active.container.Cgroups.Freezer)
186
+	return active.Pause()
191 187
 }
192 188
 
193 189
 func (d *driver) Unpause(c *execdriver.Command) error {
... ...
@@ -195,44 +238,31 @@ func (d *driver) Unpause(c *execdriver.Command) error {
195 195
 	if active == nil {
196 196
 		return fmt.Errorf("active container for %s does not exist", c.ID)
197 197
 	}
198
-	active.container.Cgroups.Freezer = "THAWED"
199
-	if systemd.UseSystemd() {
200
-		return systemd.Freeze(active.container.Cgroups, active.container.Cgroups.Freezer)
201
-	}
202
-	return fs.Freeze(active.container.Cgroups, active.container.Cgroups.Freezer)
198
+	return active.Resume()
203 199
 }
204 200
 
205
-func (d *driver) Terminate(p *execdriver.Command) error {
201
+func (d *driver) Terminate(c *execdriver.Command) error {
206 202
 	// lets check the start time for the process
207
-	state, err := libcontainer.GetState(filepath.Join(d.root, p.ID))
203
+	active := d.activeContainers[c.ID]
204
+	if active == nil {
205
+		return fmt.Errorf("active container for %s does not exist", c.ID)
206
+	}
207
+	state, err := active.State()
208 208
 	if err != nil {
209
-		if !os.IsNotExist(err) {
210
-			return err
211
-		}
212
-		// TODO: Remove this part for version 1.2.0
213
-		// This is added only to ensure smooth upgrades from pre 1.1.0 to 1.1.0
214
-		data, err := ioutil.ReadFile(filepath.Join(d.root, p.ID, "start"))
215
-		if err != nil {
216
-			// if we don't have the data on disk then we can assume the process is gone
217
-			// because this is only removed after we know the process has stopped
218
-			if os.IsNotExist(err) {
219
-				return nil
220
-			}
221
-			return err
222
-		}
223
-		state = &libcontainer.State{InitStartTime: string(data)}
209
+		return err
224 210
 	}
211
+	pid := state.InitProcessPid
225 212
 
226
-	currentStartTime, err := system.GetProcessStartTime(p.ProcessConfig.Process.Pid)
213
+	currentStartTime, err := system.GetProcessStartTime(pid)
227 214
 	if err != nil {
228 215
 		return err
229 216
 	}
230 217
 
231
-	if state.InitStartTime == currentStartTime {
232
-		err = syscall.Kill(p.ProcessConfig.Process.Pid, 9)
233
-		syscall.Wait4(p.ProcessConfig.Process.Pid, nil, 0, nil)
218
+	if state.InitProcessStartTime == currentStartTime {
219
+		err = syscall.Kill(pid, 9)
220
+		syscall.Wait4(pid, nil, 0, nil)
234 221
 	}
235
-	d.cleanContainer(p.ID)
222
+	d.cleanContainer(c.ID)
236 223
 
237 224
 	return err
238 225
 
... ...
@@ -257,15 +287,10 @@ func (d *driver) GetPidsForContainer(id string) ([]int, error) {
257 257
 	if active == nil {
258 258
 		return nil, fmt.Errorf("active container for %s does not exist", id)
259 259
 	}
260
-	c := active.container.Cgroups
261
-
262
-	if systemd.UseSystemd() {
263
-		return systemd.GetPids(c)
264
-	}
265
-	return fs.GetPids(c)
260
+	return active.Processes()
266 261
 }
267 262
 
268
-func (d *driver) writeContainerFile(container *libcontainer.Config, id string) error {
263
+func (d *driver) writeContainerFile(container *configs.Config, id string) error {
269 264
 	data, err := json.Marshal(container)
270 265
 	if err != nil {
271 266
 		return err
... ...
@@ -289,42 +314,61 @@ func (d *driver) Clean(id string) error {
289 289
 }
290 290
 
291 291
 func (d *driver) Stats(id string) (*execdriver.ResourceStats, error) {
292
-	return execdriver.Stats(filepath.Join(d.root, id), d.activeContainers[id].container.Cgroups.Memory, d.machineMemory)
292
+	c := d.activeContainers[id]
293
+	now := time.Now()
294
+	stats, err := c.Stats()
295
+	if err != nil {
296
+		return nil, err
297
+	}
298
+	memoryLimit := c.Config().Cgroups.Memory
299
+	// if the container does not have any memory limit specified set the
300
+	// limit to the machines memory
301
+	if memoryLimit == 0 {
302
+		memoryLimit = d.machineMemory
303
+	}
304
+	return &execdriver.ResourceStats{
305
+		Stats:       stats,
306
+		Read:        now,
307
+		MemoryLimit: memoryLimit,
308
+	}, nil
293 309
 }
294 310
 
295
-type TtyConsole struct {
296
-	MasterPty *os.File
311
+func getEnv(key string, env []string) string {
312
+	for _, pair := range env {
313
+		parts := strings.Split(pair, "=")
314
+		if parts[0] == key {
315
+			return parts[1]
316
+		}
317
+	}
318
+	return ""
297 319
 }
298 320
 
299
-func NewTtyConsole(processConfig *execdriver.ProcessConfig, pipes *execdriver.Pipes) (*TtyConsole, error) {
300
-	ptyMaster, console, err := consolepkg.CreateMasterAndConsole()
301
-	if err != nil {
302
-		return nil, err
303
-	}
321
+type TtyConsole struct {
322
+	console libcontainer.Console
323
+}
304 324
 
325
+func NewTtyConsole(console libcontainer.Console, pipes *execdriver.Pipes, rootuid int) (*TtyConsole, error) {
305 326
 	tty := &TtyConsole{
306
-		MasterPty: ptyMaster,
327
+		console: console,
307 328
 	}
308 329
 
309
-	if err := tty.AttachPipes(&processConfig.Cmd, pipes); err != nil {
330
+	if err := tty.AttachPipes(pipes); err != nil {
310 331
 		tty.Close()
311 332
 		return nil, err
312 333
 	}
313 334
 
314
-	processConfig.Console = console
315
-
316 335
 	return tty, nil
317 336
 }
318 337
 
319
-func (t *TtyConsole) Master() *os.File {
320
-	return t.MasterPty
338
+func (t *TtyConsole) Master() libcontainer.Console {
339
+	return t.console
321 340
 }
322 341
 
323 342
 func (t *TtyConsole) Resize(h, w int) error {
324
-	return term.SetWinsize(t.MasterPty.Fd(), &term.Winsize{Height: uint16(h), Width: uint16(w)})
343
+	return term.SetWinsize(t.console.Fd(), &term.Winsize{Height: uint16(h), Width: uint16(w)})
325 344
 }
326 345
 
327
-func (t *TtyConsole) AttachPipes(command *exec.Cmd, pipes *execdriver.Pipes) error {
346
+func (t *TtyConsole) AttachPipes(pipes *execdriver.Pipes) error {
328 347
 	go func() {
329 348
 		if wb, ok := pipes.Stdout.(interface {
330 349
 			CloseWriters() error
... ...
@@ -332,12 +376,12 @@ func (t *TtyConsole) AttachPipes(command *exec.Cmd, pipes *execdriver.Pipes) err
332 332
 			defer wb.CloseWriters()
333 333
 		}
334 334
 
335
-		io.Copy(pipes.Stdout, t.MasterPty)
335
+		io.Copy(pipes.Stdout, t.console)
336 336
 	}()
337 337
 
338 338
 	if pipes.Stdin != nil {
339 339
 		go func() {
340
-			io.Copy(t.MasterPty, pipes.Stdin)
340
+			io.Copy(t.console, pipes.Stdin)
341 341
 
342 342
 			pipes.Stdin.Close()
343 343
 		}()
... ...
@@ -347,5 +391,5 @@ func (t *TtyConsole) AttachPipes(command *exec.Cmd, pipes *execdriver.Pipes) err
347 347
 }
348 348
 
349 349
 func (t *TtyConsole) Close() error {
350
-	return t.MasterPty.Close()
350
+	return t.console.Close()
351 351
 }
... ...
@@ -4,67 +4,77 @@ package native
4 4
 
5 5
 import (
6 6
 	"fmt"
7
-	"log"
8 7
 	"os"
9 8
 	"os/exec"
10
-	"path/filepath"
11
-	"runtime"
9
+	"syscall"
12 10
 
13 11
 	"github.com/docker/docker/daemon/execdriver"
14
-	"github.com/docker/docker/pkg/reexec"
15 12
 	"github.com/docker/libcontainer"
16
-	"github.com/docker/libcontainer/namespaces"
13
+	_ "github.com/docker/libcontainer/nsenter"
14
+	"github.com/docker/libcontainer/utils"
17 15
 )
18 16
 
19
-const execCommandName = "nsenter-exec"
20
-
21
-func init() {
22
-	reexec.Register(execCommandName, nsenterExec)
23
-}
24
-
25
-func nsenterExec() {
26
-	runtime.LockOSThread()
27
-
28
-	// User args are passed after '--' in the command line.
29
-	userArgs := findUserArgs()
30
-
31
-	config, err := loadConfigFromFd()
32
-	if err != nil {
33
-		log.Fatalf("docker-exec: unable to receive config from sync pipe: %s", err)
34
-	}
35
-
36
-	if err := namespaces.FinalizeSetns(config, userArgs); err != nil {
37
-		log.Fatalf("docker-exec: failed to exec: %s", err)
38
-	}
39
-}
40
-
41 17
 // TODO(vishh): Add support for running in priviledged mode and running as a different user.
42 18
 func (d *driver) Exec(c *execdriver.Command, processConfig *execdriver.ProcessConfig, pipes *execdriver.Pipes, startCallback execdriver.StartCallback) (int, error) {
43 19
 	active := d.activeContainers[c.ID]
44 20
 	if active == nil {
45 21
 		return -1, fmt.Errorf("No active container exists with ID %s", c.ID)
46 22
 	}
47
-	state, err := libcontainer.GetState(filepath.Join(d.root, c.ID))
48
-	if err != nil {
49
-		return -1, fmt.Errorf("State unavailable for container with ID %s. The container may have been cleaned up already. Error: %s", c.ID, err)
50
-	}
51 23
 
52 24
 	var term execdriver.Terminal
25
+	var err error
26
+
27
+	p := &libcontainer.Process{
28
+		Args: append([]string{processConfig.Entrypoint}, processConfig.Arguments...),
29
+		Env:  c.ProcessConfig.Env,
30
+		Cwd:  c.WorkingDir,
31
+		User: c.ProcessConfig.User,
32
+	}
53 33
 
54 34
 	if processConfig.Tty {
55
-		term, err = NewTtyConsole(processConfig, pipes)
35
+		config := active.Config()
36
+		rootuid, err := config.HostUID()
37
+		if err != nil {
38
+			return -1, err
39
+		}
40
+		cons, err := p.NewConsole(rootuid)
41
+		if err != nil {
42
+			return -1, err
43
+		}
44
+		term, err = NewTtyConsole(cons, pipes, rootuid)
56 45
 	} else {
57
-		term, err = execdriver.NewStdConsole(processConfig, pipes)
46
+		p.Stdout = pipes.Stdout
47
+		p.Stderr = pipes.Stderr
48
+		p.Stdin = pipes.Stdin
49
+		term = &execdriver.StdConsole{}
50
+	}
51
+	if err != nil {
52
+		return -1, err
58 53
 	}
59 54
 
60 55
 	processConfig.Terminal = term
61 56
 
62
-	args := append([]string{processConfig.Entrypoint}, processConfig.Arguments...)
57
+	if err := active.Start(p); err != nil {
58
+		return -1, err
59
+	}
60
+
61
+	if startCallback != nil {
62
+		pid, err := p.Pid()
63
+		if err != nil {
64
+			p.Signal(os.Kill)
65
+			p.Wait()
66
+			return -1, err
67
+		}
68
+		startCallback(&c.ProcessConfig, pid)
69
+	}
63 70
 
64
-	return namespaces.ExecIn(active.container, state, args, os.Args[0], "exec", processConfig.Stdin, processConfig.Stdout, processConfig.Stderr, processConfig.Console,
65
-		func(cmd *exec.Cmd) {
66
-			if startCallback != nil {
67
-				startCallback(&c.ProcessConfig, cmd.Process.Pid)
68
-			}
69
-		})
71
+	ps, err := p.Wait()
72
+	if err != nil {
73
+		exitErr, ok := err.(*exec.ExitError)
74
+		if !ok {
75
+			return -1, err
76
+		}
77
+		ps = exitErr.ProcessState
78
+	}
79
+	return utils.ExitStatus(ps.Sys().(syscall.WaitStatus)), nil
70 80
 }
... ...
@@ -2,13 +2,6 @@
2 2
 
3 3
 package native
4 4
 
5
-import (
6
-	"os"
7
-	"path/filepath"
8
-
9
-	"github.com/docker/libcontainer"
10
-)
11
-
12 5
 type info struct {
13 6
 	ID     string
14 7
 	driver *driver
... ...
@@ -18,13 +11,6 @@ type info struct {
18 18
 // pid file for a container.  If the file exists then the
19 19
 // container is currently running
20 20
 func (i *info) IsRunning() bool {
21
-	if _, err := libcontainer.GetState(filepath.Join(i.driver.root, i.ID)); err == nil {
22
-		return true
23
-	}
24
-	// TODO: Remove this part for version 1.2.0
25
-	// This is added only to ensure smooth upgrades from pre 1.1.0 to 1.1.0
26
-	if _, err := os.Stat(filepath.Join(i.driver.root, i.ID, "pid")); err == nil {
27
-		return true
28
-	}
29
-	return false
21
+	_, ok := i.driver.activeContainers[i.ID]
22
+	return ok
30 23
 }
... ...
@@ -3,55 +3,40 @@
3 3
 package native
4 4
 
5 5
 import (
6
-	"encoding/json"
7
-	"flag"
8 6
 	"fmt"
9 7
 	"os"
10
-	"path/filepath"
11 8
 	"runtime"
12 9
 
13 10
 	"github.com/docker/docker/pkg/reexec"
14 11
 	"github.com/docker/libcontainer"
15
-	"github.com/docker/libcontainer/namespaces"
16 12
 )
17 13
 
18 14
 func init() {
19 15
 	reexec.Register(DriverName, initializer)
20 16
 }
21 17
 
22
-func initializer() {
23
-	runtime.LockOSThread()
24
-
25
-	var (
26
-		pipe    = flag.Int("pipe", 0, "sync pipe fd")
27
-		console = flag.String("console", "", "console (pty slave) path")
28
-		root    = flag.String("root", ".", "root path for configuration files")
29
-	)
30
-
31
-	flag.Parse()
32
-
33
-	var container *libcontainer.Config
34
-	f, err := os.Open(filepath.Join(*root, "container.json"))
35
-	if err != nil {
36
-		writeError(err)
18
+func fatal(err error) {
19
+	if lerr, ok := err.(libcontainer.Error); ok {
20
+		lerr.Detail(os.Stderr)
21
+		os.Exit(1)
37 22
 	}
38 23
 
39
-	if err := json.NewDecoder(f).Decode(&container); err != nil {
40
-		f.Close()
41
-		writeError(err)
42
-	}
43
-	f.Close()
24
+	fmt.Fprintln(os.Stderr, err)
25
+	os.Exit(1)
26
+}
44 27
 
45
-	rootfs, err := os.Getwd()
28
+func initializer() {
29
+	runtime.GOMAXPROCS(1)
30
+	runtime.LockOSThread()
31
+	factory, err := libcontainer.New("")
46 32
 	if err != nil {
47
-		writeError(err)
33
+		fatal(err)
48 34
 	}
49
-
50
-	if err := namespaces.Init(container, rootfs, *console, os.NewFile(uintptr(*pipe), "child"), flag.Args()); err != nil {
51
-		writeError(err)
35
+	if err := factory.StartInitialization(3); err != nil {
36
+		fatal(err)
52 37
 	}
53 38
 
54
-	panic("Unreachable")
39
+	panic("unreachable")
55 40
 }
56 41
 
57 42
 func writeError(err error) {
... ...
@@ -1,14 +1,17 @@
1 1
 package template
2 2
 
3 3
 import (
4
-	"github.com/docker/libcontainer"
4
+	"syscall"
5
+
5 6
 	"github.com/docker/libcontainer/apparmor"
6
-	"github.com/docker/libcontainer/cgroups"
7
+	"github.com/docker/libcontainer/configs"
7 8
 )
8 9
 
10
+const defaultMountFlags = syscall.MS_NOEXEC | syscall.MS_NOSUID | syscall.MS_NODEV
11
+
9 12
 // New returns the docker default configuration for libcontainer
10
-func New() *libcontainer.Config {
11
-	container := &libcontainer.Config{
13
+func New() *configs.Config {
14
+	container := &configs.Config{
12 15
 		Capabilities: []string{
13 16
 			"CHOWN",
14 17
 			"DAC_OVERRIDE",
... ...
@@ -25,18 +28,51 @@ func New() *libcontainer.Config {
25 25
 			"KILL",
26 26
 			"AUDIT_WRITE",
27 27
 		},
28
-		Namespaces: libcontainer.Namespaces([]libcontainer.Namespace{
28
+		Namespaces: configs.Namespaces([]configs.Namespace{
29 29
 			{Type: "NEWNS"},
30 30
 			{Type: "NEWUTS"},
31 31
 			{Type: "NEWIPC"},
32 32
 			{Type: "NEWPID"},
33 33
 			{Type: "NEWNET"},
34 34
 		}),
35
-		Cgroups: &cgroups.Cgroup{
35
+		Cgroups: &configs.Cgroup{
36 36
 			Parent:          "docker",
37 37
 			AllowAllDevices: false,
38 38
 		},
39
-		MountConfig: &libcontainer.MountConfig{},
39
+		Mounts: []*configs.Mount{
40
+			{
41
+				Device:      "tmpfs",
42
+				Source:      "shm",
43
+				Destination: "/dev/shm",
44
+				Data:        "mode=1777,size=65536k",
45
+				Flags:       defaultMountFlags,
46
+			},
47
+			{
48
+				Source:      "mqueue",
49
+				Destination: "/dev/mqueue",
50
+				Device:      "mqueue",
51
+				Flags:       defaultMountFlags,
52
+			},
53
+			{
54
+				Source:      "sysfs",
55
+				Destination: "/sys",
56
+				Device:      "sysfs",
57
+				Flags:       defaultMountFlags | syscall.MS_RDONLY,
58
+			},
59
+		},
60
+		MaskPaths: []string{
61
+			"/proc/kcore",
62
+		},
63
+		ReadonlyPaths: []string{
64
+			"/proc/sys", "/proc/sysrq-trigger", "/proc/irq", "/proc/bus",
65
+		},
66
+		Rlimits: []configs.Rlimit{
67
+			{
68
+				Type: syscall.RLIMIT_NOFILE,
69
+				Hard: 1024,
70
+				Soft: 1024,
71
+			},
72
+		},
40 73
 	}
41 74
 
42 75
 	if apparmor.IsEnabled() {
... ...
@@ -2,28 +2,21 @@
2 2
 
3 3
 package native
4 4
 
5
-import (
6
-	"encoding/json"
7
-	"os"
5
+//func findUserArgs() []string {
6
+//for i, a := range os.Args {
7
+//if a == "--" {
8
+//return os.Args[i+1:]
9
+//}
10
+//}
11
+//return []string{}
12
+//}
8 13
 
9
-	"github.com/docker/libcontainer"
10
-)
11
-
12
-func findUserArgs() []string {
13
-	for i, a := range os.Args {
14
-		if a == "--" {
15
-			return os.Args[i+1:]
16
-		}
17
-	}
18
-	return []string{}
19
-}
20
-
21
-// loadConfigFromFd loads a container's config from the sync pipe that is provided by
22
-// fd 3 when running a process
23
-func loadConfigFromFd() (*libcontainer.Config, error) {
24
-	var config *libcontainer.Config
25
-	if err := json.NewDecoder(os.NewFile(3, "child")).Decode(&config); err != nil {
26
-		return nil, err
27
-	}
28
-	return config, nil
29
-}
14
+//// loadConfigFromFd loads a container's config from the sync pipe that is provided by
15
+//// fd 3 when running a process
16
+//func loadConfigFromFd() (*configs.Config, error) {
17
+//var config *libcontainer.Config
18
+//if err := json.NewDecoder(os.NewFile(3, "child")).Decode(&config); err != nil {
19
+//return nil, err
20
+//}
21
+//return config, nil
22
+//}
... ...
@@ -5,13 +5,83 @@ import (
5 5
 	"strings"
6 6
 
7 7
 	"github.com/docker/docker/utils"
8
-	"github.com/docker/libcontainer/security/capabilities"
8
+	"github.com/syndtr/gocapability/capability"
9 9
 )
10 10
 
11
+var capabilityList = Capabilities{
12
+	{Key: "SETPCAP", Value: capability.CAP_SETPCAP},
13
+	{Key: "SYS_MODULE", Value: capability.CAP_SYS_MODULE},
14
+	{Key: "SYS_RAWIO", Value: capability.CAP_SYS_RAWIO},
15
+	{Key: "SYS_PACCT", Value: capability.CAP_SYS_PACCT},
16
+	{Key: "SYS_ADMIN", Value: capability.CAP_SYS_ADMIN},
17
+	{Key: "SYS_NICE", Value: capability.CAP_SYS_NICE},
18
+	{Key: "SYS_RESOURCE", Value: capability.CAP_SYS_RESOURCE},
19
+	{Key: "SYS_TIME", Value: capability.CAP_SYS_TIME},
20
+	{Key: "SYS_TTY_CONFIG", Value: capability.CAP_SYS_TTY_CONFIG},
21
+	{Key: "MKNOD", Value: capability.CAP_MKNOD},
22
+	{Key: "AUDIT_WRITE", Value: capability.CAP_AUDIT_WRITE},
23
+	{Key: "AUDIT_CONTROL", Value: capability.CAP_AUDIT_CONTROL},
24
+	{Key: "MAC_OVERRIDE", Value: capability.CAP_MAC_OVERRIDE},
25
+	{Key: "MAC_ADMIN", Value: capability.CAP_MAC_ADMIN},
26
+	{Key: "NET_ADMIN", Value: capability.CAP_NET_ADMIN},
27
+	{Key: "SYSLOG", Value: capability.CAP_SYSLOG},
28
+	{Key: "CHOWN", Value: capability.CAP_CHOWN},
29
+	{Key: "NET_RAW", Value: capability.CAP_NET_RAW},
30
+	{Key: "DAC_OVERRIDE", Value: capability.CAP_DAC_OVERRIDE},
31
+	{Key: "FOWNER", Value: capability.CAP_FOWNER},
32
+	{Key: "DAC_READ_SEARCH", Value: capability.CAP_DAC_READ_SEARCH},
33
+	{Key: "FSETID", Value: capability.CAP_FSETID},
34
+	{Key: "KILL", Value: capability.CAP_KILL},
35
+	{Key: "SETGID", Value: capability.CAP_SETGID},
36
+	{Key: "SETUID", Value: capability.CAP_SETUID},
37
+	{Key: "LINUX_IMMUTABLE", Value: capability.CAP_LINUX_IMMUTABLE},
38
+	{Key: "NET_BIND_SERVICE", Value: capability.CAP_NET_BIND_SERVICE},
39
+	{Key: "NET_BROADCAST", Value: capability.CAP_NET_BROADCAST},
40
+	{Key: "IPC_LOCK", Value: capability.CAP_IPC_LOCK},
41
+	{Key: "IPC_OWNER", Value: capability.CAP_IPC_OWNER},
42
+	{Key: "SYS_CHROOT", Value: capability.CAP_SYS_CHROOT},
43
+	{Key: "SYS_PTRACE", Value: capability.CAP_SYS_PTRACE},
44
+	{Key: "SYS_BOOT", Value: capability.CAP_SYS_BOOT},
45
+	{Key: "LEASE", Value: capability.CAP_LEASE},
46
+	{Key: "SETFCAP", Value: capability.CAP_SETFCAP},
47
+	{Key: "WAKE_ALARM", Value: capability.CAP_WAKE_ALARM},
48
+	{Key: "BLOCK_SUSPEND", Value: capability.CAP_BLOCK_SUSPEND},
49
+}
50
+
51
+type (
52
+	CapabilityMapping struct {
53
+		Key   string         `json:"key,omitempty"`
54
+		Value capability.Cap `json:"value,omitempty"`
55
+	}
56
+	Capabilities []*CapabilityMapping
57
+)
58
+
59
+func (c *CapabilityMapping) String() string {
60
+	return c.Key
61
+}
62
+
63
+func GetCapability(key string) *CapabilityMapping {
64
+	for _, capp := range capabilityList {
65
+		if capp.Key == key {
66
+			cpy := *capp
67
+			return &cpy
68
+		}
69
+	}
70
+	return nil
71
+}
72
+
73
+func GetAllCapabilities() []string {
74
+	output := make([]string, len(capabilityList))
75
+	for i, capability := range capabilityList {
76
+		output[i] = capability.String()
77
+	}
78
+	return output
79
+}
80
+
11 81
 func TweakCapabilities(basics, adds, drops []string) ([]string, error) {
12 82
 	var (
13 83
 		newCaps []string
14
-		allCaps = capabilities.GetAllCapabilities()
84
+		allCaps = GetAllCapabilities()
15 85
 	)
16 86
 
17 87
 	// look for invalid cap in the drop list
... ...
@@ -26,7 +96,7 @@ func TweakCapabilities(basics, adds, drops []string) ([]string, error) {
26 26
 
27 27
 	// handle --cap-add=all
28 28
 	if utils.StringsContainsNoCase(adds, "all") {
29
-		basics = capabilities.GetAllCapabilities()
29
+		basics = allCaps
30 30
 	}
31 31
 
32 32
 	if !utils.StringsContainsNoCase(drops, "all") {
... ...
@@ -18,7 +18,7 @@ func (daemon *Daemon) ContainerStats(job *engine.Job) engine.Status {
18 18
 	enc := json.NewEncoder(job.Stdout)
19 19
 	for v := range updates {
20 20
 		update := v.(*execdriver.ResourceStats)
21
-		ss := convertToAPITypes(update.ContainerStats)
21
+		ss := convertToAPITypes(update.Stats)
22 22
 		ss.MemoryStats.Limit = uint64(update.MemoryLimit)
23 23
 		ss.Read = update.Read
24 24
 		ss.CpuStats.SystemUsage = update.SystemUsage
... ...
@@ -31,20 +31,21 @@ func (daemon *Daemon) ContainerStats(job *engine.Job) engine.Status {
31 31
 	return engine.StatusOK
32 32
 }
33 33
 
34
-// convertToAPITypes converts the libcontainer.ContainerStats to the api specific
34
+// convertToAPITypes converts the libcontainer.Stats to the api specific
35 35
 // structs.  This is done to preserve API compatibility and versioning.
36
-func convertToAPITypes(ls *libcontainer.ContainerStats) *types.Stats {
36
+func convertToAPITypes(ls *libcontainer.Stats) *types.Stats {
37 37
 	s := &types.Stats{}
38
-	if ls.NetworkStats != nil {
39
-		s.Network = types.Network{
40
-			RxBytes:   ls.NetworkStats.RxBytes,
41
-			RxPackets: ls.NetworkStats.RxPackets,
42
-			RxErrors:  ls.NetworkStats.RxErrors,
43
-			RxDropped: ls.NetworkStats.RxDropped,
44
-			TxBytes:   ls.NetworkStats.TxBytes,
45
-			TxPackets: ls.NetworkStats.TxPackets,
46
-			TxErrors:  ls.NetworkStats.TxErrors,
47
-			TxDropped: ls.NetworkStats.TxDropped,
38
+	if ls.Interfaces != nil {
39
+		s.Network = types.Network{}
40
+		for _, iface := range ls.Interfaces {
41
+			s.Network.RxBytes += iface.RxBytes
42
+			s.Network.RxPackets += iface.RxPackets
43
+			s.Network.RxErrors += iface.RxErrors
44
+			s.Network.RxDropped += iface.RxDropped
45
+			s.Network.TxBytes += iface.TxBytes
46
+			s.Network.TxPackets += iface.TxPackets
47
+			s.Network.TxErrors += iface.TxErrors
48
+			s.Network.TxDropped += iface.TxDropped
48 49
 		}
49 50
 	}
50 51
 	cs := ls.CgroupStats
... ...
@@ -60,7 +60,7 @@ func TestExecInteractiveStdinClose(t *testing.T) {
60 60
 
61 61
 		out, err := cmd.CombinedOutput()
62 62
 		if err != nil {
63
-			t.Fatal(err, out)
63
+			t.Fatal(err, string(out))
64 64
 		}
65 65
 
66 66
 		if string(out) == "" {
... ...
@@ -538,7 +538,6 @@ func TestRunExecDir(t *testing.T) {
538 538
 	id := strings.TrimSpace(out)
539 539
 	execDir := filepath.Join(execDriverPath, id)
540 540
 	stateFile := filepath.Join(execDir, "state.json")
541
-	contFile := filepath.Join(execDir, "container.json")
542 541
 
543 542
 	{
544 543
 		fi, err := os.Stat(execDir)
... ...
@@ -552,10 +551,6 @@ func TestRunExecDir(t *testing.T) {
552 552
 		if err != nil {
553 553
 			t.Fatal(err)
554 554
 		}
555
-		fi, err = os.Stat(contFile)
556
-		if err != nil {
557
-			t.Fatal(err)
558
-		}
559 555
 	}
560 556
 
561 557
 	stopCmd := exec.Command(dockerBinary, "stop", id)
... ...
@@ -564,23 +559,12 @@ func TestRunExecDir(t *testing.T) {
564 564
 		t.Fatal(err, out)
565 565
 	}
566 566
 	{
567
-		fi, err := os.Stat(execDir)
568
-		if err != nil {
569
-			t.Fatal(err)
570
-		}
571
-		if !fi.IsDir() {
572
-			t.Fatalf("%q must be a directory", execDir)
573
-		}
574
-		fi, err = os.Stat(stateFile)
567
+		_, err := os.Stat(execDir)
575 568
 		if err == nil {
576
-			t.Fatalf("Statefile %q is exists for stopped container!", stateFile)
577
-		}
578
-		if !os.IsNotExist(err) {
579
-			t.Fatalf("Error should be about non-existing, got %s", err)
569
+			t.Fatal(err)
580 570
 		}
581
-		fi, err = os.Stat(contFile)
582 571
 		if err == nil {
583
-			t.Fatalf("Container file %q is exists for stopped container!", contFile)
572
+			t.Fatalf("Exec directory %q exists for removed container!", execDir)
584 573
 		}
585 574
 		if !os.IsNotExist(err) {
586 575
 			t.Fatalf("Error should be about non-existing, got %s", err)
... ...
@@ -603,10 +587,6 @@ func TestRunExecDir(t *testing.T) {
603 603
 		if err != nil {
604 604
 			t.Fatal(err)
605 605
 		}
606
-		fi, err = os.Stat(contFile)
607
-		if err != nil {
608
-			t.Fatal(err)
609
-		}
610 606
 	}
611 607
 	rmCmd := exec.Command(dockerBinary, "rm", "-f", id)
612 608
 	out, _, err = runCommandWithOutput(rmCmd)