diff --git a/client/alloc_runner.go b/client/alloc_runner.go index 71de749c7..606ec8877 100644 --- a/client/alloc_runner.go +++ b/client/alloc_runner.go @@ -424,3 +424,7 @@ func (r *AllocRunner) Destroy() { func (r *AllocRunner) WaitCh() <-chan struct{} { return r.waitCh } + +func (r *AllocRunner) FSList(path string) ([]*allocdir.AllocFile, error) { + return r.ctx.AllocDir.FSList(path) +} diff --git a/client/allocdir/alloc_dir.go b/client/allocdir/alloc_dir.go index 7fe318a6b..4add2434d 100644 --- a/client/allocdir/alloc_dir.go +++ b/client/allocdir/alloc_dir.go @@ -38,6 +38,11 @@ type AllocDir struct { mounted []string } +type AllocFile struct { + Name string + IsDir bool +} + func NewAllocDir(allocDir string) *AllocDir { d := &AllocDir{AllocDir: allocDir, TaskDirs: make(map[string]string)} d.SharedDir = filepath.Join(d.AllocDir, SharedAllocName) @@ -217,6 +222,22 @@ func (d *AllocDir) MountSharedDir(task string) error { return nil } +func (d *AllocDir) FSList(path string) ([]*AllocFile, error) { + p := filepath.Join(d.AllocDir, path) + finfos, err := ioutil.ReadDir(p) + if err != nil { + return []*AllocFile{}, nil + } + files := make([]*AllocFile, len(finfos)) + for idx, info := range finfos { + files[idx] = &AllocFile{ + Name: info.Name(), + IsDir: info.IsDir(), + } + } + return files, err +} + func fileCopy(src, dst string, perm os.FileMode) error { // Do a simple copy. srcFile, err := os.Open(src) diff --git a/client/client.go b/client/client.go index 61b317127..20c7b1f7c 100644 --- a/client/client.go +++ b/client/client.go @@ -12,6 +12,7 @@ import ( "time" "github.com/hashicorp/go-multierror" + "github.com/hashicorp/nomad/client/allocdir" "github.com/hashicorp/nomad/client/config" "github.com/hashicorp/nomad/client/driver" "github.com/hashicorp/nomad/client/fingerprint" @@ -353,6 +354,15 @@ func (c *Client) Node() *structs.Node { return c.config.Node } +func (c *Client) FSList(allocID string, path string) ([]*allocdir.AllocFile, error) { + ar, ok := c.allocs[allocID] + if !ok { + return nil, fmt.Errorf("alloc not present") + } + + return ar.FSList(path) +} + // restoreState is used to restore our state from the data dir func (c *Client) restoreState() error { if c.config.DevMode { diff --git a/command/agent/fs_endpoint.go b/command/agent/fs_endpoint.go new file mode 100644 index 000000000..46540997a --- /dev/null +++ b/command/agent/fs_endpoint.go @@ -0,0 +1,32 @@ +package agent + +import ( + "fmt" + "net/http" + "strings" +) + +func (s *HTTPServer) DirectoryListRequest(resp http.ResponseWriter, req *http.Request) (interface{}, error) { + allocID := strings.TrimPrefix(req.URL.Path, "/v1/client/fs/ls/") + path := req.URL.Query().Get("path") + if path == "" { + path = "/" + } + if allocID == "" { + resp.WriteHeader(http.StatusNotFound) + return nil, fmt.Errorf("alloc id not found") + } + files, err := s.agent.client.FSList(allocID, path) + if err != nil { + return nil, err + } + return files, nil +} + +func (s *HTTPServer) FileStatRequest(resp http.ResponseWriter, req *http.Request) (interface{}, error) { + return nil, nil +} + +func (s *HTTPServer) FileReadAtRequest(resp http.ResponseWriter, req *http.Request) (interface{}, error) { + return nil, nil +} diff --git a/command/agent/http.go b/command/agent/http.go index 4c46ee8b4..ca5b20104 100644 --- a/command/agent/http.go +++ b/command/agent/http.go @@ -103,6 +103,10 @@ func (s *HTTPServer) registerHandlers(enableDebug bool) { s.mux.HandleFunc("/v1/evaluations", s.wrap(s.EvalsRequest)) s.mux.HandleFunc("/v1/evaluation/", s.wrap(s.EvalSpecificRequest)) + s.mux.HandleFunc("/v1/client/fs/ls/", s.wrap(s.DirectoryListRequest)) + s.mux.HandleFunc("/v1/client/fs/stat/", s.wrap(s.FileStatRequest)) + s.mux.HandleFunc("/v1/client/fs/readat/", s.wrap(s.FileReadAtRequest)) + s.mux.HandleFunc("/v1/agent/self", s.wrap(s.AgentSelfRequest)) s.mux.HandleFunc("/v1/agent/join", s.wrap(s.AgentJoinRequest)) s.mux.HandleFunc("/v1/agent/members", s.wrap(s.AgentMembersRequest))