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)
| ... | ... |
@@ -78,7 +78,27 @@ func main() {
|
| 78 | 78 |
return |
| 79 | 79 |
} |
| 80 | 80 |
|
| 81 |
- eng, err := engine.New(*flRoot) |
|
| 81 |
+ // set up the TempDir to use a canonical path |
|
| 82 |
+ tmp := os.TempDir() |
|
| 83 |
+ realTmp, err := utils.ReadSymlinkedDirectory(tmp) |
|
| 84 |
+ if err != nil {
|
|
| 85 |
+ log.Fatalf("Unable to get the full path to the TempDir (%s): %s", tmp, err)
|
|
| 86 |
+ } |
|
| 87 |
+ os.Setenv("TMPDIR", realTmp)
|
|
| 88 |
+ |
|
| 89 |
+ // get the canonical path to the Docker root directory |
|
| 90 |
+ root := *flRoot |
|
| 91 |
+ var realRoot string |
|
| 92 |
+ if _, err := os.Stat(root); err != nil && os.IsNotExist(err) {
|
|
| 93 |
+ realRoot = root |
|
| 94 |
+ } else {
|
|
| 95 |
+ realRoot, err = utils.ReadSymlinkedDirectory(root) |
|
| 96 |
+ if err != nil {
|
|
| 97 |
+ log.Fatalf("Unable to get the full path to root (%s): %s", root, err)
|
|
| 98 |
+ } |
|
| 99 |
+ } |
|
| 100 |
+ |
|
| 101 |
+ eng, err := engine.New(realRoot) |
|
| 82 | 102 |
if err != nil {
|
| 83 | 103 |
log.Fatal(err) |
| 84 | 104 |
} |
| ... | ... |
@@ -91,7 +111,7 @@ func main() {
|
| 91 | 91 |
// Load plugin: httpapi |
| 92 | 92 |
job := eng.Job("initserver")
|
| 93 | 93 |
job.Setenv("Pidfile", *pidfile)
|
| 94 |
- job.Setenv("Root", *flRoot)
|
|
| 94 |
+ job.Setenv("Root", realRoot)
|
|
| 95 | 95 |
job.SetenvBool("AutoRestart", *flAutoRestart)
|
| 96 | 96 |
job.SetenvList("Dns", flDns.GetAll())
|
| 97 | 97 |
job.SetenvBool("EnableIptables", *flEnableIptables)
|
| ... | ... |
@@ -112,11 +112,15 @@ Using ``fd://`` will work perfectly for most setups but you can also specify ind |
| 112 | 112 |
If the specified socket activated files aren't found then docker will exit. |
| 113 | 113 |
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/>`_. |
| 114 | 114 |
|
| 115 |
-.. warning:: |
|
| 116 |
- Docker and LXC do not support the use of softlinks for either the Docker data directory (``/var/lib/docker``) or for ``/tmp``. |
|
| 117 |
- If your system is likely to be set up in that way, you can use ``readlink -f`` to canonicalise the links: |
|
| 115 |
+Docker supports softlinks for the Docker data directory (``/var/lib/docker``) and for ``/tmp``. |
|
| 116 |
+TMPDIR and the data directory can be set like this: |
|
| 118 | 117 |
|
| 119 |
- ``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`` |
|
| 118 |
+:: |
|
| 119 |
+ |
|
| 120 |
+ TMPDIR=/mnt/disk2/tmp /usr/local/bin/docker -d -D -g /var/lib/docker -H unix:// > /var/lib/boot2docker/docker.log 2>&1 |
|
| 121 |
+ # or |
|
| 122 |
+ export TMPDIR=/mnt/disk2/tmp |
|
| 123 |
+ /usr/local/bin/docker -d -D -g /var/lib/docker -H unix:// > /var/lib/boot2docker/docker.log 2>&1 |
|
| 120 | 124 |
|
| 121 | 125 |
.. _cli_attach: |
| 122 | 126 |
|
| ... | ... |
@@ -7,7 +7,6 @@ import ( |
| 7 | 7 |
"io" |
| 8 | 8 |
"log" |
| 9 | 9 |
"os" |
| 10 |
- "path/filepath" |
|
| 11 | 10 |
"runtime" |
| 12 | 11 |
"sort" |
| 13 | 12 |
"strings" |
| ... | ... |
@@ -90,19 +89,6 @@ func New(root string) (*Engine, error) {
|
| 90 | 90 |
return nil, err |
| 91 | 91 |
} |
| 92 | 92 |
|
| 93 |
- // Docker makes some assumptions about the "absoluteness" of root |
|
| 94 |
- // ... so let's make sure it has no symlinks |
|
| 95 |
- if p, err := filepath.Abs(root); err != nil {
|
|
| 96 |
- log.Fatalf("Unable to get absolute root (%s): %s", root, err)
|
|
| 97 |
- } else {
|
|
| 98 |
- root = p |
|
| 99 |
- } |
|
| 100 |
- if p, err := filepath.EvalSymlinks(root); err != nil {
|
|
| 101 |
- log.Fatalf("Unable to canonicalize root (%s): %s", root, err)
|
|
| 102 |
- } else {
|
|
| 103 |
- root = p |
|
| 104 |
- } |
|
| 105 |
- |
|
| 106 | 93 |
eng := &Engine{
|
| 107 | 94 |
root: root, |
| 108 | 95 |
handlers: make(map[string]Handler), |
| ... | ... |
@@ -997,3 +997,24 @@ func ReplaceOrAppendEnvValues(defaults, overrides []string) []string {
|
| 997 | 997 |
} |
| 998 | 998 |
return defaults |
| 999 | 999 |
} |
| 1000 |
+ |
|
| 1001 |
+// ReadSymlinkedDirectory returns the target directory of a symlink. |
|
| 1002 |
+// The target of the symbolic link may not be a file. |
|
| 1003 |
+func ReadSymlinkedDirectory(path string) (string, error) {
|
|
| 1004 |
+ var realPath string |
|
| 1005 |
+ var err error |
|
| 1006 |
+ if realPath, err = filepath.Abs(path); err != nil {
|
|
| 1007 |
+ return "", fmt.Errorf("unable to get absolute path for %s: %s", path, err)
|
|
| 1008 |
+ } |
|
| 1009 |
+ if realPath, err = filepath.EvalSymlinks(realPath); err != nil {
|
|
| 1010 |
+ return "", fmt.Errorf("failed to canonicalise path for %s: %s", path, err)
|
|
| 1011 |
+ } |
|
| 1012 |
+ realPathInfo, err := os.Stat(realPath) |
|
| 1013 |
+ if err != nil {
|
|
| 1014 |
+ return "", fmt.Errorf("failed to stat target '%s' of '%s': %s", realPath, path, err)
|
|
| 1015 |
+ } |
|
| 1016 |
+ if !realPathInfo.Mode().IsDir() {
|
|
| 1017 |
+ return "", fmt.Errorf("canonical path points to a file '%s'", realPath)
|
|
| 1018 |
+ } |
|
| 1019 |
+ return realPath, nil |
|
| 1020 |
+} |
| ... | ... |
@@ -5,6 +5,7 @@ import ( |
| 5 | 5 |
"errors" |
| 6 | 6 |
"io" |
| 7 | 7 |
"io/ioutil" |
| 8 |
+ "os" |
|
| 8 | 9 |
"strings" |
| 9 | 10 |
"testing" |
| 10 | 11 |
) |
| ... | ... |
@@ -498,3 +499,78 @@ func TestReplaceAndAppendEnvVars(t *testing.T) {
|
| 498 | 498 |
t.Fatalf("expected TERM=xterm got '%s'", env[1])
|
| 499 | 499 |
} |
| 500 | 500 |
} |
| 501 |
+ |
|
| 502 |
+// Reading a symlink to a directory must return the directory |
|
| 503 |
+func TestReadSymlinkedDirectoryExistingDirectory(t *testing.T) {
|
|
| 504 |
+ var err error |
|
| 505 |
+ if err = os.Mkdir("/tmp/testReadSymlinkToExistingDirectory", 0777); err != nil {
|
|
| 506 |
+ t.Errorf("failed to create directory: %s", err)
|
|
| 507 |
+ } |
|
| 508 |
+ |
|
| 509 |
+ if err = os.Symlink("/tmp/testReadSymlinkToExistingDirectory", "/tmp/dirLinkTest"); err != nil {
|
|
| 510 |
+ t.Errorf("failed to create symlink: %s", err)
|
|
| 511 |
+ } |
|
| 512 |
+ |
|
| 513 |
+ var path string |
|
| 514 |
+ if path, err = ReadSymlinkedDirectory("/tmp/dirLinkTest"); err != nil {
|
|
| 515 |
+ t.Fatalf("failed to read symlink to directory: %s", err)
|
|
| 516 |
+ } |
|
| 517 |
+ |
|
| 518 |
+ if path != "/tmp/testReadSymlinkToExistingDirectory" {
|
|
| 519 |
+ t.Fatalf("symlink returned unexpected directory: %s", path)
|
|
| 520 |
+ } |
|
| 521 |
+ |
|
| 522 |
+ if err = os.Remove("/tmp/testReadSymlinkToExistingDirectory"); err != nil {
|
|
| 523 |
+ t.Errorf("failed to remove temporary directory: %s", err)
|
|
| 524 |
+ } |
|
| 525 |
+ |
|
| 526 |
+ if err = os.Remove("/tmp/dirLinkTest"); err != nil {
|
|
| 527 |
+ t.Errorf("failed to remove symlink: %s", err)
|
|
| 528 |
+ } |
|
| 529 |
+} |
|
| 530 |
+ |
|
| 531 |
+// Reading a non-existing symlink must fail |
|
| 532 |
+func TestReadSymlinkedDirectoryNonExistingSymlink(t *testing.T) {
|
|
| 533 |
+ var path string |
|
| 534 |
+ var err error |
|
| 535 |
+ if path, err = ReadSymlinkedDirectory("/tmp/test/foo/Non/ExistingPath"); err == nil {
|
|
| 536 |
+ t.Fatalf("error expected for non-existing symlink")
|
|
| 537 |
+ } |
|
| 538 |
+ |
|
| 539 |
+ if path != "" {
|
|
| 540 |
+ t.Fatalf("expected empty path, but '%s' was returned", path)
|
|
| 541 |
+ } |
|
| 542 |
+} |
|
| 543 |
+ |
|
| 544 |
+// Reading a symlink to a file must fail |
|
| 545 |
+func TestReadSymlinkedDirectoryToFile(t *testing.T) {
|
|
| 546 |
+ var err error |
|
| 547 |
+ var file *os.File |
|
| 548 |
+ |
|
| 549 |
+ if file, err = os.Create("/tmp/testReadSymlinkToFile"); err != nil {
|
|
| 550 |
+ t.Fatalf("failed to create file: %s", err)
|
|
| 551 |
+ } |
|
| 552 |
+ |
|
| 553 |
+ file.Close() |
|
| 554 |
+ |
|
| 555 |
+ if err = os.Symlink("/tmp/testReadSymlinkToFile", "/tmp/fileLinkTest"); err != nil {
|
|
| 556 |
+ t.Errorf("failed to create symlink: %s", err)
|
|
| 557 |
+ } |
|
| 558 |
+ |
|
| 559 |
+ var path string |
|
| 560 |
+ if path, err = ReadSymlinkedDirectory("/tmp/fileLinkTest"); err == nil {
|
|
| 561 |
+ t.Fatalf("ReadSymlinkedDirectory on a symlink to a file should've failed")
|
|
| 562 |
+ } |
|
| 563 |
+ |
|
| 564 |
+ if path != "" {
|
|
| 565 |
+ t.Fatalf("path should've been empty: %s", path)
|
|
| 566 |
+ } |
|
| 567 |
+ |
|
| 568 |
+ if err = os.Remove("/tmp/testReadSymlinkToFile"); err != nil {
|
|
| 569 |
+ t.Errorf("failed to remove file: %s", err)
|
|
| 570 |
+ } |
|
| 571 |
+ |
|
| 572 |
+ if err = os.Remove("/tmp/fileLinkTest"); err != nil {
|
|
| 573 |
+ t.Errorf("failed to remove symlink: %s", err)
|
|
| 574 |
+ } |
|
| 575 |
+} |