Browse code

Update runc/libcontainer to v0.0.6

Signed-off-by: Mrunal Patel <mrunalp@gmail.com>

Mrunal Patel authored on 2015/12/12 05:18:39
Showing 20 changed files
... ...
@@ -16,6 +16,7 @@ import (
16 16
 
17 17
 	"github.com/Sirupsen/logrus"
18 18
 	"github.com/docker/docker/daemon/execdriver"
19
+	"github.com/docker/docker/daemon/execdriver/native/template"
19 20
 	"github.com/docker/docker/pkg/parsers"
20 21
 	"github.com/docker/docker/pkg/pools"
21 22
 	"github.com/docker/docker/pkg/reexec"
... ...
@@ -89,6 +90,7 @@ func NewDriver(root string, options []string) (*Driver, error) {
89 89
 			case "systemd":
90 90
 				if systemd.UseSystemd() {
91 91
 					cgm = libcontainer.SystemdCgroups
92
+					template.SystemdCgroups = true
92 93
 				} else {
93 94
 					// warn them that they chose the wrong driver
94 95
 					logrus.Warn("You cannot use systemd as native.cgroupdriver, using cgroupfs instead")
... ...
@@ -9,6 +9,9 @@ import (
9 9
 
10 10
 const defaultMountFlags = syscall.MS_NOEXEC | syscall.MS_NOSUID | syscall.MS_NODEV
11 11
 
12
+// SystemdCgroups indicates whether systemd cgroup implemenation is in use or not
13
+var SystemdCgroups = false
14
+
12 15
 // New returns the docker default configuration for libcontainer
13 16
 func New() *configs.Config {
14 17
 	container := &configs.Config{
... ...
@@ -94,5 +97,10 @@ func New() *configs.Config {
94 94
 		container.AppArmorProfile = "docker-default"
95 95
 	}
96 96
 
97
+	if SystemdCgroups {
98
+		container.Cgroups.Parent = "system.slice"
99
+		container.Cgroups.ScopePrefix = "docker"
100
+	}
101
+
97 102
 	return container
98 103
 }
... ...
@@ -49,7 +49,7 @@ clone git github.com/miekg/pkcs11 80f102b5cac759de406949c47f0928b99bd64cdf
49 49
 clone git github.com/jfrazelle/go v1.5.1-1
50 50
 clone git github.com/agl/ed25519 d2b94fd789ea21d12fac1a4443dd3a3f79cda72c
51 51
 
52
-clone git github.com/opencontainers/runc v0.0.5 # libcontainer
52
+clone git github.com/opencontainers/runc v0.0.6 # libcontainer
53 53
 clone git github.com/opencontainers/specs 46d949ea81080c5f60dfb72ee91468b1e9fb2998 # specs
54 54
 clone git github.com/seccomp/libseccomp-golang 1b506fc7c24eec5a3693cdcbed40d9c226cfc6a1
55 55
 # libcontainer deps (see src/github.com/opencontainers/runc/Godeps/Godeps.json)
... ...
@@ -2,10 +2,19 @@
2 2
 
3 3
 package apparmor
4 4
 
5
+import (
6
+	"errors"
7
+)
8
+
9
+var ErrApparmorNotEnabled = errors.New("apparmor: config provided but apparmor not supported")
10
+
5 11
 func IsEnabled() bool {
6 12
 	return false
7 13
 }
8 14
 
9 15
 func ApplyProfile(name string) error {
16
+	if name != "" {
17
+		return ErrApparmorNotEnabled
18
+	}
10 19
 	return nil
11 20
 }
... ...
@@ -167,8 +167,8 @@ func (m *Manager) Apply(pid int) error {
167 167
 		properties []systemdDbus.Property
168 168
 	)
169 169
 
170
-	if c.Slice != "" {
171
-		slice = c.Slice
170
+	if c.Parent != "" {
171
+		slice = c.Parent
172 172
 	}
173 173
 
174 174
 	properties = append(properties,
... ...
@@ -406,8 +406,8 @@ func getSubsystemPath(c *configs.Cgroup, subsystem string) (string, error) {
406 406
 	}
407 407
 
408 408
 	slice := "system.slice"
409
-	if c.Slice != "" {
410
-		slice = c.Slice
409
+	if c.Parent != "" {
410
+		slice = c.Parent
411 411
 	}
412 412
 
413 413
 	return filepath.Join(mountpoint, initPath, slice, getUnitName(c)), nil
... ...
@@ -472,7 +472,7 @@ func (m *Manager) Set(container *configs.Config) error {
472 472
 }
473 473
 
474 474
 func getUnitName(c *configs.Cgroup) string {
475
-	return fmt.Sprintf("%s-%s.scope", c.Parent, c.Name)
475
+	return fmt.Sprintf("%s-%s.scope", c.ScopePrefix, c.Name)
476 476
 }
477 477
 
478 478
 // Atm we can't use the systemd device support because of two missing things:
... ...
@@ -83,8 +83,8 @@ type Cgroup struct {
83 83
 	// Hugetlb limit (in bytes)
84 84
 	HugetlbLimit []*HugepageLimit `json:"hugetlb_limit"`
85 85
 
86
-	// Parent slice to use for systemd TODO: remove in favor or parent
87
-	Slice string `json:"slice"`
86
+	// ScopePrefix decribes prefix for the scope name
87
+	ScopePrefix string `json:"scope_prefix"`
88 88
 
89 89
 	// Whether to disable OOM Killer
90 90
 	OomKillDisable bool `json:"oom_kill_disable"`
91 91
new file mode 100644
... ...
@@ -0,0 +1,6 @@
0
+// +build !windows,!linux,!freebsd
1
+
2
+package configs
3
+
4
+type Cgroup struct {
5
+}
... ...
@@ -6,8 +6,8 @@ import (
6 6
 	"errors"
7 7
 )
8 8
 
9
-// newConsole returns an initalized console that can be used within a container by copying bytes
9
+// NewConsole returns an initalized console that can be used within a container by copying bytes
10 10
 // from the master side to the slave that is attached as the tty for the container's init process.
11
-func newConsole(uid, gid int) (Console, error) {
11
+func NewConsole(uid, gid int) (Console, error) {
12 12
 	return nil, errors.New("libcontainer console is not supported on FreeBSD")
13 13
 }
... ...
@@ -10,9 +10,9 @@ import (
10 10
 	"github.com/opencontainers/runc/libcontainer/label"
11 11
 )
12 12
 
13
-// newConsole returns an initalized console that can be used within a container by copying bytes
13
+// NewConsole returns an initalized console that can be used within a container by copying bytes
14 14
 // from the master side to the slave that is attached as the tty for the container's init process.
15
-func newConsole(uid, gid int) (Console, error) {
15
+func NewConsole(uid, gid int) (Console, error) {
16 16
 	master, err := os.OpenFile("/dev/ptmx", syscall.O_RDWR|syscall.O_NOCTTY|syscall.O_CLOEXEC, 0)
17 17
 	if err != nil {
18 18
 		return nil, err
... ...
@@ -1,7 +1,7 @@
1 1
 package libcontainer
2 2
 
3
-// newConsole returns an initalized console that can be used within a container
4
-func newConsole(uid, gid int) (Console, error) {
3
+// NewConsole returns an initalized console that can be used within a container
4
+func NewConsole(uid, gid int) (Console, error) {
5 5
 	return &windowsConsole{}, nil
6 6
 }
7 7
 
... ...
@@ -3,8 +3,10 @@
3 3
 package libcontainer
4 4
 
5 5
 import (
6
+	"bytes"
6 7
 	"encoding/json"
7 8
 	"fmt"
9
+	"io"
8 10
 	"io/ioutil"
9 11
 	"os"
10 12
 	"os/exec"
... ...
@@ -19,6 +21,7 @@ import (
19 19
 	"github.com/opencontainers/runc/libcontainer/cgroups"
20 20
 	"github.com/opencontainers/runc/libcontainer/configs"
21 21
 	"github.com/opencontainers/runc/libcontainer/criurpc"
22
+	"github.com/vishvananda/netlink/nl"
22 23
 )
23 24
 
24 25
 const stdioFdCount = 3
... ...
@@ -218,7 +221,7 @@ func (c *linuxContainer) newParentProcess(p *Process, doInit bool) (parentProces
218 218
 		return nil, newSystemError(err)
219 219
 	}
220 220
 	if !doInit {
221
-		return c.newSetnsProcess(p, cmd, parentPipe, childPipe), nil
221
+		return c.newSetnsProcess(p, cmd, parentPipe, childPipe)
222 222
 	}
223 223
 	return c.newInitProcess(p, cmd, parentPipe, childPipe)
224 224
 }
... ...
@@ -273,23 +276,24 @@ func (c *linuxContainer) newInitProcess(p *Process, cmd *exec.Cmd, parentPipe, c
273 273
 	}, nil
274 274
 }
275 275
 
276
-func (c *linuxContainer) newSetnsProcess(p *Process, cmd *exec.Cmd, parentPipe, childPipe *os.File) *setnsProcess {
277
-	cmd.Env = append(cmd.Env,
278
-		fmt.Sprintf("_LIBCONTAINER_INITPID=%d", c.initProcess.pid()),
279
-		"_LIBCONTAINER_INITTYPE=setns",
280
-	)
281
-	if p.consolePath != "" {
282
-		cmd.Env = append(cmd.Env, "_LIBCONTAINER_CONSOLE_PATH="+p.consolePath)
276
+func (c *linuxContainer) newSetnsProcess(p *Process, cmd *exec.Cmd, parentPipe, childPipe *os.File) (*setnsProcess, error) {
277
+	cmd.Env = append(cmd.Env, "_LIBCONTAINER_INITTYPE=setns")
278
+	// for setns process, we dont have to set cloneflags as the process namespaces
279
+	// will only be set via setns syscall
280
+	data, err := c.bootstrapData(0, c.initProcess.pid(), p.consolePath)
281
+	if err != nil {
282
+		return nil, err
283 283
 	}
284 284
 	// TODO: set on container for process management
285 285
 	return &setnsProcess{
286
-		cmd:         cmd,
287
-		cgroupPaths: c.cgroupManager.GetPaths(),
288
-		childPipe:   childPipe,
289
-		parentPipe:  parentPipe,
290
-		config:      c.newInitConfig(p),
291
-		process:     p,
292
-	}
286
+		cmd:           cmd,
287
+		cgroupPaths:   c.cgroupManager.GetPaths(),
288
+		childPipe:     childPipe,
289
+		parentPipe:    parentPipe,
290
+		config:        c.newInitConfig(p),
291
+		process:       p,
292
+		bootstrapData: data,
293
+	}, nil
293 294
 }
294 295
 
295 296
 func (c *linuxContainer) newInitConfig(process *Process) *initConfig {
... ...
@@ -1021,3 +1025,25 @@ func (c *linuxContainer) currentState() (*State, error) {
1021 1021
 	}
1022 1022
 	return state, nil
1023 1023
 }
1024
+
1025
+// bootstrapData encodes the necessary data in netlink binary format as a io.Reader.
1026
+// Consumer can write the data to a bootstrap program such as one that uses
1027
+// nsenter package to bootstrap the container's init process correctly, i.e. with
1028
+// correct namespaces, uid/gid mapping etc.
1029
+func (c *linuxContainer) bootstrapData(cloneFlags uintptr, pid int, consolePath string) (io.Reader, error) {
1030
+	// create the netlink message
1031
+	r := nl.NewNetlinkRequest(int(InitMsg), 0)
1032
+	// write pid
1033
+	r.AddData(&Int32msg{
1034
+		Type:  PidAttr,
1035
+		Value: uint32(pid),
1036
+	})
1037
+	// write console path
1038
+	if consolePath != "" {
1039
+		r.AddData(&Bytemsg{
1040
+			Type:  ConsolePathAttr,
1041
+			Value: []byte(consolePath),
1042
+		})
1043
+	}
1044
+	return bytes.NewReader(r.Serialize()), nil
1045
+}
... ...
@@ -22,6 +22,7 @@ const (
22 22
 
23 23
 	// Common errors
24 24
 	ConfigInvalid
25
+	ConsoleExists
25 26
 	SystemError
26 27
 )
27 28
 
... ...
@@ -43,6 +44,8 @@ func (c ErrorCode) String() string {
43 43
 		return "Container is not stopped"
44 44
 	case ContainerNotRunning:
45 45
 		return "Container is not running"
46
+	case ConsoleExists:
47
+		return "Console exists for process"
46 48
 	default:
47 49
 		return "Unknown error"
48 50
 	}
49 51
new file mode 100644
... ...
@@ -0,0 +1,60 @@
0
+// +build linux
1
+
2
+package libcontainer
3
+
4
+import (
5
+	"syscall"
6
+
7
+	"github.com/vishvananda/netlink/nl"
8
+)
9
+
10
+// list of known message types we want to send to bootstrap program
11
+// The number is randomly chosen to not conflict with known netlink types
12
+const (
13
+	InitMsg         uint16 = 62000
14
+	PidAttr         uint16 = 27281
15
+	ConsolePathAttr uint16 = 27282
16
+)
17
+
18
+type Int32msg struct {
19
+	Type  uint16
20
+	Value uint32
21
+}
22
+
23
+// int32msg has the following representation
24
+// | nlattr len | nlattr type |
25
+// | uint32 value             |
26
+func (msg *Int32msg) Serialize() []byte {
27
+	buf := make([]byte, msg.Len())
28
+	native := nl.NativeEndian()
29
+	native.PutUint16(buf[0:2], uint16(msg.Len()))
30
+	native.PutUint16(buf[2:4], msg.Type)
31
+	native.PutUint32(buf[4:8], msg.Value)
32
+	return buf
33
+}
34
+
35
+func (msg *Int32msg) Len() int {
36
+	return syscall.NLA_HDRLEN + 4
37
+}
38
+
39
+// bytemsg has the following representation
40
+// | nlattr len | nlattr type |
41
+// | value              | pad |
42
+type Bytemsg struct {
43
+	Type  uint16
44
+	Value []byte
45
+}
46
+
47
+func (msg *Bytemsg) Serialize() []byte {
48
+	l := msg.Len()
49
+	buf := make([]byte, (l+syscall.NLA_ALIGNTO-1) & ^(syscall.NLA_ALIGNTO-1))
50
+	native := nl.NativeEndian()
51
+	native.PutUint16(buf[0:2], uint16(l))
52
+	native.PutUint16(buf[2:4], msg.Type)
53
+	copy(buf[4:], msg.Value)
54
+	return buf
55
+}
56
+
57
+func (msg *Bytemsg) Len() int {
58
+	return syscall.NLA_HDRLEN + len(msg.Value) + 1 // null-terminated
59
+}
... ...
@@ -93,7 +93,7 @@ func (l *loopback) create(n *network, nspid int) error {
93 93
 }
94 94
 
95 95
 func (l *loopback) initialize(config *network) error {
96
-	return netlink.LinkSetUp(&netlink.Device{netlink.LinkAttrs{Name: "lo"}})
96
+	return netlink.LinkSetUp(&netlink.Device{LinkAttrs: netlink.LinkAttrs{Name: "lo"}})
97 97
 }
98 98
 
99 99
 func (l *loopback) attach(n *configs.Network) (err error) {
... ...
@@ -111,7 +111,7 @@ type veth struct {
111 111
 }
112 112
 
113 113
 func (v *veth) detach(n *configs.Network) (err error) {
114
-	return netlink.LinkSetMaster(&netlink.Device{netlink.LinkAttrs{Name: n.HostInterfaceName}}, nil)
114
+	return netlink.LinkSetMaster(&netlink.Device{LinkAttrs: netlink.LinkAttrs{Name: n.HostInterfaceName}}, nil)
115 115
 }
116 116
 
117 117
 // attach a container network interface to an external network
... ...
@@ -17,6 +17,11 @@
17 17
 #include <sched.h>
18 18
 #include <signal.h>
19 19
 
20
+#include <linux/netlink.h>
21
+#include <linux/types.h>
22
+#include <stdint.h>
23
+#include <sys/socket.h>
24
+
20 25
 /* All arguments should be above stack, because it grows down */
21 26
 struct clone_arg {
22 27
 	/*
... ...
@@ -63,24 +68,33 @@ static int clone_parent(jmp_buf * env)
63 63
 	return child;
64 64
 }
65 65
 
66
+static uint32_t readint32(char *buf)
67
+{
68
+	return *(uint32_t *) buf;
69
+}
70
+
71
+// list of known message types we want to send to bootstrap program
72
+// These are defined in libcontainer/message_linux.go
73
+#define INIT_MSG 62000
74
+#define PID_ATTR 27281
75
+#define CONSOLE_PATH_ATTR 27282
76
+
66 77
 void nsexec()
67 78
 {
68 79
 	char *namespaces[] = { "ipc", "uts", "net", "pid", "mnt", "user" };
69 80
 	const int num = sizeof(namespaces) / sizeof(char *);
70 81
 	jmp_buf env;
71 82
 	char buf[PATH_MAX], *val;
72
-	int i, tfd, self_tfd, child, len, pipenum, consolefd = -1;
73
-	pid_t pid;
74
-	char *console;
83
+	int i, tfd, self_tfd, child, n, len, pipenum, consolefd = -1;
84
+	pid_t pid = 0;
75 85
 
76
-	val = getenv("_LIBCONTAINER_INITPID");
77
-	if (val == NULL)
86
+	// if we dont have INITTYPE or this is the init process, skip the bootstrap process
87
+	val = getenv("_LIBCONTAINER_INITTYPE");
88
+	if (val == NULL || strcmp(val, "standard") == 0) {
78 89
 		return;
79
-
80
-	pid = atoi(val);
81
-	snprintf(buf, sizeof(buf), "%d", pid);
82
-	if (strcmp(val, buf)) {
83
-		pr_perror("Unable to parse _LIBCONTAINER_INITPID");
90
+	}
91
+	if (strcmp(val, "setns") != 0) {
92
+		pr_perror("Invalid inittype %s", val);
84 93
 		exit(1);
85 94
 	}
86 95
 
... ...
@@ -89,7 +103,6 @@ void nsexec()
89 89
 		pr_perror("Child pipe not found");
90 90
 		exit(1);
91 91
 	}
92
-
93 92
 	pipenum = atoi(val);
94 93
 	snprintf(buf, sizeof(buf), "%d", pipenum);
95 94
 	if (strcmp(val, buf)) {
... ...
@@ -97,13 +110,56 @@ void nsexec()
97 97
 		exit(1);
98 98
 	}
99 99
 
100
-	console = getenv("_LIBCONTAINER_CONSOLE_PATH");
101
-	if (console != NULL) {
102
-		consolefd = open(console, O_RDWR);
103
-		if (consolefd < 0) {
104
-			pr_perror("Failed to open console %s", console);
105
-			exit(1);
100
+	char nlbuf[NLMSG_HDRLEN];
101
+	struct nlmsghdr *nh;
102
+	if ((n = read(pipenum, nlbuf, NLMSG_HDRLEN)) != NLMSG_HDRLEN) {
103
+		pr_perror("Failed to read netlink header, got %d", n);
104
+		exit(1);
105
+	}
106
+
107
+	nh = (struct nlmsghdr *)nlbuf;
108
+	if (nh->nlmsg_type == NLMSG_ERROR) {
109
+		pr_perror("Invalid netlink header message");
110
+		exit(1);
111
+	}
112
+	if (nh->nlmsg_type != INIT_MSG) {
113
+		pr_perror("Unexpected netlink message type %d", nh->nlmsg_type);
114
+		exit(1);
115
+	}
116
+	// read the netlink payload
117
+	len = NLMSG_PAYLOAD(nh, 0);
118
+	char data[len];
119
+	if ((n = read(pipenum, data, len)) != len) {
120
+		pr_perror("Failed to read netlink payload, got %d", n);
121
+		exit(1);
122
+	}
123
+
124
+	int start = 0;
125
+	struct nlattr *attr;
126
+	while (start < len) {
127
+		int payload_len;
128
+		attr = (struct nlattr *)((void *)data + start);
129
+		start += NLA_HDRLEN;
130
+		payload_len = attr->nla_len - NLA_HDRLEN;
131
+		switch (attr->nla_type) {
132
+		case PID_ATTR:
133
+			pid = (pid_t) readint32(data + start);
134
+			break;
135
+		case CONSOLE_PATH_ATTR:
136
+			consolefd = open((char *)data + start, O_RDWR);
137
+			if (consolefd < 0) {
138
+				pr_perror("Failed to open console %s", (char *)data + start);
139
+				exit(1);
140
+			}
141
+			break;
106 142
 		}
143
+		start += NLA_ALIGN(payload_len);
144
+	}
145
+
146
+	// required pid to be passed
147
+	if (pid == 0) {
148
+		pr_perror("missing pid");
149
+		exit(1);
107 150
 	}
108 151
 
109 152
 	/* Check that the specified process exists */
... ...
@@ -133,15 +189,13 @@ void nsexec()
133 133
 		}
134 134
 
135 135
 		/* Skip namespaces we're already part of */
136
-		if (fstatat(self_tfd, namespaces[i], &self_st, 0) != -1 &&
137
-		    st.st_ino == self_st.st_ino) {
136
+		if (fstatat(self_tfd, namespaces[i], &self_st, 0) != -1 && st.st_ino == self_st.st_ino) {
138 137
 			continue;
139 138
 		}
140 139
 
141 140
 		fd = openat(tfd, namespaces[i], O_RDONLY);
142 141
 		if (fd == -1) {
143
-			pr_perror("Failed to open ns file %s for ns %s", buf,
144
-				  namespaces[i]);
142
+			pr_perror("Failed to open ns file %s for ns %s", buf, namespaces[i]);
145 143
 			exit(1);
146 144
 		}
147 145
 		// Set the namespace.
... ...
@@ -80,10 +80,19 @@ func (p Process) Signal(sig os.Signal) error {
80 80
 
81 81
 // NewConsole creates new console for process and returns it
82 82
 func (p *Process) NewConsole(rootuid int) (Console, error) {
83
-	console, err := newConsole(rootuid, rootuid)
83
+	console, err := NewConsole(rootuid, rootuid)
84 84
 	if err != nil {
85 85
 		return nil, err
86 86
 	}
87 87
 	p.consolePath = console.Path()
88 88
 	return console, nil
89 89
 }
90
+
91
+// ConsoleFromPath sets the process's console with the path provided
92
+func (p *Process) ConsoleFromPath(path string) error {
93
+	if p.consolePath != "" {
94
+		return newGenericError(fmt.Errorf("console path already exists for process"), ConsoleExists)
95
+	}
96
+	p.consolePath = path
97
+	return nil
98
+}
... ...
@@ -41,13 +41,14 @@ type parentProcess interface {
41 41
 }
42 42
 
43 43
 type setnsProcess struct {
44
-	cmd         *exec.Cmd
45
-	parentPipe  *os.File
46
-	childPipe   *os.File
47
-	cgroupPaths map[string]string
48
-	config      *initConfig
49
-	fds         []string
50
-	process     *Process
44
+	cmd           *exec.Cmd
45
+	parentPipe    *os.File
46
+	childPipe     *os.File
47
+	cgroupPaths   map[string]string
48
+	config        *initConfig
49
+	fds           []string
50
+	process       *Process
51
+	bootstrapData io.Reader
51 52
 }
52 53
 
53 54
 func (p *setnsProcess) startTime() (string, error) {
... ...
@@ -64,6 +65,16 @@ func (p *setnsProcess) signal(sig os.Signal) error {
64 64
 
65 65
 func (p *setnsProcess) start() (err error) {
66 66
 	defer p.parentPipe.Close()
67
+	err = p.cmd.Start()
68
+	p.childPipe.Close()
69
+	if err != nil {
70
+		return newSystemError(err)
71
+	}
72
+	if p.bootstrapData != nil {
73
+		if _, err := io.Copy(p.parentPipe, p.bootstrapData); err != nil {
74
+			return newSystemError(err)
75
+		}
76
+	}
67 77
 	if err = p.execSetns(); err != nil {
68 78
 		return newSystemError(err)
69 79
 	}
... ...
@@ -96,11 +107,6 @@ func (p *setnsProcess) start() (err error) {
96 96
 // before the go runtime boots, we wait on the process to die and receive the child's pid
97 97
 // over the provided pipe.
98 98
 func (p *setnsProcess) execSetns() error {
99
-	err := p.cmd.Start()
100
-	p.childPipe.Close()
101
-	if err != nil {
102
-		return newSystemError(err)
103
-	}
104 99
 	status, err := p.cmd.Process.Wait()
105 100
 	if err != nil {
106 101
 		p.cmd.Wait()
... ...
@@ -17,3 +17,4 @@ script:
17 17
   - go vet -x ./...
18 18
   - $HOME/gopath/bin/golint ./...
19 19
   - $HOME/gopath/bin/git-validation -run DCO,short-subject -v -range ${TRAVIS_COMMIT_RANGE}
20
+  
... ...
@@ -10,7 +10,7 @@ Topics listed in the roadmap do not mean that they will be implemented or added
10 10
 
11 11
 ### Digest and Hashing
12 12
 
13
-A bundle is designed to be moved between hosts.
13
+A bundle is designed to be moved between hosts. 
14 14
 Although OCI doesn't define a transport method we should have a cryptographic digest of the on-disk bundle that can be used to verify that a bundle is not corrupted and in an expected configuration.
15 15
 
16 16
 *Owner:* philips
... ...
@@ -20,11 +20,11 @@ Although OCI doesn't define a transport method we should have a cryptographic di
20 20
 There are some discussions about having `runtime.json` being optional for containers and specifying defaults.
21 21
 Runtimes would use this standard set of defaults for containers and `runtime.json` would provide overrides for fine tuning of these extra host or platform specific settings.
22 22
 
23
-*Owner:*
23
+*Owner:*  
24 24
 
25 25
 ### Define Container Lifecycle
26 26
 
27
-Containers have a lifecycle and being able to identify and document the lifecycle of a container is very helpful for implementations of the spec.
27
+Containers have a lifecycle and being able to identify and document the lifecycle of a container is very helpful for implementations of the spec.  
28 28
 The lifecycle events of a container also help identify areas to implement hooks that are portable across various implementations and platforms.
29 29
 
30 30
 *Owner:* mrunalp
... ...
@@ -33,27 +33,27 @@ The lifecycle events of a container also help identify areas to implement hooks
33 33
 
34 34
 Define what type of actions a runtime can perform on a container without imposing hardships on authors of platforms that do not support advanced options.
35 35
 
36
-*Owner:*
36
+*Owner:*  
37 37
 
38 38
 ### Clarify rootfs requirement in base spec
39 39
 
40 40
 Is the rootfs needed or should it just be expected in the bundle without having a field in the spec?
41 41
 
42
-*Owner:*
42
+*Owner:*  
43 43
 
44 44
 ### Container Definition
45 45
 
46 46
 Define what a software container is and its attributes in a cross platform way.
47 47
 
48
-*Owner:*
48
+*Owner:*  
49 49
 
50 50
 ### Live Container Updates
51 51
 
52
-Should we allow dynamic container updates to runtime options?
52
+Should we allow dynamic container updates to runtime options? 
53 53
 
54 54
 *Owner:* vishh
55 55
 
56
-### Protobuf Config
56
+### Protobuf Config 
57 57
 
58 58
 We currently have only one language binding for the spec and that is Go.
59 59
 If we change the specs format in the respository to be something like protobuf then the generation for multiple language bindings become effortless.
... ...
@@ -62,7 +62,7 @@ If we change the specs format in the respository to be something like protobuf t
62 62
 
63 63
 ### Validation Tooling
64 64
 
65
-Provide validation tooling for compliance with OCI spec and runtime environment.
65
+Provide validation tooling for compliance with OCI spec and runtime environment. 
66 66
 
67 67
 *Owner:* mrunalp
68 68
 
... ...
@@ -70,27 +70,27 @@ Provide validation tooling for compliance with OCI spec and runtime environment.
70 70
 
71 71
 Decide on a robust versioning schema for the spec as it evolves.
72 72
 
73
-*Owner:*
73
+*Owner:*  
74 74
 
75 75
 ### Printable/Compiled Spec
76 76
 
77 77
 Reguardless of how the spec is written, ensure that it is easy to read and follow for first time users.
78 78
 
79
-*Owner:* vbatts
79
+*Owner:* vbatts 
80 80
 
81 81
 ### Base Config Compatibility
82 82
 
83 83
 Ensure that the base configuration format is viable for various platforms.
84 84
 
85
-Systems:
85
+Systems: 
86 86
 
87 87
 * Solaris
88
-* Windows
88
+* Windows 
89 89
 * Linux
90 90
 
91
-*Owner:*
91
+*Owner:* 
92 92
 
93 93
 ### Full Lifecycle Hooks
94 94
 Ensure that we have lifecycle hooks in the correct places with full coverage over the container lifecycle.
95 95
 
96
-*Owner:*
96
+*Owner:*  
... ...
@@ -30,7 +30,7 @@ The OpenContainers team reserves the right to deny participation any individual
30 30
 Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct.
31 31
 By adopting this Code of Conduct, project maintainers commit themselves to fairly and consistently applying these principles to every aspect of managing this project.
32 32
 
33
-## Thanks
33
+## Thanks 
34 34
 
35 35
 Thanks to the [Fedora Code of Conduct](https://getfedora.org/code-of-conduct) and [Contributor Covenant](http://contributor-covenant.org) for inspiration and ideas.
36 36