handle symlinks for Docker's root dir & TMPDIR
This removes the incomplete symlink handling from engine.go and it adds it one place in docker.go. It also enables handling symlinks for TMPDIR. Docker-DCO-1.1-Signed-off-by: Cristian Staretu <cristian.staretu@gmail.com> (github: unclejack)
This commit is contained in:
parent
aac9542a68
commit
611acf7a7c
5 changed files with 127 additions and 20 deletions
|
@ -78,7 +78,27 @@ func main() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
eng, err := engine.New(*flRoot)
|
// set up the TempDir to use a canonical path
|
||||||
|
tmp := os.TempDir()
|
||||||
|
realTmp, err := utils.ReadSymlinkedDirectory(tmp)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Unable to get the full path to the TempDir (%s): %s", tmp, err)
|
||||||
|
}
|
||||||
|
os.Setenv("TMPDIR", realTmp)
|
||||||
|
|
||||||
|
// get the canonical path to the Docker root directory
|
||||||
|
root := *flRoot
|
||||||
|
var realRoot string
|
||||||
|
if _, err := os.Stat(root); err != nil && os.IsNotExist(err) {
|
||||||
|
realRoot = root
|
||||||
|
} else {
|
||||||
|
realRoot, err = utils.ReadSymlinkedDirectory(root)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Unable to get the full path to root (%s): %s", root, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
eng, err := engine.New(realRoot)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -91,7 +111,7 @@ func main() {
|
||||||
// Load plugin: httpapi
|
// Load plugin: httpapi
|
||||||
job := eng.Job("initserver")
|
job := eng.Job("initserver")
|
||||||
job.Setenv("Pidfile", *pidfile)
|
job.Setenv("Pidfile", *pidfile)
|
||||||
job.Setenv("Root", *flRoot)
|
job.Setenv("Root", realRoot)
|
||||||
job.SetenvBool("AutoRestart", *flAutoRestart)
|
job.SetenvBool("AutoRestart", *flAutoRestart)
|
||||||
job.SetenvList("Dns", flDns.GetAll())
|
job.SetenvList("Dns", flDns.GetAll())
|
||||||
job.SetenvBool("EnableIptables", *flEnableIptables)
|
job.SetenvBool("EnableIptables", *flEnableIptables)
|
||||||
|
|
|
@ -112,11 +112,15 @@ Using ``fd://`` will work perfectly for most setups but you can also specify ind
|
||||||
If the specified socket activated files aren't found then docker will exit.
|
If the specified socket activated files aren't found then docker will exit.
|
||||||
You can find examples of using systemd socket activation with docker and systemd in the `docker source tree <https://github.com/dotcloud/docker/blob/master/contrib/init/systemd/socket-activation/>`_.
|
You can find examples of using systemd socket activation with docker and systemd in the `docker source tree <https://github.com/dotcloud/docker/blob/master/contrib/init/systemd/socket-activation/>`_.
|
||||||
|
|
||||||
.. warning::
|
Docker supports softlinks for the Docker data directory (``/var/lib/docker``) and for ``/tmp``.
|
||||||
Docker and LXC do not support the use of softlinks for either the Docker data directory (``/var/lib/docker``) or for ``/tmp``.
|
TMPDIR and the data directory can be set like this:
|
||||||
If your system is likely to be set up in that way, you can use ``readlink -f`` to canonicalise the links:
|
|
||||||
|
|
||||||
``TMPDIR=$(readlink -f /tmp) /usr/local/bin/docker -d -D -g $(readlink -f /var/lib/docker) -H unix:// $EXPOSE_ALL > /var/lib/boot2docker/docker.log 2>&1``
|
::
|
||||||
|
|
||||||
|
TMPDIR=/mnt/disk2/tmp /usr/local/bin/docker -d -D -g /var/lib/docker -H unix:// > /var/lib/boot2docker/docker.log 2>&1
|
||||||
|
# or
|
||||||
|
export TMPDIR=/mnt/disk2/tmp
|
||||||
|
/usr/local/bin/docker -d -D -g /var/lib/docker -H unix:// > /var/lib/boot2docker/docker.log 2>&1
|
||||||
|
|
||||||
.. _cli_attach:
|
.. _cli_attach:
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,6 @@ import (
|
||||||
"io"
|
"io"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
|
||||||
"runtime"
|
"runtime"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
|
@ -90,19 +89,6 @@ func New(root string) (*Engine, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Docker makes some assumptions about the "absoluteness" of root
|
|
||||||
// ... so let's make sure it has no symlinks
|
|
||||||
if p, err := filepath.Abs(root); err != nil {
|
|
||||||
log.Fatalf("Unable to get absolute root (%s): %s", root, err)
|
|
||||||
} else {
|
|
||||||
root = p
|
|
||||||
}
|
|
||||||
if p, err := filepath.EvalSymlinks(root); err != nil {
|
|
||||||
log.Fatalf("Unable to canonicalize root (%s): %s", root, err)
|
|
||||||
} else {
|
|
||||||
root = p
|
|
||||||
}
|
|
||||||
|
|
||||||
eng := &Engine{
|
eng := &Engine{
|
||||||
root: root,
|
root: root,
|
||||||
handlers: make(map[string]Handler),
|
handlers: make(map[string]Handler),
|
||||||
|
|
|
@ -997,3 +997,24 @@ func ReplaceOrAppendEnvValues(defaults, overrides []string) []string {
|
||||||
}
|
}
|
||||||
return defaults
|
return defaults
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ReadSymlinkedDirectory returns the target directory of a symlink.
|
||||||
|
// The target of the symbolic link may not be a file.
|
||||||
|
func ReadSymlinkedDirectory(path string) (string, error) {
|
||||||
|
var realPath string
|
||||||
|
var err error
|
||||||
|
if realPath, err = filepath.Abs(path); err != nil {
|
||||||
|
return "", fmt.Errorf("unable to get absolute path for %s: %s", path, err)
|
||||||
|
}
|
||||||
|
if realPath, err = filepath.EvalSymlinks(realPath); err != nil {
|
||||||
|
return "", fmt.Errorf("failed to canonicalise path for %s: %s", path, err)
|
||||||
|
}
|
||||||
|
realPathInfo, err := os.Stat(realPath)
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("failed to stat target '%s' of '%s': %s", realPath, path, err)
|
||||||
|
}
|
||||||
|
if !realPathInfo.Mode().IsDir() {
|
||||||
|
return "", fmt.Errorf("canonical path points to a file '%s'", realPath)
|
||||||
|
}
|
||||||
|
return realPath, nil
|
||||||
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
@ -498,3 +499,78 @@ func TestReplaceAndAppendEnvVars(t *testing.T) {
|
||||||
t.Fatalf("expected TERM=xterm got '%s'", env[1])
|
t.Fatalf("expected TERM=xterm got '%s'", env[1])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Reading a symlink to a directory must return the directory
|
||||||
|
func TestReadSymlinkedDirectoryExistingDirectory(t *testing.T) {
|
||||||
|
var err error
|
||||||
|
if err = os.Mkdir("/tmp/testReadSymlinkToExistingDirectory", 0777); err != nil {
|
||||||
|
t.Errorf("failed to create directory: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = os.Symlink("/tmp/testReadSymlinkToExistingDirectory", "/tmp/dirLinkTest"); err != nil {
|
||||||
|
t.Errorf("failed to create symlink: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var path string
|
||||||
|
if path, err = ReadSymlinkedDirectory("/tmp/dirLinkTest"); err != nil {
|
||||||
|
t.Fatalf("failed to read symlink to directory: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if path != "/tmp/testReadSymlinkToExistingDirectory" {
|
||||||
|
t.Fatalf("symlink returned unexpected directory: %s", path)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = os.Remove("/tmp/testReadSymlinkToExistingDirectory"); err != nil {
|
||||||
|
t.Errorf("failed to remove temporary directory: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = os.Remove("/tmp/dirLinkTest"); err != nil {
|
||||||
|
t.Errorf("failed to remove symlink: %s", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reading a non-existing symlink must fail
|
||||||
|
func TestReadSymlinkedDirectoryNonExistingSymlink(t *testing.T) {
|
||||||
|
var path string
|
||||||
|
var err error
|
||||||
|
if path, err = ReadSymlinkedDirectory("/tmp/test/foo/Non/ExistingPath"); err == nil {
|
||||||
|
t.Fatalf("error expected for non-existing symlink")
|
||||||
|
}
|
||||||
|
|
||||||
|
if path != "" {
|
||||||
|
t.Fatalf("expected empty path, but '%s' was returned", path)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reading a symlink to a file must fail
|
||||||
|
func TestReadSymlinkedDirectoryToFile(t *testing.T) {
|
||||||
|
var err error
|
||||||
|
var file *os.File
|
||||||
|
|
||||||
|
if file, err = os.Create("/tmp/testReadSymlinkToFile"); err != nil {
|
||||||
|
t.Fatalf("failed to create file: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
file.Close()
|
||||||
|
|
||||||
|
if err = os.Symlink("/tmp/testReadSymlinkToFile", "/tmp/fileLinkTest"); err != nil {
|
||||||
|
t.Errorf("failed to create symlink: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var path string
|
||||||
|
if path, err = ReadSymlinkedDirectory("/tmp/fileLinkTest"); err == nil {
|
||||||
|
t.Fatalf("ReadSymlinkedDirectory on a symlink to a file should've failed")
|
||||||
|
}
|
||||||
|
|
||||||
|
if path != "" {
|
||||||
|
t.Fatalf("path should've been empty: %s", path)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = os.Remove("/tmp/testReadSymlinkToFile"); err != nil {
|
||||||
|
t.Errorf("failed to remove file: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = os.Remove("/tmp/fileLinkTest"); err != nil {
|
||||||
|
t.Errorf("failed to remove symlink: %s", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue