[ARVADOS] created: 2.1.0-920-g3d8ed2b76

Git user git at public.arvados.org
Mon Jun 14 14:15:37 UTC 2021


        at  3d8ed2b76b87033b4fed70e6b0998694c4326b8c (commit)


commit 3d8ed2b76b87033b4fed70e6b0998694c4326b8c
Author: Tom Clegg <tom at curii.com>
Date:   Mon Jun 14 09:22:32 2021 -0400

    17805: Access containers and container requests via sitefs (WIP).
    
    Arvados-DCO-1.1-Signed-off-by: Tom Clegg <tom at curii.com>

diff --git a/lib/mount/fs.go b/lib/mount/fs.go
index c008b96af..5d8b38688 100644
--- a/lib/mount/fs.go
+++ b/lib/mount/fs.go
@@ -271,6 +271,8 @@ func (fs *keepFS) fillStat(stat *fuse.Stat_t, fi os.FileInfo) {
 	var m uint32
 	if fi.IsDir() {
 		m = m | fuse.S_IFDIR
+	} else if fi.Mode()&os.ModeSymlink != 0 {
+		m = m | fuse.S_IFLNK
 	} else {
 		m = m | fuse.S_IFREG
 	}
@@ -315,6 +317,15 @@ func (fs *keepFS) Write(path string, buf []byte, ofst int64, fh uint64) (n int)
 	return n
 }
 
+func (fs *keepFS) Readlink(path string) (n int, target string) {
+	defer fs.debugPanics()
+	if target, err := fs.root.Readlink(path); err != nil {
+		return fs.errCode(err), ""
+	} else {
+		return 0, target
+	}
+}
+
 func (fs *keepFS) Read(path string, buf []byte, ofst int64, fh uint64) (n int) {
 	defer fs.debugPanics()
 	f := fs.lookupFH(fh)
diff --git a/sdk/go/arvados/container.go b/sdk/go/arvados/container.go
index f54263470..72acd63de 100644
--- a/sdk/go/arvados/container.go
+++ b/sdk/go/arvados/container.go
@@ -20,6 +20,7 @@ type Container struct {
 	Environment               map[string]string      `json:"environment"`
 	LockedByUUID              string                 `json:"locked_by_uuid"`
 	Mounts                    map[string]Mount       `json:"mounts"`
+	Log                       string                 `json:"log"`
 	Output                    string                 `json:"output"`
 	OutputPath                string                 `json:"output_path"`
 	Priority                  int64                  `json:"priority"`
diff --git a/sdk/go/arvados/fs_base.go b/sdk/go/arvados/fs_base.go
index 2478641df..d2de43819 100644
--- a/sdk/go/arvados/fs_base.go
+++ b/sdk/go/arvados/fs_base.go
@@ -93,6 +93,7 @@ type FileSystem interface {
 	Remove(name string) error
 	RemoveAll(name string) error
 	Rename(oldname, newname string) error
+	Readlink(name string) (string, error)
 
 	// Write buffered data from memory to storage, returning when
 	// all updates have been saved to persistent storage.
@@ -483,6 +484,21 @@ func (fs *fileSystem) Stat(name string) (os.FileInfo, error) {
 	return node.FileInfo(), nil
 }
 
+func (fs *fileSystem) Readlink(name string) (string, error) {
+	node, err := rlookup(fs.root, name)
+	if err != nil {
+		return "", err
+	}
+	if node.FileInfo().Mode()&os.ModeSymlink == 0 {
+		return "", ErrInvalidArgument
+	}
+	buf := make([]byte, int(node.FileInfo().Size()))
+	// FIXME: target/size could change here between calls to
+	// Size() and Read(), causing incorrect output
+	_, _, err = node.Read(buf, filenodePtr{})
+	return string(buf), err
+}
+
 func (fs *fileSystem) Rename(oldname, newname string) error {
 	olddir, oldname := path.Split(oldname)
 	if oldname == "" || oldname == "." || oldname == ".." {
diff --git a/sdk/go/arvados/fs_getternode.go b/sdk/go/arvados/fs_getternode.go
index 966fe9d5c..f28c5744b 100644
--- a/sdk/go/arvados/fs_getternode.go
+++ b/sdk/go/arvados/fs_getternode.go
@@ -51,8 +51,9 @@ func (gn *getternode) FileInfo() os.FileInfo {
 		size = gn.data.Size()
 	}
 	return fileinfo{
+		name:    gn.treenode.fileinfo.name,
 		modTime: time.Now(),
-		mode:    0444,
+		mode:    0444 | gn.treenode.fileinfo.mode,
 		size:    size,
 	}
 }
diff --git a/sdk/go/arvados/fs_lookup.go b/sdk/go/arvados/fs_lookup.go
index 021e8241c..bd9d70c5f 100644
--- a/sdk/go/arvados/fs_lookup.go
+++ b/sdk/go/arvados/fs_lookup.go
@@ -45,29 +45,37 @@ func (ln *lookupnode) Readdir() ([]os.FileInfo, error) {
 	defer ln.staleLock.Unlock()
 	checkTime := time.Now()
 	if ln.stale(ln.staleAll) {
-		all, err := ln.loadAll(ln)
+		ln.treenode.Lock()
+		err := ln.refreshAll(checkTime)
+		ln.treenode.Unlock()
 		if err != nil {
 			return nil, err
 		}
-		for _, child := range all {
-			ln.treenode.Lock()
-			_, err = ln.treenode.Child(child.FileInfo().Name(), func(inode) (inode, error) {
-				return child, nil
-			})
-			ln.treenode.Unlock()
-			if err != nil {
-				return nil, err
-			}
-		}
-		ln.staleAll = checkTime
-		// No value in ln.staleOne can make a difference to an
-		// "entry is stale?" test now, because no value is
-		// newer than ln.staleAll. Reclaim memory.
-		ln.staleOne = nil
 	}
 	return ln.treenode.Readdir()
 }
 
+func (ln *lookupnode) refreshAll(checkTime time.Time) error {
+	all, err := ln.loadAll(ln)
+	if err != nil {
+		return err
+	}
+	for _, child := range all {
+		_, err = ln.treenode.Child(child.FileInfo().Name(), func(inode) (inode, error) {
+			return child, nil
+		})
+		if err != nil {
+			return err
+		}
+	}
+	ln.staleAll = checkTime
+	// No value in ln.staleOne can make a difference to an
+	// "entry is stale?" test now, because no value is
+	// newer than ln.staleAll. Reclaim memory.
+	ln.staleOne = nil
+	return nil
+}
+
 // Child rejects (with ErrInvalidArgument) calls to add/replace
 // children, instead calling loadOne when a non-existing child is
 // looked up.
@@ -79,6 +87,10 @@ func (ln *lookupnode) Child(name string, replace func(inode) (inode, error)) (in
 	var err error
 	if ln.stale(ln.staleAll) && ln.stale(ln.staleOne[name]) {
 		existing, err = ln.treenode.Child(name, func(inode) (inode, error) {
+			if ln.loadOne == nil {
+				err = ln.refreshAll(checkTime)
+				return ln.treenode.inodes[name], err
+			}
 			return ln.loadOne(ln, name)
 		})
 		if err == nil && existing != nil {
diff --git a/sdk/go/arvados/fs_site.go b/sdk/go/arvados/fs_site.go
index 900893aa3..c68273741 100644
--- a/sdk/go/arvados/fs_site.go
+++ b/sdk/go/arvados/fs_site.go
@@ -5,6 +5,8 @@
 package arvados
 
 import (
+	"encoding/json"
+	"fmt"
 	"os"
 	"strings"
 	"sync"
@@ -135,6 +137,10 @@ func (fs *customFileSystem) mountByID(parent inode, id string) inode {
 		return fs.mountCollection(parent, id)
 	} else if strings.Contains(id, "-j7d0g-") {
 		return fs.newProjectNode(fs.root, id, id)
+	} else if strings.Contains(id, "-dz642-") {
+		return fs.mountContainer(fs.root, id)
+	} else if strings.Contains(id, "-xvhdp-") {
+		return fs.mountContainerRequest(fs.root, id)
 	} else {
 		return nil
 	}
@@ -155,6 +161,92 @@ func (fs *customFileSystem) mountCollection(parent inode, id string) inode {
 	return cfs
 }
 
+func (fs *customFileSystem) mountContainerRequest(parent inode, id string) inode {
+	return &lookupnode{
+		stale: fs.Stale,
+		loadAll: func(parent inode) ([]inode, error) {
+			var all []inode
+			var cr ContainerRequest
+			err := fs.RequestAndDecode(&cr, "GET", "arvados/v1/container_requests/"+id, nil, nil)
+			if err != nil {
+				return nil, err
+			}
+			jsondata, _ := json.MarshalIndent(cr, "", "  ")
+			jsondata = append(jsondata, '\n')
+			if cr.LogUUID != "" {
+				all = append(all, &getternode{Getter: func() ([]byte, error) { return []byte("../" + cr.LogUUID), nil }, treenode: treenode{fileinfo: fileinfo{name: "log", mode: os.ModeSymlink}}})
+			}
+			if cr.OutputUUID != "" {
+				all = append(all, &getternode{Getter: func() ([]byte, error) { return []byte("../" + cr.OutputUUID), nil }, treenode: treenode{fileinfo: fileinfo{name: "output", mode: os.ModeSymlink}}})
+			}
+			all = append(all,
+				&getternode{Getter: func() ([]byte, error) { return jsondata, nil }, treenode: treenode{fileinfo: fileinfo{name: "json"}}},
+				&getternode{Getter: func() ([]byte, error) { return []byte(cr.UUID + "\n"), nil }, treenode: treenode{fileinfo: fileinfo{name: "uuid"}}},
+				&getternode{Getter: func() ([]byte, error) { return []byte(cr.State + "\n"), nil }, treenode: treenode{fileinfo: fileinfo{name: "state"}}},
+				&getternode{Getter: func() ([]byte, error) { return []byte(cr.ContainerImage + "\n"), nil }, treenode: treenode{fileinfo: fileinfo{name: "container_image"}}},
+				&getternode{Getter: func() ([]byte, error) { return []byte("../" + cr.ContainerUUID), nil }, treenode: treenode{fileinfo: fileinfo{name: "container", mode: os.ModeSymlink}}},
+			)
+			if cr.RequestingContainerUUID != "" {
+				all = append(all, &getternode{Getter: func() ([]byte, error) { return []byte("../" + cr.RequestingContainerUUID), nil }, treenode: treenode{fileinfo: fileinfo{name: "requesting_container", mode: os.ModeSymlink}}})
+			}
+			return all, nil
+		},
+		treenode: treenode{
+			fs:     fs,
+			parent: parent,
+			inodes: make(map[string]inode),
+			fileinfo: fileinfo{
+				name:    id,
+				modTime: time.Now(),
+				mode:    0755 | os.ModeDir,
+			},
+		},
+	}
+}
+
+func (fs *customFileSystem) mountContainer(parent inode, id string) inode {
+	node := &lookupnode{
+		stale: fs.Stale,
+		loadAll: func(parent inode) ([]inode, error) {
+			var all []inode
+			var c Container
+			err := fs.RequestAndDecode(&c, "GET", "arvados/v1/containers/"+id, nil, nil)
+			if err != nil {
+				return nil, err
+			}
+			jsondata, _ := json.MarshalIndent(c, "", "  ")
+			jsondata = append(jsondata, '\n')
+			if c.Log != "" {
+				all = append(all, &getternode{Getter: func() ([]byte, error) { return []byte("../" + c.Log), nil }, treenode: treenode{fileinfo: fileinfo{name: "log", mode: os.ModeSymlink}}})
+			}
+			if c.Output != "" {
+				all = append(all, &getternode{Getter: func() ([]byte, error) { return []byte("../" + c.Output), nil }, treenode: treenode{fileinfo: fileinfo{name: "output", mode: os.ModeSymlink}}})
+			}
+			all = append(all,
+				&getternode{Getter: func() ([]byte, error) { return jsondata, nil }, treenode: treenode{fileinfo: fileinfo{name: "json"}}},
+				&getternode{Getter: func() ([]byte, error) { return []byte(c.UUID + "\n"), nil }, treenode: treenode{fileinfo: fileinfo{name: "uuid"}}},
+				&getternode{Getter: func() ([]byte, error) { return []byte(c.State + "\n"), nil }, treenode: treenode{fileinfo: fileinfo{name: "state"}}},
+				&getternode{Getter: func() ([]byte, error) { return []byte("../" + c.ContainerImage), nil }, treenode: treenode{fileinfo: fileinfo{name: "container_image", mode: os.ModeSymlink}}},
+				&getternode{Getter: func() ([]byte, error) { return []byte(c.GatewayAddress + "\n"), nil }, treenode: treenode{fileinfo: fileinfo{name: "gateway_address"}}},
+				&getternode{Getter: func() ([]byte, error) { return []byte(fmt.Sprintf("%d\n", c.ExitCode)), nil }, treenode: treenode{fileinfo: fileinfo{name: "exit_code"}}},
+				&getternode{Getter: func() ([]byte, error) { return []byte(fmt.Sprintf("%v\n", c.InteractiveSessionStarted)), nil }, treenode: treenode{fileinfo: fileinfo{name: "interactive_session_started"}}},
+			)
+			return all, nil
+		},
+		treenode: treenode{
+			fs:     fs,
+			parent: parent,
+			inodes: make(map[string]inode),
+			fileinfo: fileinfo{
+				name:    id,
+				modTime: time.Now(),
+				mode:    0755 | os.ModeDir,
+			},
+		},
+	}
+	return node
+}
+
 func (fs *customFileSystem) newProjectNode(root inode, name, uuid string) inode {
 	return &lookupnode{
 		stale:   fs.Stale,

-----------------------------------------------------------------------


hooks/post-receive
-- 




More information about the arvados-commits mailing list