12183: Update documentation.
authorPeter Amstutz <pamstutz@veritasgenetics.com>
Wed, 1 Nov 2017 21:10:20 +0000 (17:10 -0400)
committerPeter Amstutz <pamstutz@veritasgenetics.com>
Wed, 1 Nov 2017 21:10:20 +0000 (17:10 -0400)
Improve error message about follow symlink chains that are too long.

Arvados-DCO-1.1-Signed-off-by: Peter Amstutz <pamstutz@veritasgenetics.com>

doc/_includes/_mount_types.liquid
doc/api/methods/container_requests.html.textile.liquid
services/crunch-run/crunchrun.go

index 38770ea50a9e275864994ab2191baad4e01602d7..db1661a8e41d9735d1310400fc0c9fa1592de95e 100644 (file)
@@ -122,3 +122,7 @@ table(table table-bordered table-condensed).
 "output_path": "/tmp"
 </code></pre>|Specified path refers to the file *hello.txt* in the *alice* subdirectory|./*foo* 030326... 0:13:*bar*\n
 *Note:* Here the subdirectory *alice* is replaced with *foo* and the filename *hello.txt* from this subdirectory is replaced with *bar*.|
+
+h2(#symlinks-in-output). Symlinks in output
+
+When a container's output_path is a tmp mount backed by local disk, this output directory can contain symlinks to other files in the the output directory, or to collection mount points.  If the symlink leads to a collection mount, efficiently copy the collection into the output collection.  Symlinks leading to files or directories are expanded and created as regular files in the output collection.  Further, whether symlinks are relative or absolute, every symlink target (even targets that are symlinks themselves) must either remain in the output directory or point to a collection mount.
index 6c4d3cda7510e5e364c2055aaae31f8374964e61..7491fecc37614de1fe7ae3c70133654803abea70 100644 (file)
@@ -47,7 +47,7 @@ table(table table-bordered table-condensed).
 |environment|hash|Environment variables and values that should be set in the container environment (@docker run --env@). This augments and (when conflicts exist) overrides environment variables given in the image's Dockerfile.||
 |cwd|string|Initial working directory, given as an absolute path (in the container) or a path relative to the WORKDIR given in the image's Dockerfile.|Required.|
 |command|array of strings|Command to execute in the container.|Required. e.g., @["echo","hello"]@|
-|output_path|string|Path to a directory or file inside the container that should be preserved as container's output when it finishes. This path must be, or be inside, one of the mount targets. For best performance, point output_path to a writable collection mount. Also, see "Pre-populate output using Mount points":#pre-populate-output for details regarding optional output pre-population using mount points.|Required.|
+|output_path|string|Path to a directory or file inside the container that should be preserved as container's output when it finishes. This path must be one of the mount targets. For best performance, point output_path to a writable collection mount.  See "Pre-populate output using Mount points":#pre-populate-output for details regarding optional output pre-population using mount points and "Symlinks in output":#symlinks-in-output for additional details.|Required.|
 |output_name|string|Desired name for the output collection. If null, a name will be assigned automatically.||
 |output_ttl|integer|Desired lifetime for the output collection, in seconds. If zero, the output collection will not be deleted automatically.||
 |priority|integer|Higher value means spend more resources on this container_request, i.e., go ahead of other queued containers, bring up more nodes etc.|Priority 0 means a container should not be run on behalf of this request. Clients are expected to submit container requests with zero priority in order to preview the container that will be used to satisfy it. Priority can be null if and only if state!="Committed".|
index 56cee10de8e486a45fec7f7f1b288d873158e2a9..ca46bb0eaa14b81f41275de0afb9cfcf268f2a47 100644 (file)
@@ -920,7 +920,7 @@ func (runner *ContainerRunner) WaitFinish() (err error) {
        return nil
 }
 
-var NotInOutputDirError = fmt.Errorf("Must point to path within the output directory")
+var ErrNotInOutputDir = fmt.Errorf("Must point to path within the output directory")
 
 func (runner *ContainerRunner) derefOutputSymlink(path string, startinfo os.FileInfo) (tgt string, readlinktgt string, info os.FileInfo, err error) {
        // Follow symlinks if necessary
@@ -929,9 +929,9 @@ func (runner *ContainerRunner) derefOutputSymlink(path string, startinfo os.File
        readlinktgt = ""
        nextlink := path
        for followed := 0; info.Mode()&os.ModeSymlink != 0; followed++ {
-               if followed >= 16 {
+               if followed >= limitFollowSymlinks {
                        // Got stuck in a loop or just a pathological number of links, give up.
-                       err = fmt.Errorf("Followed too many symlinks from path %q", path)
+                       err = fmt.Errorf("Followed more than %v symlinks from path %q", limitFollowSymlinks, path)
                        return
                }
 
@@ -953,7 +953,7 @@ func (runner *ContainerRunner) derefOutputSymlink(path string, startinfo os.File
                        // After dereferencing, symlink target must either be
                        // within output directory, or must point to a
                        // collection mount.
-                       err = NotInOutputDirError
+                       err = ErrNotInOutputDir
                        return
                }
 
@@ -971,11 +971,14 @@ func (runner *ContainerRunner) derefOutputSymlink(path string, startinfo os.File
        return
 }
 
+var limitFollowSymlinks = 10
+
 // UploadFile uploads files within the output directory, with special handling
 // for symlinks. If the symlink leads to a keep mount, copy the manifest text
 // from the keep mount into the output manifestText.  Ensure that whether
-// symlinks are relative or absolute, they must remain within the output
-// directory.
+// symlinks are relative or absolute, every symlink target (even targets that
+// are symlinks themselves) must either remain in the output directory or point
+// to a collection mount.
 //
 // Assumes initial value of "path" is absolute, and located within runner.HostOutputDir.
 func (runner *ContainerRunner) UploadOutputFile(
@@ -996,10 +999,10 @@ func (runner *ContainerRunner) UploadOutputFile(
                return "", infoerr
        }
 
-       if followed >= 8 {
+       if followed >= limitFollowSymlinks {
                // Got stuck in a loop or just a pathological number of
                // directory links, give up.
-               err = fmt.Errorf("Followed too many symlinks from path %q", path)
+               err = fmt.Errorf("Followed more than %v symlinks from path %q", limitFollowSymlinks, path)
                return
        }