Merge pull request #1500 from justincormack/mount-overrides

Allow overriding the default mount options
This commit is contained in:
Justin Cormack 2017-04-05 15:13:06 +01:00 committed by GitHub
commit bc1dd84337

View File

@ -6,7 +6,10 @@ import (
"encoding/json" "encoding/json"
"errors" "errors"
"fmt" "fmt"
"os"
"path" "path"
"path/filepath"
"sort"
"strings" "strings"
log "github.com/Sirupsen/logrus" log "github.com/Sirupsen/logrus"
@ -92,6 +95,39 @@ func ConfigToOCI(image *MobyImage) ([]byte, error) {
return ConfigInspectToOCI(image, inspect) return ConfigInspectToOCI(image, inspect)
} }
func defaultMountpoint(tp string) string {
switch tp {
case "proc":
return "/proc"
case "devpts":
return "/dev/pts"
case "sysfs":
return "/sys"
case "cgroup":
return "/sys/fs/cgroup"
case "mqueue":
return "/dev/mqueue"
default:
return ""
}
}
// Sort mounts by number of path components so /dev/pts is listed after /dev
type mlist []specs.Mount
func (m mlist) Len() int {
return len(m)
}
func (m mlist) Less(i, j int) bool {
return m.parts(i) < m.parts(j)
}
func (m mlist) Swap(i, j int) {
m[i], m[j] = m[j], m[i]
}
func (m mlist) parts(i int) int {
return strings.Count(filepath.Clean(m[i].Destination), string(os.PathSeparator))
}
// ConfigInspectToOCI converts a config and the output of image inspect to an OCI config file // ConfigInspectToOCI converts a config and the output of image inspect to an OCI config file
func ConfigInspectToOCI(image *MobyImage, inspect types.ImageInspect) ([]byte, error) { func ConfigInspectToOCI(image *MobyImage, inspect types.ImageInspect) ([]byte, error) {
oci := specs.Spec{} oci := specs.Spec{}
@ -116,6 +152,7 @@ func ConfigInspectToOCI(image *MobyImage, inspect types.ImageInspect) ([]byte, e
if cwd == "" { if cwd == "" {
cwd = "/" cwd = "/"
} }
// default options match what Docker does
procOptions := []string{"nosuid", "nodev", "noexec", "relatime"} procOptions := []string{"nosuid", "nodev", "noexec", "relatime"}
devOptions := []string{"nosuid", "strictatime", "mode=755", "size=65536k"} devOptions := []string{"nosuid", "strictatime", "mode=755", "size=65536k"}
if image.Readonly { if image.Readonly {
@ -128,15 +165,13 @@ func ConfigInspectToOCI(image *MobyImage, inspect types.ImageInspect) ([]byte, e
} }
cgroupOptions := []string{"nosuid", "noexec", "nodev", "relatime", "ro"} cgroupOptions := []string{"nosuid", "noexec", "nodev", "relatime", "ro"}
// note omits "standard" /dev/shm and /dev/mqueue // note omits "standard" /dev/shm and /dev/mqueue
mounts := []specs.Mount{ mounts := map[string]specs.Mount{
{Destination: "/proc", Type: "proc", Source: "proc", Options: procOptions}, "/proc": {Destination: "/proc", Type: "proc", Source: "proc", Options: procOptions},
{Destination: "/dev", Type: "tmpfs", Source: "tmpfs", Options: devOptions}, "/dev": {Destination: "/dev", Type: "tmpfs", Source: "tmpfs", Options: devOptions},
{Destination: "/dev/pts", Type: "devpts", Source: "devpts", Options: ptsOptions}, "/dev/pts": {Destination: "/dev/pts", Type: "devpts", Source: "devpts", Options: ptsOptions},
{Destination: "/sys", Type: "sysfs", Source: "sysfs", Options: sysOptions}, "/sys": {Destination: "/sys", Type: "sysfs", Source: "sysfs", Options: sysOptions},
{Destination: "/sys/fs/cgroup", Type: "cgroup", Source: "cgroup", Options: cgroupOptions}, "/sys/fs/cgroup": {Destination: "/sys/fs/cgroup", Type: "cgroup", Source: "cgroup", Options: cgroupOptions},
} }
// TODO if any standard mount points supplied, remove from above, so can change options
mounts = append(mounts, image.Mounts...)
for _, t := range image.Tmpfs { for _, t := range image.Tmpfs {
parts := strings.Split(t, ":") parts := strings.Split(t, ":")
if len(parts) > 2 { if len(parts) > 2 {
@ -147,7 +182,7 @@ func ConfigInspectToOCI(image *MobyImage, inspect types.ImageInspect) ([]byte, e
if len(parts) == 2 { if len(parts) == 2 {
opts = strings.Split(parts[2], ",") opts = strings.Split(parts[2], ",")
} }
mounts = append(mounts, specs.Mount{Destination: dest, Type: "tmpfs", Source: "tmpfs", Options: opts}) mounts[dest] = specs.Mount{Destination: dest, Type: "tmpfs", Source: "tmpfs", Options: opts}
} }
for _, b := range image.Binds { for _, b := range image.Binds {
parts := strings.Split(b, ":") parts := strings.Split(b, ":")
@ -163,9 +198,42 @@ func ConfigInspectToOCI(image *MobyImage, inspect types.ImageInspect) ([]byte, e
if len(parts) == 3 { if len(parts) == 3 {
opts = strings.Split(parts[2], ",") opts = strings.Split(parts[2], ",")
} }
mounts = append(mounts, specs.Mount{Destination: dest, Type: "bind", Source: src, Options: opts}) mounts[dest] = specs.Mount{Destination: dest, Type: "bind", Source: src, Options: opts}
} }
for _, m := range image.Mounts {
tp := m.Type
src := m.Source
dest := m.Destination
opts := m.Options
if tp == "" {
switch src {
case "mqueue", "devpts", "proc", "sysfs", "cgroup":
tp = src
}
}
if tp == "" && dest == "/dev" {
tp = "tmpfs"
}
if tp == "" {
return []byte{}, fmt.Errorf("Mount for destination %s is missing type", dest)
}
if src == "" {
// usually sane, eg proc, tmpfs etc
src = tp
}
if dest == "" {
dest = defaultMountpoint(tp)
}
if dest == "" {
return []byte{}, fmt.Errorf("Mount type %s is missing destination", tp)
}
mounts[dest] = specs.Mount{Destination: dest, Type: tp, Source: src, Options: opts}
}
mountList := mlist{}
for _, m := range mounts {
mountList = append(mountList, m)
}
sort.Sort(mountList)
namespaces := []specs.LinuxNamespace{} namespaces := []specs.LinuxNamespace{}
if image.Net != "" && image.Net != "host" { if image.Net != "" && image.Net != "host" {
return []byte{}, fmt.Errorf("invalid net namespace: %s", image.Net) return []byte{}, fmt.Errorf("invalid net namespace: %s", image.Net)
@ -275,7 +343,7 @@ func ConfigInspectToOCI(image *MobyImage, inspect types.ImageInspect) ([]byte, e
} }
oci.Hostname = image.Hostname oci.Hostname = image.Hostname
oci.Mounts = mounts oci.Mounts = mountList
oci.Linux = &specs.Linux{ oci.Linux = &specs.Linux{
// UIDMappings // UIDMappings