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)
| ... | ... |
@@ -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 |
+} |