зеркало из https://github.com/microsoft/docker.git
Merge pull request #2445 from alexlarsson/fix-shared-root-from-dm
Fix lxc start for shared root filesystems
This commit is contained in:
Коммит
629c6e3649
27
container.go
27
container.go
|
@ -894,7 +894,13 @@ func (container *Container) Start() (err error) {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var lxcStart string = "lxc-start"
|
||||||
|
if container.hostConfig.Privileged && container.runtime.capabilities.AppArmor {
|
||||||
|
lxcStart = path.Join(container.runtime.config.Root, "lxc-start-unconfined")
|
||||||
|
}
|
||||||
|
|
||||||
params := []string{
|
params := []string{
|
||||||
|
lxcStart,
|
||||||
"-n", container.ID,
|
"-n", container.ID,
|
||||||
"-f", container.lxcConfigPath(),
|
"-f", container.lxcConfigPath(),
|
||||||
"--",
|
"--",
|
||||||
|
@ -987,11 +993,24 @@ func (container *Container) Start() (err error) {
|
||||||
params = append(params, "--", container.Path)
|
params = append(params, "--", container.Path)
|
||||||
params = append(params, container.Args...)
|
params = append(params, container.Args...)
|
||||||
|
|
||||||
var lxcStart string = "lxc-start"
|
if RootIsShared() {
|
||||||
if container.hostConfig.Privileged && container.runtime.capabilities.AppArmor {
|
// lxc-start really needs / to be non-shared, or all kinds of stuff break
|
||||||
lxcStart = path.Join(container.runtime.config.Root, "lxc-start-unconfined")
|
// when lxc-start unmount things and those unmounts propagate to the main
|
||||||
|
// mount namespace.
|
||||||
|
// What we really want is to clone into a new namespace and then
|
||||||
|
// mount / MS_REC|MS_SLAVE, but since we can't really clone or fork
|
||||||
|
// without exec in go we have to do this horrible shell hack...
|
||||||
|
shellString :=
|
||||||
|
"mount --make-rslave /; exec " +
|
||||||
|
utils.ShellQuoteArguments(params)
|
||||||
|
|
||||||
|
params = []string{
|
||||||
|
"unshare", "-m", "--", "/bin/sh", "-c", shellString,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
container.cmd = exec.Command(lxcStart, params...)
|
|
||||||
|
container.cmd = exec.Command(params[0], params[1:]...)
|
||||||
|
|
||||||
// Setup logging of stdout and stderr to disk
|
// Setup logging of stdout and stderr to disk
|
||||||
if err := container.runtime.LogToDisk(container.stdout, container.logPath("json"), "stdout"); err != nil {
|
if err := container.runtime.LogToDisk(container.stdout, container.logPath("json"), "stdout"); err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
15
utils.go
15
utils.go
|
@ -4,6 +4,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/dotcloud/docker/namesgenerator"
|
"github.com/dotcloud/docker/namesgenerator"
|
||||||
"github.com/dotcloud/docker/utils"
|
"github.com/dotcloud/docker/utils"
|
||||||
|
"io/ioutil"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
@ -310,6 +311,20 @@ func parseLink(rawLink string) (map[string]string, error) {
|
||||||
return utils.PartParser("name:alias", rawLink)
|
return utils.PartParser("name:alias", rawLink)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func RootIsShared() bool {
|
||||||
|
if data, err := ioutil.ReadFile("/proc/self/mountinfo"); err == nil {
|
||||||
|
for _, line := range strings.Split(string(data), "\n") {
|
||||||
|
cols := strings.Split(line, " ")
|
||||||
|
if len(cols) >= 6 && cols[4] == "/" {
|
||||||
|
return strings.HasPrefix(cols[6], "shared")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// No idea, probably safe to assume so
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
type checker struct {
|
type checker struct {
|
||||||
runtime *Runtime
|
runtime *Runtime
|
||||||
}
|
}
|
||||||
|
|
|
@ -1179,6 +1179,41 @@ func (e *StatusError) Error() string {
|
||||||
return fmt.Sprintf("Status: %d", e.Status)
|
return fmt.Sprintf("Status: %d", e.Status)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func quote(word string, buf *bytes.Buffer) {
|
||||||
|
// Bail out early for "simple" strings
|
||||||
|
if word != "" && !strings.ContainsAny(word, "\\'\"`${[|&;<>()~*?! \t\n") {
|
||||||
|
buf.WriteString(word)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
buf.WriteString("'")
|
||||||
|
|
||||||
|
for i := 0; i < len(word); i++ {
|
||||||
|
b := word[i]
|
||||||
|
if b == '\'' {
|
||||||
|
// Replace literal ' with a close ', a \', and a open '
|
||||||
|
buf.WriteString("'\\''")
|
||||||
|
} else {
|
||||||
|
buf.WriteByte(b)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
buf.WriteString("'")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Take a list of strings and escape them so they will be handled right
|
||||||
|
// when passed as arguments to an program via a shell
|
||||||
|
func ShellQuoteArguments(args []string) string {
|
||||||
|
var buf bytes.Buffer
|
||||||
|
for i, arg := range args {
|
||||||
|
if i != 0 {
|
||||||
|
buf.WriteByte(' ')
|
||||||
|
}
|
||||||
|
quote(arg, &buf)
|
||||||
|
}
|
||||||
|
return buf.String()
|
||||||
|
}
|
||||||
|
|
||||||
func IsClosedError(err error) bool {
|
func IsClosedError(err error) bool {
|
||||||
/* This comparison is ugly, but unfortunately, net.go doesn't export errClosing.
|
/* This comparison is ugly, but unfortunately, net.go doesn't export errClosing.
|
||||||
* See:
|
* See:
|
||||||
|
|
Загрузка…
Ссылка в новой задаче