Browse code

LXC TEMPLATE WILL CREATE MOUNT

Lxc driver was throwing errors for mounts where the mount point does not exist in the container.
This adds a create=dir/file mount option to the lxc template, to alleviate this issue.

Docker-DCO-1.1-Signed-off-by: Abin Shahab <ashahab@altiscale.com> (github: ashahab-altiscale)

Abin Shahab authored on 2014/11/05 01:40:59
Showing 2 changed files
... ...
@@ -1,11 +1,11 @@
1 1
 package lxc
2 2
 
3 3
 import (
4
-	"strings"
5
-	"text/template"
6
-
7 4
 	"github.com/docker/docker/daemon/execdriver"
8 5
 	"github.com/docker/libcontainer/label"
6
+	"os"
7
+	"strings"
8
+	"text/template"
9 9
 )
10 10
 
11 11
 const LxcTemplate = `
... ...
@@ -70,10 +70,11 @@ lxc.mount.entry = devpts {{escapeFstabSpaces $ROOTFS}}/dev/pts devpts {{formatMo
70 70
 lxc.mount.entry = shm {{escapeFstabSpaces $ROOTFS}}/dev/shm tmpfs {{formatMountLabel "size=65536k,nosuid,nodev,noexec" ""}} 0 0
71 71
 
72 72
 {{range $value := .Mounts}}
73
+{{$createVal := isDirectory $value.Source}}
73 74
 {{if $value.Writable}}
74
-lxc.mount.entry = {{$value.Source}} {{escapeFstabSpaces $ROOTFS}}/{{escapeFstabSpaces $value.Destination}} none rbind,rw 0 0
75
+lxc.mount.entry = {{$value.Source}} {{escapeFstabSpaces $ROOTFS}}/{{escapeFstabSpaces $value.Destination}} none rbind,rw,create={{$createVal}} 0 0
75 76
 {{else}}
76
-lxc.mount.entry = {{$value.Source}} {{escapeFstabSpaces $ROOTFS}}/{{escapeFstabSpaces $value.Destination}} none rbind,ro 0 0
77
+lxc.mount.entry = {{$value.Source}} {{escapeFstabSpaces $ROOTFS}}/{{escapeFstabSpaces $value.Destination}} none rbind,ro,create={{$createVal}} 0 0
77 78
 {{end}}
78 79
 {{end}}
79 80
 
... ...
@@ -117,6 +118,20 @@ func escapeFstabSpaces(field string) string {
117 117
 	return strings.Replace(field, " ", "\\040", -1)
118 118
 }
119 119
 
120
+func isDirectory(source string) string {
121
+	f, err := os.Stat(source)
122
+	if err != nil {
123
+		if os.IsNotExist(err) {
124
+			return "dir"
125
+		}
126
+		return ""
127
+	}
128
+	if f.IsDir() {
129
+		return "dir"
130
+	}
131
+	return "file"
132
+}
133
+
120 134
 func getMemorySwap(v *execdriver.Resources) int64 {
121 135
 	// By default, MemorySwap is set to twice the size of RAM.
122 136
 	// If you want to omit MemorySwap, set it to `-1'.
... ...
@@ -143,6 +158,7 @@ func init() {
143 143
 		"getMemorySwap":     getMemorySwap,
144 144
 		"escapeFstabSpaces": escapeFstabSpaces,
145 145
 		"formatMountLabel":  label.FormatMountLabel,
146
+		"isDirectory":       isDirectory,
146 147
 	}
147 148
 	LxcTemplateCompiled, err = template.New("lxc").Funcs(funcMap).Parse(LxcTemplate)
148 149
 	if err != nil {
... ...
@@ -140,3 +140,91 @@ func TestEscapeFstabSpaces(t *testing.T) {
140 140
 		}
141 141
 	}
142 142
 }
143
+
144
+func TestIsDirectory(t *testing.T) {
145
+	tempDir, err := ioutil.TempDir("", "TestIsDir")
146
+	if err != nil {
147
+		t.Fatal(err)
148
+	}
149
+	defer os.RemoveAll(tempDir)
150
+
151
+	tempFile, err := ioutil.TempFile(tempDir, "TestIsDirFile")
152
+	if err != nil {
153
+		t.Fatal(err)
154
+	}
155
+
156
+	if isDirectory(tempDir) != "dir" {
157
+		t.Logf("Could not identify %s as a directory", tempDir)
158
+		t.Fail()
159
+	}
160
+
161
+	if isDirectory(tempFile.Name()) != "file" {
162
+		t.Logf("Could not identify %s as a file", tempFile.Name())
163
+		t.Fail()
164
+	}
165
+}
166
+
167
+func TestCustomLxcConfigMounts(t *testing.T) {
168
+	root, err := ioutil.TempDir("", "TestCustomLxcConfig")
169
+	if err != nil {
170
+		t.Fatal(err)
171
+	}
172
+	defer os.RemoveAll(root)
173
+	tempDir, err := ioutil.TempDir("", "TestIsDir")
174
+	if err != nil {
175
+		t.Fatal(err)
176
+	}
177
+	defer os.RemoveAll(tempDir)
178
+
179
+	tempFile, err := ioutil.TempFile(tempDir, "TestIsDirFile")
180
+	if err != nil {
181
+		t.Fatal(err)
182
+	}
183
+	os.MkdirAll(path.Join(root, "containers", "1"), 0777)
184
+
185
+	driver, err := NewDriver(root, "", false)
186
+	if err != nil {
187
+		t.Fatal(err)
188
+	}
189
+	processConfig := execdriver.ProcessConfig{
190
+		Privileged: false,
191
+	}
192
+	mounts := []execdriver.Mount{
193
+		{
194
+			Source:      tempDir,
195
+			Destination: tempDir,
196
+			Writable:    false,
197
+			Private:     true,
198
+		},
199
+		{
200
+			Source:      tempFile.Name(),
201
+			Destination: tempFile.Name(),
202
+			Writable:    true,
203
+			Private:     true,
204
+		},
205
+	}
206
+	command := &execdriver.Command{
207
+		ID: "1",
208
+		LxcConfig: []string{
209
+			"lxc.utsname = docker",
210
+			"lxc.cgroup.cpuset.cpus = 0,1",
211
+		},
212
+		Network: &execdriver.Network{
213
+			Mtu:       1500,
214
+			Interface: nil,
215
+		},
216
+		Mounts:        mounts,
217
+		ProcessConfig: processConfig,
218
+	}
219
+
220
+	p, err := driver.generateLXCConfig(command)
221
+	if err != nil {
222
+		t.Fatal(err)
223
+	}
224
+
225
+	grepFile(t, p, "lxc.utsname = docker")
226
+	grepFile(t, p, "lxc.cgroup.cpuset.cpus = 0,1")
227
+
228
+	grepFile(t, p, fmt.Sprintf("lxc.mount.entry = %s %s none rbind,ro,create=%s 0 0", tempDir, "/"+tempDir, "dir"))
229
+	grepFile(t, p, fmt.Sprintf("lxc.mount.entry = %s %s none rbind,rw,create=%s 0 0", tempFile.Name(), "/"+tempFile.Name(), "file"))
230
+}