From 744c226c23058d945b8178da7676b2a509cbea2a Mon Sep 17 00:00:00 2001 From: Diptanu Choudhury Date: Tue, 12 Jan 2016 15:03:53 -0800 Subject: [PATCH 01/18] Added methods for listing directories inside an alloc --- client/alloc_runner.go | 4 ++++ client/allocdir/alloc_dir.go | 21 +++++++++++++++++++++ client/client.go | 10 ++++++++++ command/agent/fs_endpoint.go | 32 ++++++++++++++++++++++++++++++++ command/agent/http.go | 4 ++++ 5 files changed, 71 insertions(+) create mode 100644 command/agent/fs_endpoint.go 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)) From cbcdaec3fe8f134b8205612eab44b0d5377e07e0 Mon Sep 17 00:00:00 2001 From: Diptanu Choudhury Date: Tue, 12 Jan 2016 15:25:51 -0800 Subject: [PATCH 02/18] Added the Stat API --- client/alloc_runner.go | 4 ++++ client/allocdir/alloc_dir.go | 16 ++++++++++++++++ client/client.go | 8 ++++++++ command/agent/fs_endpoint.go | 16 +++++++++++++++- 4 files changed, 43 insertions(+), 1 deletion(-) diff --git a/client/alloc_runner.go b/client/alloc_runner.go index 606ec8877..771f3fe87 100644 --- a/client/alloc_runner.go +++ b/client/alloc_runner.go @@ -428,3 +428,7 @@ func (r *AllocRunner) WaitCh() <-chan struct{} { func (r *AllocRunner) FSList(path string) ([]*allocdir.AllocFile, error) { return r.ctx.AllocDir.FSList(path) } + +func (r *AllocRunner) FSStat(path string) (*allocdir.AllocFile, error) { + return r.ctx.AllocDir.FSStat(path) +} diff --git a/client/allocdir/alloc_dir.go b/client/allocdir/alloc_dir.go index 4add2434d..19a26fd9c 100644 --- a/client/allocdir/alloc_dir.go +++ b/client/allocdir/alloc_dir.go @@ -41,6 +41,7 @@ type AllocDir struct { type AllocFile struct { Name string IsDir bool + Size int64 } func NewAllocDir(allocDir string) *AllocDir { @@ -233,11 +234,26 @@ func (d *AllocDir) FSList(path string) ([]*AllocFile, error) { files[idx] = &AllocFile{ Name: info.Name(), IsDir: info.IsDir(), + Size: info.Size(), } } return files, err } +func (d *AllocDir) FSStat(path string) (*AllocFile, error) { + info, err := os.Stat(path) + if err != nil { + return nil, err + } + + return &AllocFile{ + Size: info.Size(), + Name: info.Name(), + IsDir: info.IsDir(), + }, nil + +} + 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 20c7b1f7c..f7ae52682 100644 --- a/client/client.go +++ b/client/client.go @@ -363,6 +363,14 @@ func (c *Client) FSList(allocID string, path string) ([]*allocdir.AllocFile, err return ar.FSList(path) } +func (c *Client) FSStat(allocID string, path string) (*allocdir.AllocFile, error) { + ar, ok := c.allocs[allocID] + if !ok { + return nil, fmt.Errorf("alloc not found") + } + return ar.FSStat(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 index 46540997a..58dd1e5ab 100644 --- a/command/agent/fs_endpoint.go +++ b/command/agent/fs_endpoint.go @@ -24,7 +24,21 @@ func (s *HTTPServer) DirectoryListRequest(resp http.ResponseWriter, req *http.Re } func (s *HTTPServer) FileStatRequest(resp http.ResponseWriter, req *http.Request) (interface{}, error) { - return nil, nil + allocID := strings.TrimPrefix(req.URL.Path, "/v1/client/fs/ls/") + path := req.URL.Query().Get("path") + if path == "" { + resp.WriteHeader(http.StatusNotFound) + return nil, fmt.Errorf("must provide a file name") + } + if allocID == "" { + resp.WriteHeader(http.StatusNotFound) + return nil, fmt.Errorf("alloc id not found") + } + fileInfo, err := s.agent.client.FSStat(allocID, path) + if err != nil { + return nil, err + } + return fileInfo, nil } func (s *HTTPServer) FileReadAtRequest(resp http.ResponseWriter, req *http.Request) (interface{}, error) { From b5385b616d7978e7e01e7f3c5722de66ec5ef030 Mon Sep 17 00:00:00 2001 From: Diptanu Choudhury Date: Tue, 12 Jan 2016 21:28:07 -0800 Subject: [PATCH 03/18] Implemented the Stat API --- client/allocdir/alloc_dir.go | 13 ++++++++++++- client/client.go | 4 ++++ command/agent/fs_endpoint.go | 2 +- 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/client/allocdir/alloc_dir.go b/client/allocdir/alloc_dir.go index 19a26fd9c..589a77d55 100644 --- a/client/allocdir/alloc_dir.go +++ b/client/allocdir/alloc_dir.go @@ -241,7 +241,8 @@ func (d *AllocDir) FSList(path string) ([]*AllocFile, error) { } func (d *AllocDir) FSStat(path string) (*AllocFile, error) { - info, err := os.Stat(path) + p := filepath.Join(d.AllocDir, path) + info, err := os.Stat(p) if err != nil { return nil, err } @@ -251,7 +252,17 @@ func (d *AllocDir) FSStat(path string) (*AllocFile, error) { Name: info.Name(), IsDir: info.IsDir(), }, nil +} +func (d *AllocDir) FSReadAt(allocID string, path string, offset int64, limit int64) ([]byte, error) { + p := filepath.Join(d.AllocDir, path) + f, err := os.Open(p) + if err != nil { + return nil, err + } + b := make([]byte, limit) + f.ReadAt(b, offset) + return b, nil } func fileCopy(src, dst string, perm os.FileMode) error { diff --git a/client/client.go b/client/client.go index f7ae52682..f7a526c09 100644 --- a/client/client.go +++ b/client/client.go @@ -371,6 +371,10 @@ func (c *Client) FSStat(allocID string, path string) (*allocdir.AllocFile, error return ar.FSStat(path) } +func (c *Client) FSReadAt(allocID string, path string, offset int64, limit int64) ([]byte, error) { + return nil, nil +} + // 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 index 58dd1e5ab..a4fd48cb3 100644 --- a/command/agent/fs_endpoint.go +++ b/command/agent/fs_endpoint.go @@ -24,7 +24,7 @@ func (s *HTTPServer) DirectoryListRequest(resp http.ResponseWriter, req *http.Re } func (s *HTTPServer) FileStatRequest(resp http.ResponseWriter, req *http.Request) (interface{}, error) { - allocID := strings.TrimPrefix(req.URL.Path, "/v1/client/fs/ls/") + allocID := strings.TrimPrefix(req.URL.Path, "/v1/client/fs/stat/") path := req.URL.Query().Get("path") if path == "" { resp.WriteHeader(http.StatusNotFound) From 11a67599b95673035e14a18f1bd5d0087054ca3c Mon Sep 17 00:00:00 2001 From: Diptanu Choudhury Date: Tue, 12 Jan 2016 22:06:42 -0800 Subject: [PATCH 04/18] Implemeted readAt --- client/alloc_runner.go | 5 +++++ client/allocdir/alloc_dir.go | 14 +++++++++----- client/client.go | 9 +++++++-- command/agent/fs_endpoint.go | 30 ++++++++++++++++++++++++++++++ 4 files changed, 51 insertions(+), 7 deletions(-) diff --git a/client/alloc_runner.go b/client/alloc_runner.go index 771f3fe87..5e8b44287 100644 --- a/client/alloc_runner.go +++ b/client/alloc_runner.go @@ -3,6 +3,7 @@ package client import ( "encoding/json" "fmt" + "io" "log" "os" "path/filepath" @@ -432,3 +433,7 @@ func (r *AllocRunner) FSList(path string) ([]*allocdir.AllocFile, error) { func (r *AllocRunner) FSStat(path string) (*allocdir.AllocFile, error) { return r.ctx.AllocDir.FSStat(path) } + +func (r *AllocRunner) FSReadAt(allocID string, path string, offset int64, limit int64, w io.Writer) error { + return r.ctx.AllocDir.FSReadAt(allocID, path, offset, limit, w) +} diff --git a/client/allocdir/alloc_dir.go b/client/allocdir/alloc_dir.go index 589a77d55..312866a6a 100644 --- a/client/allocdir/alloc_dir.go +++ b/client/allocdir/alloc_dir.go @@ -254,15 +254,19 @@ func (d *AllocDir) FSStat(path string) (*AllocFile, error) { }, nil } -func (d *AllocDir) FSReadAt(allocID string, path string, offset int64, limit int64) ([]byte, error) { +func (d *AllocDir) FSReadAt(allocID string, path string, offset int64, limit int64, w io.Writer) error { + buf := make([]byte, limit) p := filepath.Join(d.AllocDir, path) f, err := os.Open(p) if err != nil { - return nil, err + return err } - b := make([]byte, limit) - f.ReadAt(b, offset) - return b, nil + n, err := f.ReadAt(buf, offset) + if err != nil { + return err + } + w.Write(buf[:n]) + return nil } func fileCopy(src, dst string, perm os.FileMode) error { diff --git a/client/client.go b/client/client.go index f7a526c09..8fe213572 100644 --- a/client/client.go +++ b/client/client.go @@ -2,6 +2,7 @@ package client import ( "fmt" + "io" "io/ioutil" "log" "net" @@ -371,8 +372,12 @@ func (c *Client) FSStat(allocID string, path string) (*allocdir.AllocFile, error return ar.FSStat(path) } -func (c *Client) FSReadAt(allocID string, path string, offset int64, limit int64) ([]byte, error) { - return nil, nil +func (c *Client) FSReadAt(allocID string, path string, offset int64, limit int64, w io.Writer) error { + ar, ok := c.allocs[allocID] + if !ok { + return fmt.Errorf("alloc not found") + } + return ar.FSReadAt(allocID, path, offset, limit, w) } // restoreState is used to restore our state from the data dir diff --git a/command/agent/fs_endpoint.go b/command/agent/fs_endpoint.go index a4fd48cb3..66d1c0633 100644 --- a/command/agent/fs_endpoint.go +++ b/command/agent/fs_endpoint.go @@ -3,6 +3,7 @@ package agent import ( "fmt" "net/http" + "strconv" "strings" ) @@ -42,5 +43,34 @@ func (s *HTTPServer) FileStatRequest(resp http.ResponseWriter, req *http.Request } func (s *HTTPServer) FileReadAtRequest(resp http.ResponseWriter, req *http.Request) (interface{}, error) { + allocID := strings.TrimPrefix(req.URL.Path, "/v1/client/fs/readat/") + path := req.URL.Query().Get("path") + ofs := req.URL.Query().Get("offset") + if ofs == "" { + ofs = "0" + } + + offset, err := strconv.ParseInt(ofs, 10, 64) + if err != nil { + return nil, fmt.Errorf("error parsing offset: %v", err) + } + lim := req.URL.Query().Get("limit") + limit, err := strconv.ParseInt(lim, 10, 64) + if err != nil { + return nil, fmt.Errorf("error parsing limit: %v", err) + } + + if path == "" { + resp.WriteHeader(http.StatusNotFound) + return nil, fmt.Errorf("must provide a file name") + } + if allocID == "" { + resp.WriteHeader(http.StatusNotFound) + return nil, fmt.Errorf("alloc id not found") + } + if err = s.agent.client.FSReadAt(allocID, path, offset, limit, resp); err != nil { + return nil, err + } return nil, nil + } From f7c367397f9e6bb7c58dd3793ac840a6874e3f0a Mon Sep 17 00:00:00 2001 From: Diptanu Choudhury Date: Tue, 12 Jan 2016 22:25:12 -0800 Subject: [PATCH 05/18] Refactored the code --- command/agent/fs_endpoint.go | 70 ++++++++++++++---------------------- 1 file changed, 26 insertions(+), 44 deletions(-) diff --git a/command/agent/fs_endpoint.go b/command/agent/fs_endpoint.go index 66d1c0633..712e45636 100644 --- a/command/agent/fs_endpoint.go +++ b/command/agent/fs_endpoint.go @@ -8,69 +8,51 @@ import ( ) 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) + var allocID, path string + + if allocID = strings.TrimPrefix(req.URL.Path, "/v1/client/fs/ls/"); allocID == "" { return nil, fmt.Errorf("alloc id not found") } - files, err := s.agent.client.FSList(allocID, path) - if err != nil { - return nil, err + if path = req.URL.Query().Get("path"); path == "" { + path = "/" } - return files, nil + return s.agent.client.FSList(allocID, path) } func (s *HTTPServer) FileStatRequest(resp http.ResponseWriter, req *http.Request) (interface{}, error) { - allocID := strings.TrimPrefix(req.URL.Path, "/v1/client/fs/stat/") - path := req.URL.Query().Get("path") - if path == "" { - resp.WriteHeader(http.StatusNotFound) - return nil, fmt.Errorf("must provide a file name") - } - if allocID == "" { - resp.WriteHeader(http.StatusNotFound) + var allocID, path string + + if allocID = strings.TrimPrefix(req.URL.Path, "/v1/client/fs/stat/"); allocID == "" { return nil, fmt.Errorf("alloc id not found") } - fileInfo, err := s.agent.client.FSStat(allocID, path) - if err != nil { - return nil, err + if path := req.URL.Query().Get("path"); path == "" { + return nil, fmt.Errorf("must provide a file name") } - return fileInfo, nil + return s.agent.client.FSStat(allocID, path) } func (s *HTTPServer) FileReadAtRequest(resp http.ResponseWriter, req *http.Request) (interface{}, error) { - allocID := strings.TrimPrefix(req.URL.Path, "/v1/client/fs/readat/") - path := req.URL.Query().Get("path") - ofs := req.URL.Query().Get("offset") - if ofs == "" { - ofs = "0" - } + var allocID, path string + var offset, limit int64 + var err error - offset, err := strconv.ParseInt(ofs, 10, 64) - if err != nil { - return nil, fmt.Errorf("error parsing offset: %v", err) - } - lim := req.URL.Query().Get("limit") - limit, err := strconv.ParseInt(lim, 10, 64) - if err != nil { - return nil, fmt.Errorf("error parsing limit: %v", err) - } + q := req.URL.Query() - if path == "" { - resp.WriteHeader(http.StatusNotFound) + if allocID = strings.TrimPrefix(req.URL.Path, "/v1/client/fs/readat/"); allocID == "" { + return nil, fmt.Errorf("alloc id not found") + } + if path = q.Get("path"); path == "" { return nil, fmt.Errorf("must provide a file name") } - if allocID == "" { - resp.WriteHeader(http.StatusNotFound) - return nil, fmt.Errorf("alloc id not found") + + if offset, err = strconv.ParseInt(q.Get("offset"), 10, 64); err != nil { + return nil, fmt.Errorf("error parsing offset: %v", err) + } + if limit, err = strconv.ParseInt(q.Get("limit"), 10, 64); err != nil { + return nil, fmt.Errorf("error parsing limit: %v", err) } if err = s.agent.client.FSReadAt(allocID, path, offset, limit, resp); err != nil { return nil, err } return nil, nil - } From 46bb3fb5cd2ee3ec671e83760a166a0a82fc06a2 Mon Sep 17 00:00:00 2001 From: Diptanu Choudhury Date: Wed, 13 Jan 2016 11:19:45 -0800 Subject: [PATCH 06/18] Fixed the logic of extracting alloc --- command/agent/fs_endpoint.go | 1 - command/agent/fs_endpoint_test.go | 48 +++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+), 1 deletion(-) create mode 100644 command/agent/fs_endpoint_test.go diff --git a/command/agent/fs_endpoint.go b/command/agent/fs_endpoint.go index 712e45636..a769aed31 100644 --- a/command/agent/fs_endpoint.go +++ b/command/agent/fs_endpoint.go @@ -21,7 +21,6 @@ func (s *HTTPServer) DirectoryListRequest(resp http.ResponseWriter, req *http.Re func (s *HTTPServer) FileStatRequest(resp http.ResponseWriter, req *http.Request) (interface{}, error) { var allocID, path string - if allocID = strings.TrimPrefix(req.URL.Path, "/v1/client/fs/stat/"); allocID == "" { return nil, fmt.Errorf("alloc id not found") } diff --git a/command/agent/fs_endpoint_test.go b/command/agent/fs_endpoint_test.go new file mode 100644 index 000000000..a1b5bd32b --- /dev/null +++ b/command/agent/fs_endpoint_test.go @@ -0,0 +1,48 @@ +package agent + +import ( + "net/http" + "net/http/httptest" + "testing" +) + +func TestHTTP_FSDirectoryList(t *testing.T) { + httpTest(t, nil, func(s *TestServer) { + req, err := http.NewRequest("GET", "/v1/client/fs/ls", nil) + if err != nil { + t.Fatalf("err: %v", err) + } + respW := httptest.NewRecorder() + + _, err = s.Server.DirectoryListRequest(respW, req) + if err == nil { + t.Fatal("expected error") + } + }) +} + +func TestHTTP_FSStat(t *testing.T) { + httpTest(t, nil, func(s *TestServer) { + req, err := http.NewRequest("GET", "/v1/client/fs/stat/", nil) + if err != nil { + t.Fatalf("err: %v", err) + } + respW := httptest.NewRecorder() + + _, err = s.Server.FileStatRequest(respW, req) + if err == nil { + t.Fatal("expected error") + } + + req, err = http.NewRequest("GET", "/v1/client/fs/stat/foo", nil) + if err != nil { + t.Fatalf("err: %v", err) + } + respW = httptest.NewRecorder() + + _, err = s.Server.FileStatRequest(respW, req) + if err == nil { + t.Fatal("expected error") + } + }) +} From 8636fb61f7b8177b7f2d3391c5ff7f503f069aae Mon Sep 17 00:00:00 2001 From: Diptanu Choudhury Date: Wed, 13 Jan 2016 11:37:29 -0800 Subject: [PATCH 07/18] Added a test for the readat api endpoint --- command/agent/fs_endpoint_test.go | 40 ++++++++++++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) diff --git a/command/agent/fs_endpoint_test.go b/command/agent/fs_endpoint_test.go index a1b5bd32b..197fd2420 100644 --- a/command/agent/fs_endpoint_test.go +++ b/command/agent/fs_endpoint_test.go @@ -3,6 +3,7 @@ package agent import ( "net/http" "net/http/httptest" + "strings" "testing" ) @@ -30,7 +31,7 @@ func TestHTTP_FSStat(t *testing.T) { respW := httptest.NewRecorder() _, err = s.Server.FileStatRequest(respW, req) - if err == nil { + if !strings.HasPrefix(err.Error(), "alloc id not found") { t.Fatal("expected error") } @@ -41,6 +42,43 @@ func TestHTTP_FSStat(t *testing.T) { respW = httptest.NewRecorder() _, err = s.Server.FileStatRequest(respW, req) + if !strings.HasPrefix(err.Error(), "must provide a file name") { + t.Fatal("expected error") + } + }) +} + +func TestHTTP_FSReadAt(t *testing.T) { + httpTest(t, nil, func(s *TestServer) { + req, err := http.NewRequest("GET", "/v1/client/fs/readat/", nil) + if err != nil { + t.Fatalf("err: %v", err) + } + respW := httptest.NewRecorder() + + _, err = s.Server.FileReadAtRequest(respW, req) + if err == nil { + t.Fatal("expected error") + } + + req, err = http.NewRequest("GET", "/v1/client/fs/readat/foo", nil) + if err != nil { + t.Fatalf("err: %v", err) + } + respW = httptest.NewRecorder() + + _, err = s.Server.FileReadAtRequest(respW, req) + if err == nil { + t.Fatal("expected error") + } + + req, err = http.NewRequest("GET", "/v1/client/fs/readat/foo?path=/path/to/file", nil) + if err != nil { + t.Fatalf("err: %v", err) + } + respW = httptest.NewRecorder() + + _, err = s.Server.FileReadAtRequest(respW, req) if err == nil { t.Fatal("expected error") } From 6604ef5be1929ce4d2e2e4c2ac447bb7c3adc6a0 Mon Sep 17 00:00:00 2001 From: Diptanu Choudhury Date: Wed, 13 Jan 2016 11:38:43 -0800 Subject: [PATCH 08/18] Writing contents of buffer to writer even if there was an error --- client/allocdir/alloc_dir.go | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/client/allocdir/alloc_dir.go b/client/allocdir/alloc_dir.go index 312866a6a..ea5a3d441 100644 --- a/client/allocdir/alloc_dir.go +++ b/client/allocdir/alloc_dir.go @@ -262,11 +262,8 @@ func (d *AllocDir) FSReadAt(allocID string, path string, offset int64, limit int return err } n, err := f.ReadAt(buf, offset) - if err != nil { - return err - } w.Write(buf[:n]) - return nil + return err } func fileCopy(src, dst string, perm os.FileMode) error { From 2b1962b9fd79623eaee83b916e14e3461a12ad56 Mon Sep 17 00:00:00 2001 From: Diptanu Choudhury Date: Wed, 13 Jan 2016 11:49:39 -0800 Subject: [PATCH 09/18] Refactored the tests --- command/agent/fs_endpoint.go | 15 ++++++++++----- command/agent/fs_endpoint_test.go | 16 ++++++++-------- 2 files changed, 18 insertions(+), 13 deletions(-) diff --git a/command/agent/fs_endpoint.go b/command/agent/fs_endpoint.go index a769aed31..c2395ee12 100644 --- a/command/agent/fs_endpoint.go +++ b/command/agent/fs_endpoint.go @@ -7,11 +7,16 @@ import ( "strings" ) +var ( + allocIDNotPresentErr = fmt.Errorf("must provide a valid alloc id") + fileNameNotPresentErr = fmt.Errorf("must provide a file name") +) + func (s *HTTPServer) DirectoryListRequest(resp http.ResponseWriter, req *http.Request) (interface{}, error) { var allocID, path string if allocID = strings.TrimPrefix(req.URL.Path, "/v1/client/fs/ls/"); allocID == "" { - return nil, fmt.Errorf("alloc id not found") + return nil, allocIDNotPresentErr } if path = req.URL.Query().Get("path"); path == "" { path = "/" @@ -22,10 +27,10 @@ func (s *HTTPServer) DirectoryListRequest(resp http.ResponseWriter, req *http.Re func (s *HTTPServer) FileStatRequest(resp http.ResponseWriter, req *http.Request) (interface{}, error) { var allocID, path string if allocID = strings.TrimPrefix(req.URL.Path, "/v1/client/fs/stat/"); allocID == "" { - return nil, fmt.Errorf("alloc id not found") + return nil, allocIDNotPresentErr } if path := req.URL.Query().Get("path"); path == "" { - return nil, fmt.Errorf("must provide a file name") + return nil, fileNameNotPresentErr } return s.agent.client.FSStat(allocID, path) } @@ -38,10 +43,10 @@ func (s *HTTPServer) FileReadAtRequest(resp http.ResponseWriter, req *http.Reque q := req.URL.Query() if allocID = strings.TrimPrefix(req.URL.Path, "/v1/client/fs/readat/"); allocID == "" { - return nil, fmt.Errorf("alloc id not found") + return nil, allocIDNotPresentErr } if path = q.Get("path"); path == "" { - return nil, fmt.Errorf("must provide a file name") + return nil, fileNameNotPresentErr } if offset, err = strconv.ParseInt(q.Get("offset"), 10, 64); err != nil { diff --git a/command/agent/fs_endpoint_test.go b/command/agent/fs_endpoint_test.go index 197fd2420..e0e35da53 100644 --- a/command/agent/fs_endpoint_test.go +++ b/command/agent/fs_endpoint_test.go @@ -3,21 +3,20 @@ package agent import ( "net/http" "net/http/httptest" - "strings" "testing" ) func TestHTTP_FSDirectoryList(t *testing.T) { httpTest(t, nil, func(s *TestServer) { - req, err := http.NewRequest("GET", "/v1/client/fs/ls", nil) + req, err := http.NewRequest("GET", "/v1/client/fs/ls/", nil) if err != nil { t.Fatalf("err: %v", err) } respW := httptest.NewRecorder() _, err = s.Server.DirectoryListRequest(respW, req) - if err == nil { - t.Fatal("expected error") + if err != allocIDNotPresentErr { + t.Fatalf("expected err: %v, actual: %v", allocIDNotPresentErr, err) } }) } @@ -31,8 +30,8 @@ func TestHTTP_FSStat(t *testing.T) { respW := httptest.NewRecorder() _, err = s.Server.FileStatRequest(respW, req) - if !strings.HasPrefix(err.Error(), "alloc id not found") { - t.Fatal("expected error") + if err != allocIDNotPresentErr { + t.Fatalf("expected err: %v, actual: %v", allocIDNotPresentErr, err) } req, err = http.NewRequest("GET", "/v1/client/fs/stat/foo", nil) @@ -42,9 +41,10 @@ func TestHTTP_FSStat(t *testing.T) { respW = httptest.NewRecorder() _, err = s.Server.FileStatRequest(respW, req) - if !strings.HasPrefix(err.Error(), "must provide a file name") { - t.Fatal("expected error") + if err != fileNameNotPresentErr { + t.Fatalf("expected err: %v, actual: %v", allocIDNotPresentErr, err) } + }) } From 9dced9a8903fb45b38f40a3ae1e2cf56ceb2024b Mon Sep 17 00:00:00 2001 From: Diptanu Choudhury Date: Wed, 13 Jan 2016 12:43:13 -0800 Subject: [PATCH 10/18] alex: making the readat more efficient --- client/allocdir/alloc_dir.go | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/client/allocdir/alloc_dir.go b/client/allocdir/alloc_dir.go index ea5a3d441..03cd0ecb5 100644 --- a/client/allocdir/alloc_dir.go +++ b/client/allocdir/alloc_dir.go @@ -255,15 +255,13 @@ func (d *AllocDir) FSStat(path string) (*AllocFile, error) { } func (d *AllocDir) FSReadAt(allocID string, path string, offset int64, limit int64, w io.Writer) error { - buf := make([]byte, limit) p := filepath.Join(d.AllocDir, path) f, err := os.Open(p) if err != nil { return err } - n, err := f.ReadAt(buf, offset) - w.Write(buf[:n]) - return err + io.Copy(w, io.LimitReader(f, limit)) + return nil } func fileCopy(src, dst string, perm os.FileMode) error { From ee369382aa29daa5fa525edb1417722f28b35477 Mon Sep 17 00:00:00 2001 From: Diptanu Choudhury Date: Wed, 13 Jan 2016 13:21:03 -0800 Subject: [PATCH 11/18] Fixed the query for extracting path from stat --- command/agent/fs_endpoint.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/command/agent/fs_endpoint.go b/command/agent/fs_endpoint.go index c2395ee12..aaadad386 100644 --- a/command/agent/fs_endpoint.go +++ b/command/agent/fs_endpoint.go @@ -29,7 +29,7 @@ func (s *HTTPServer) FileStatRequest(resp http.ResponseWriter, req *http.Request if allocID = strings.TrimPrefix(req.URL.Path, "/v1/client/fs/stat/"); allocID == "" { return nil, allocIDNotPresentErr } - if path := req.URL.Query().Get("path"); path == "" { + if path = req.URL.Query().Get("path"); path == "" { return nil, fileNameNotPresentErr } return s.agent.client.FSStat(allocID, path) From 78d03616f66f1b549b072bfebf944f935114015b Mon Sep 17 00:00:00 2001 From: Diptanu Choudhury Date: Wed, 13 Jan 2016 14:39:06 -0800 Subject: [PATCH 12/18] Closing the file handler after finishing readat --- client/allocdir/alloc_dir.go | 1 + 1 file changed, 1 insertion(+) diff --git a/client/allocdir/alloc_dir.go b/client/allocdir/alloc_dir.go index 03cd0ecb5..3ee33c72e 100644 --- a/client/allocdir/alloc_dir.go +++ b/client/allocdir/alloc_dir.go @@ -260,6 +260,7 @@ func (d *AllocDir) FSReadAt(allocID string, path string, offset int64, limit int if err != nil { return err } + defer f.Close() io.Copy(w, io.LimitReader(f, limit)) return nil } From 4345fc9bee59297a5ebd06ddb5e259e8e873d604 Mon Sep 17 00:00:00 2001 From: Diptanu Choudhury Date: Wed, 13 Jan 2016 17:18:10 -0800 Subject: [PATCH 13/18] Renamed AllocFile to AllocFileInfo --- client/alloc_runner.go | 10 +++++----- client/allocdir/alloc_dir.go | 16 ++++++++-------- client/client.go | 4 ++-- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/client/alloc_runner.go b/client/alloc_runner.go index 5e8b44287..65a73b15f 100644 --- a/client/alloc_runner.go +++ b/client/alloc_runner.go @@ -426,14 +426,14 @@ func (r *AllocRunner) WaitCh() <-chan struct{} { return r.waitCh } -func (r *AllocRunner) FSList(path string) ([]*allocdir.AllocFile, error) { - return r.ctx.AllocDir.FSList(path) +func (r *AllocRunner) FSList(path string) ([]*allocdir.AllocFileInfo, error) { + return r.ctx.AllocDir.List(path) } -func (r *AllocRunner) FSStat(path string) (*allocdir.AllocFile, error) { - return r.ctx.AllocDir.FSStat(path) +func (r *AllocRunner) FSStat(path string) (*allocdir.AllocFileInfo, error) { + return r.ctx.AllocDir.Stat(path) } func (r *AllocRunner) FSReadAt(allocID string, path string, offset int64, limit int64, w io.Writer) error { - return r.ctx.AllocDir.FSReadAt(allocID, path, offset, limit, w) + return r.ctx.AllocDir.ReadAt(allocID, path, offset, limit, w) } diff --git a/client/allocdir/alloc_dir.go b/client/allocdir/alloc_dir.go index 3ee33c72e..c227282d7 100644 --- a/client/allocdir/alloc_dir.go +++ b/client/allocdir/alloc_dir.go @@ -38,7 +38,7 @@ type AllocDir struct { mounted []string } -type AllocFile struct { +type AllocFileInfo struct { Name string IsDir bool Size int64 @@ -223,15 +223,15 @@ func (d *AllocDir) MountSharedDir(task string) error { return nil } -func (d *AllocDir) FSList(path string) ([]*AllocFile, error) { +func (d *AllocDir) List(path string) ([]*AllocFileInfo, error) { p := filepath.Join(d.AllocDir, path) finfos, err := ioutil.ReadDir(p) if err != nil { - return []*AllocFile{}, nil + return []*AllocFileInfo{}, nil } - files := make([]*AllocFile, len(finfos)) + files := make([]*AllocFileInfo, len(finfos)) for idx, info := range finfos { - files[idx] = &AllocFile{ + files[idx] = &AllocFileInfo{ Name: info.Name(), IsDir: info.IsDir(), Size: info.Size(), @@ -240,21 +240,21 @@ func (d *AllocDir) FSList(path string) ([]*AllocFile, error) { return files, err } -func (d *AllocDir) FSStat(path string) (*AllocFile, error) { +func (d *AllocDir) Stat(path string) (*AllocFileInfo, error) { p := filepath.Join(d.AllocDir, path) info, err := os.Stat(p) if err != nil { return nil, err } - return &AllocFile{ + return &AllocFileInfo{ Size: info.Size(), Name: info.Name(), IsDir: info.IsDir(), }, nil } -func (d *AllocDir) FSReadAt(allocID string, path string, offset int64, limit int64, w io.Writer) error { +func (d *AllocDir) ReadAt(allocID string, path string, offset int64, limit int64, w io.Writer) error { p := filepath.Join(d.AllocDir, path) f, err := os.Open(p) if err != nil { diff --git a/client/client.go b/client/client.go index 8fe213572..737ab9b38 100644 --- a/client/client.go +++ b/client/client.go @@ -355,7 +355,7 @@ func (c *Client) Node() *structs.Node { return c.config.Node } -func (c *Client) FSList(allocID string, path string) ([]*allocdir.AllocFile, error) { +func (c *Client) FSList(allocID string, path string) ([]*allocdir.AllocFileInfo, error) { ar, ok := c.allocs[allocID] if !ok { return nil, fmt.Errorf("alloc not present") @@ -364,7 +364,7 @@ func (c *Client) FSList(allocID string, path string) ([]*allocdir.AllocFile, err return ar.FSList(path) } -func (c *Client) FSStat(allocID string, path string) (*allocdir.AllocFile, error) { +func (c *Client) FSStat(allocID string, path string) (*allocdir.AllocFileInfo, error) { ar, ok := c.allocs[allocID] if !ok { return nil, fmt.Errorf("alloc not found") From e7b1424bcb2b4344fb49eaba0999bfc9545c0beb Mon Sep 17 00:00:00 2001 From: Diptanu Choudhury Date: Thu, 14 Jan 2016 11:47:05 -0800 Subject: [PATCH 14/18] Returning an error if the list fails --- client/allocdir/alloc_dir.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/allocdir/alloc_dir.go b/client/allocdir/alloc_dir.go index c227282d7..eafca6d4e 100644 --- a/client/allocdir/alloc_dir.go +++ b/client/allocdir/alloc_dir.go @@ -227,7 +227,7 @@ func (d *AllocDir) List(path string) ([]*AllocFileInfo, error) { p := filepath.Join(d.AllocDir, path) finfos, err := ioutil.ReadDir(p) if err != nil { - return []*AllocFileInfo{}, nil + return []*AllocFileInfo{}, err } files := make([]*AllocFileInfo, len(finfos)) for idx, info := range finfos { From 21847954e061cdd2ece595f4ff783148fe8dc157 Mon Sep 17 00:00:00 2001 From: Diptanu Choudhury Date: Thu, 14 Jan 2016 13:35:42 -0800 Subject: [PATCH 15/18] changed the API of the client --- client/alloc_runner.go | 13 ++----------- client/allocdir/alloc_dir.go | 19 ++++++++++++++----- client/client.go | 21 ++------------------- command/agent/fs_endpoint.go | 21 ++++++++++++++++++--- 4 files changed, 36 insertions(+), 38 deletions(-) diff --git a/client/alloc_runner.go b/client/alloc_runner.go index 65a73b15f..1a6fd639b 100644 --- a/client/alloc_runner.go +++ b/client/alloc_runner.go @@ -3,7 +3,6 @@ package client import ( "encoding/json" "fmt" - "io" "log" "os" "path/filepath" @@ -426,14 +425,6 @@ func (r *AllocRunner) WaitCh() <-chan struct{} { return r.waitCh } -func (r *AllocRunner) FSList(path string) ([]*allocdir.AllocFileInfo, error) { - return r.ctx.AllocDir.List(path) -} - -func (r *AllocRunner) FSStat(path string) (*allocdir.AllocFileInfo, error) { - return r.ctx.AllocDir.Stat(path) -} - -func (r *AllocRunner) FSReadAt(allocID string, path string, offset int64, limit int64, w io.Writer) error { - return r.ctx.AllocDir.ReadAt(allocID, path, offset, limit, w) +func (r *AllocRunner) GetAllocFS(allocID string) allocdir.AllocDirFS { + return r.ctx.AllocDir } diff --git a/client/allocdir/alloc_dir.go b/client/allocdir/alloc_dir.go index eafca6d4e..ddefdde0f 100644 --- a/client/allocdir/alloc_dir.go +++ b/client/allocdir/alloc_dir.go @@ -44,6 +44,12 @@ type AllocFileInfo struct { Size int64 } +type AllocDirFS interface { + List(path string) ([]*AllocFileInfo, error) + Stat(path string) (*AllocFileInfo, error) + ReadAt(path string, offset int64, limit int64) (io.ReadCloser, error) +} + func NewAllocDir(allocDir string) *AllocDir { d := &AllocDir{AllocDir: allocDir, TaskDirs: make(map[string]string)} d.SharedDir = filepath.Join(d.AllocDir, SharedAllocName) @@ -254,15 +260,18 @@ func (d *AllocDir) Stat(path string) (*AllocFileInfo, error) { }, nil } -func (d *AllocDir) ReadAt(allocID string, path string, offset int64, limit int64, w io.Writer) error { +func (d *AllocDir) ReadAt(path string, offset int64, limit int64) (io.ReadCloser, error) { p := filepath.Join(d.AllocDir, path) f, err := os.Open(p) if err != nil { - return err + return nil, err } - defer f.Close() - io.Copy(w, io.LimitReader(f, limit)) - return nil + return &LimitReadCloser{Reader: io.LimitReader(f, limit), Closer: f}, nil +} + +type LimitReadCloser struct { + io.Reader + io.Closer } func fileCopy(src, dst string, perm os.FileMode) error { diff --git a/client/client.go b/client/client.go index 737ab9b38..5e2d22066 100644 --- a/client/client.go +++ b/client/client.go @@ -2,7 +2,6 @@ package client import ( "fmt" - "io" "io/ioutil" "log" "net" @@ -355,29 +354,13 @@ func (c *Client) Node() *structs.Node { return c.config.Node } -func (c *Client) FSList(allocID string, path string) ([]*allocdir.AllocFileInfo, error) { - ar, ok := c.allocs[allocID] - if !ok { - return nil, fmt.Errorf("alloc not present") - } - - return ar.FSList(path) -} - -func (c *Client) FSStat(allocID string, path string) (*allocdir.AllocFileInfo, error) { +func (c *Client) GetAllocFS(allocID string) (allocdir.AllocDirFS, error) { ar, ok := c.allocs[allocID] if !ok { return nil, fmt.Errorf("alloc not found") } - return ar.FSStat(path) -} + return ar.GetAllocFS(allocID), nil -func (c *Client) FSReadAt(allocID string, path string, offset int64, limit int64, w io.Writer) error { - ar, ok := c.allocs[allocID] - if !ok { - return fmt.Errorf("alloc not found") - } - return ar.FSReadAt(allocID, path, offset, limit, w) } // restoreState is used to restore our state from the data dir diff --git a/command/agent/fs_endpoint.go b/command/agent/fs_endpoint.go index aaadad386..4a8de5698 100644 --- a/command/agent/fs_endpoint.go +++ b/command/agent/fs_endpoint.go @@ -2,6 +2,7 @@ package agent import ( "fmt" + "io" "net/http" "strconv" "strings" @@ -21,7 +22,11 @@ func (s *HTTPServer) DirectoryListRequest(resp http.ResponseWriter, req *http.Re if path = req.URL.Query().Get("path"); path == "" { path = "/" } - return s.agent.client.FSList(allocID, path) + fs, err := s.agent.client.GetAllocFS(allocID) + if err != nil { + return nil, err + } + return fs.List(path) } func (s *HTTPServer) FileStatRequest(resp http.ResponseWriter, req *http.Request) (interface{}, error) { @@ -32,7 +37,11 @@ func (s *HTTPServer) FileStatRequest(resp http.ResponseWriter, req *http.Request if path = req.URL.Query().Get("path"); path == "" { return nil, fileNameNotPresentErr } - return s.agent.client.FSStat(allocID, path) + fs, err := s.agent.client.GetAllocFS(allocID) + if err != nil { + return nil, err + } + return fs.Stat(path) } func (s *HTTPServer) FileReadAtRequest(resp http.ResponseWriter, req *http.Request) (interface{}, error) { @@ -55,8 +64,14 @@ func (s *HTTPServer) FileReadAtRequest(resp http.ResponseWriter, req *http.Reque if limit, err = strconv.ParseInt(q.Get("limit"), 10, 64); err != nil { return nil, fmt.Errorf("error parsing limit: %v", err) } - if err = s.agent.client.FSReadAt(allocID, path, offset, limit, resp); err != nil { + fs, err := s.agent.client.GetAllocFS(allocID) + if err != nil { return nil, err } + r, err := fs.ReadAt(path, offset, limit) + if err != nil { + return nil, err + } + io.Copy(resp, r) return nil, nil } From 12f44a28f779dbfddaf27bf3c103eb98431021ce Mon Sep 17 00:00:00 2001 From: Diptanu Choudhury Date: Thu, 14 Jan 2016 13:39:30 -0800 Subject: [PATCH 16/18] Renamed the tests --- command/agent/fs_endpoint_test.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/command/agent/fs_endpoint_test.go b/command/agent/fs_endpoint_test.go index e0e35da53..90c49fdea 100644 --- a/command/agent/fs_endpoint_test.go +++ b/command/agent/fs_endpoint_test.go @@ -6,7 +6,7 @@ import ( "testing" ) -func TestHTTP_FSDirectoryList(t *testing.T) { +func TestAllocDirFS_List(t *testing.T) { httpTest(t, nil, func(s *TestServer) { req, err := http.NewRequest("GET", "/v1/client/fs/ls/", nil) if err != nil { @@ -21,7 +21,7 @@ func TestHTTP_FSDirectoryList(t *testing.T) { }) } -func TestHTTP_FSStat(t *testing.T) { +func TestAllocDirFS_Stat(t *testing.T) { httpTest(t, nil, func(s *TestServer) { req, err := http.NewRequest("GET", "/v1/client/fs/stat/", nil) if err != nil { @@ -48,7 +48,7 @@ func TestHTTP_FSStat(t *testing.T) { }) } -func TestHTTP_FSReadAt(t *testing.T) { +func TestAllocDirFS_ReadAt(t *testing.T) { httpTest(t, nil, func(s *TestServer) { req, err := http.NewRequest("GET", "/v1/client/fs/readat/", nil) if err != nil { From 91869fb79bd6ff3bed31d4fdd2dcf57ba1587588 Mon Sep 17 00:00:00 2001 From: Diptanu Choudhury Date: Thu, 14 Jan 2016 13:45:48 -0800 Subject: [PATCH 17/18] Added some docs and removed a redundant method --- client/alloc_runner.go | 4 ---- client/allocdir/alloc_dir.go | 10 ++++++++-- client/client.go | 3 ++- 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/client/alloc_runner.go b/client/alloc_runner.go index 1a6fd639b..71de749c7 100644 --- a/client/alloc_runner.go +++ b/client/alloc_runner.go @@ -424,7 +424,3 @@ func (r *AllocRunner) Destroy() { func (r *AllocRunner) WaitCh() <-chan struct{} { return r.waitCh } - -func (r *AllocRunner) GetAllocFS(allocID string) allocdir.AllocDirFS { - return r.ctx.AllocDir -} diff --git a/client/allocdir/alloc_dir.go b/client/allocdir/alloc_dir.go index ddefdde0f..ad7f57389 100644 --- a/client/allocdir/alloc_dir.go +++ b/client/allocdir/alloc_dir.go @@ -229,6 +229,7 @@ func (d *AllocDir) MountSharedDir(task string) error { return nil } +// List returns the list of files at a path relative to the alloc dir func (d *AllocDir) List(path string) ([]*AllocFileInfo, error) { p := filepath.Join(d.AllocDir, path) finfos, err := ioutil.ReadDir(p) @@ -246,6 +247,7 @@ func (d *AllocDir) List(path string) ([]*AllocFileInfo, error) { return files, err } +// Stat returns information about the file at path relative to the alloc dir func (d *AllocDir) Stat(path string) (*AllocFileInfo, error) { p := filepath.Join(d.AllocDir, path) info, err := os.Stat(p) @@ -260,16 +262,20 @@ func (d *AllocDir) Stat(path string) (*AllocFileInfo, error) { }, nil } +// ReadAt returns a reader for a file at the path relative to the alloc dir +//which will read a chunk of bytes at a particular offset func (d *AllocDir) ReadAt(path string, offset int64, limit int64) (io.ReadCloser, error) { p := filepath.Join(d.AllocDir, path) f, err := os.Open(p) if err != nil { return nil, err } - return &LimitReadCloser{Reader: io.LimitReader(f, limit), Closer: f}, nil + return &FileReadCloser{Reader: io.LimitReader(f, limit), Closer: f}, nil } -type LimitReadCloser struct { +// FileReadCloser wraps a LimitReader so that a file is closed once it has been +// read +type FileReadCloser struct { io.Reader io.Closer } diff --git a/client/client.go b/client/client.go index 5e2d22066..b7a88c233 100644 --- a/client/client.go +++ b/client/client.go @@ -354,12 +354,13 @@ func (c *Client) Node() *structs.Node { return c.config.Node } +// GetAllocFS returns the AllocFS interface for the alloc dir of an allocation func (c *Client) GetAllocFS(allocID string) (allocdir.AllocDirFS, error) { ar, ok := c.allocs[allocID] if !ok { return nil, fmt.Errorf("alloc not found") } - return ar.GetAllocFS(allocID), nil + return ar.ctx.AllocDir, nil } From 778c5d0a864e34a5dd7b6add23dde99a0888818a Mon Sep 17 00:00:00 2001 From: Diptanu Choudhury Date: Thu, 14 Jan 2016 13:47:46 -0800 Subject: [PATCH 18/18] Added some more comments --- client/allocdir/alloc_dir.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/client/allocdir/alloc_dir.go b/client/allocdir/alloc_dir.go index ad7f57389..2d2a467d9 100644 --- a/client/allocdir/alloc_dir.go +++ b/client/allocdir/alloc_dir.go @@ -38,12 +38,14 @@ type AllocDir struct { mounted []string } +// AllocFileInfo holds information about a file inside the AllocDir type AllocFileInfo struct { Name string IsDir bool Size int64 } +// AllocDirFS returns methods which exposes file operations on the alloc dir type AllocDirFS interface { List(path string) ([]*AllocFileInfo, error) Stat(path string) (*AllocFileInfo, error)