SigChan chan os.Signal
ArvMountExit chan error
finalState string
- trashLifetime time.Duration
statLogger io.WriteCloser
statReporter *crunchstat.Reporter
if mnt.Writable {
return fmt.Errorf("Can never write to a collection specified by portable data hash")
}
+ idx := strings.Index(mnt.PortableDataHash, "/")
+ if idx > 0 {
+ mnt.Path = path.Clean(mnt.PortableDataHash[idx:])
+ mnt.PortableDataHash = mnt.PortableDataHash[0:idx]
+ runner.Container.Mounts[bind] = mnt
+ }
src = fmt.Sprintf("%s/by_id/%s", runner.ArvMountPoint, mnt.PortableDataHash)
+ if mnt.Path != "" && mnt.Path != "." {
+ if strings.HasPrefix(mnt.Path, "./") {
+ mnt.Path = mnt.Path[2:]
+ } else if strings.HasPrefix(mnt.Path, "/") {
+ mnt.Path = mnt.Path[1:]
+ }
+ src += "/" + mnt.Path
+ }
} else {
src = fmt.Sprintf("%s/tmp%d", runner.ArvMountPoint, tmpcount)
arvMountCmd = append(arvMountCmd, "--mount-tmp")
continue
}
- if strings.HasPrefix(bindSuffix, "/") == false {
- bindSuffix = "/" + bindSuffix
- }
-
if mnt.ExcludeFromOutput == true {
continue
}
- idx := strings.Index(mnt.PortableDataHash, "/")
- if idx > 0 {
- mnt.Path = mnt.PortableDataHash[idx:]
- mnt.PortableDataHash = mnt.PortableDataHash[0:idx]
- }
-
// append to manifest_text
m, err := runner.getCollectionManifestForPath(mnt, bindSuffix)
if err != nil {
// Save output
var response arvados.Collection
+ manifest := manifest.Manifest{Text: manifestText}
+ manifestText = manifest.Extract(".", ".").Text
err = runner.ArvClient.Create("collections",
arvadosclient.Dict{
"collection": arvadosclient.Dict{
- "trash_at": time.Now().Add(runner.trashLifetime).Format(time.RFC3339),
+ "is_trashed": true,
"name": "output for " + runner.Container.UUID,
"manifest_text": manifestText}},
&response)
return nil
}
+var outputCollections = make(map[string]arvados.Collection)
+
// Fetch the collection for the mnt.PortableDataHash
// Return the manifest_text fragment corresponding to the specified mnt.Path
// after making any required updates.
// "path":"/subdir1/subdir2"
// "path":"/subdir/filename" etc
func (runner *ContainerRunner) getCollectionManifestForPath(mnt arvados.Mount, bindSuffix string) (string, error) {
- var collection arvados.Collection
- err := runner.ArvClient.Get("collections", mnt.PortableDataHash, nil, &collection)
- if err != nil {
- return "", fmt.Errorf("While getting collection for %v: %v", mnt.PortableDataHash, err)
- }
-
- manifestText := ""
- if mnt.Path == "" || mnt.Path == "/" {
- // no path specified; return the entire manifest text after making adjustments
- manifestText = collection.ManifestText
- manifestText = strings.Replace(manifestText, "./", "."+bindSuffix+"/", -1)
- manifestText = strings.Replace(manifestText, ". ", "."+bindSuffix+" ", -1)
- } else {
- // either a single stream or file from a stream is being sought
- bindIdx := strings.LastIndex(bindSuffix, "/")
- var bindSubdir, bindFileName string
- if bindIdx >= 0 {
- bindSubdir = "." + bindSuffix[0:bindIdx]
- bindFileName = bindSuffix[bindIdx+1:]
- }
- mntPath := mnt.Path
- if strings.HasSuffix(mntPath, "/") {
- mntPath = mntPath[0 : len(mntPath)-1]
- }
- pathIdx := strings.LastIndex(mntPath, "/")
- var pathSubdir, pathFileName string
- if pathIdx >= 0 {
- pathSubdir = "." + mntPath[0:pathIdx]
- pathFileName = mntPath[pathIdx+1:]
- }
- streams := strings.Split(collection.ManifestText, "\n")
- for _, stream := range streams {
- tokens := strings.Split(stream, " ")
- if tokens[0] == "."+mntPath {
- // path refers to this complete stream
- adjustedStream := strings.Replace(stream, "."+mntPath, "."+bindSuffix, -1)
- manifestText = adjustedStream + "\n"
- break
- } else {
- // look for a matching file in this stream
- if tokens[0] == pathSubdir {
- // path refers to a file in this stream
- for _, token := range tokens {
- if strings.Index(token, ":"+pathFileName) > 0 {
- // found the file in the stream; discard all other file tokens
- for _, t := range tokens {
- if strings.Index(t, ":") == -1 {
- manifestText += (" " + t)
- } else {
- break // done reading all non-file tokens of this stream
- }
- }
- manifestText = strings.Trim(manifestText, " ")
- token = strings.Replace(token, ":"+pathFileName, ":"+bindFileName, -1)
- manifestText += (" " + token + "\n")
- manifestText = strings.Replace(manifestText, pathSubdir, bindSubdir, -1)
- break
- }
- }
- }
- }
+ collection := outputCollections[mnt.PortableDataHash]
+ if collection.PortableDataHash == "" {
+ err := runner.ArvClient.Get("collections", mnt.PortableDataHash, nil, &collection)
+ if err != nil {
+ return "", fmt.Errorf("While getting collection for %v: %v", mnt.PortableDataHash, err)
}
+ outputCollections[mnt.PortableDataHash] = collection
}
- return manifestText, nil
-}
+ if collection.ManifestText == "" {
+ runner.CrunchLog.Printf("No manifest text for collection %v", collection.PortableDataHash)
+ return "", nil
+ }
-func (runner *ContainerRunner) loadDiscoveryVars() {
- tl, err := runner.ArvClient.Discovery("defaultTrashLifetime")
- if err != nil {
- log.Fatalf("getting defaultTrashLifetime from discovery document: %s", err)
+ mft := manifest.Manifest{Text: collection.ManifestText}
+ extracted := mft.Extract(mnt.Path, bindSuffix)
+ if extracted.Err != nil {
+ return "", fmt.Errorf("Error parsing manifest for %v: %v", mnt.PortableDataHash, extracted.Err.Error())
}
- runner.trashLifetime = time.Duration(tl.(float64)) * time.Second
+ return extracted.Text, nil
}
func (runner *ContainerRunner) CleanupDirs() {
err = runner.ArvClient.Create("collections",
arvadosclient.Dict{
"collection": arvadosclient.Dict{
- "trash_at": time.Now().Add(runner.trashLifetime).Format(time.RFC3339),
+ "is_trashed": true,
"name": "logs for " + runner.Container.UUID,
"manifest_text": mt}},
&response)
cr.Container.UUID = containerUUID
cr.CrunchLog = NewThrottledLogger(cr.NewLogWriter("crunch-run"))
cr.CrunchLog.Immediate = log.New(os.Stderr, containerUUID+" ", 0)
- cr.loadDiscoveryVars()
return cr
}