github.com/dkerwin/nomad@v0.3.3-0.20160525181927-74554135514b/api/fs.go (about) 1 package api 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "io" 7 "io/ioutil" 8 "net/http" 9 "net/url" 10 "strconv" 11 "time" 12 ) 13 14 // AllocFileInfo holds information about a file inside the AllocDir 15 type AllocFileInfo struct { 16 Name string 17 IsDir bool 18 Size int64 19 FileMode string 20 ModTime time.Time 21 } 22 23 // AllocFS is used to introspect an allocation directory on a Nomad client 24 type AllocFS struct { 25 client *Client 26 } 27 28 // AllocFS returns an handle to the AllocFS endpoints 29 func (c *Client) AllocFS() *AllocFS { 30 return &AllocFS{client: c} 31 } 32 33 // List is used to list the files at a given path of an allocation directory 34 func (a *AllocFS) List(alloc *Allocation, path string, q *QueryOptions) ([]*AllocFileInfo, *QueryMeta, error) { 35 node, _, err := a.client.Nodes().Info(alloc.NodeID, &QueryOptions{}) 36 if err != nil { 37 return nil, nil, err 38 } 39 40 if node.HTTPAddr == "" { 41 return nil, nil, fmt.Errorf("http addr of the node where alloc %q is running is not advertised", alloc.ID) 42 } 43 u := &url.URL{ 44 Scheme: "http", 45 Host: node.HTTPAddr, 46 Path: fmt.Sprintf("/v1/client/fs/ls/%s", alloc.ID), 47 } 48 v := url.Values{} 49 v.Set("path", path) 50 u.RawQuery = v.Encode() 51 req := &http.Request{ 52 Method: "GET", 53 URL: u, 54 } 55 c := http.Client{} 56 resp, err := c.Do(req) 57 if err != nil { 58 return nil, nil, err 59 } 60 if resp.StatusCode != 200 { 61 return nil, nil, a.getErrorMsg(resp) 62 } 63 decoder := json.NewDecoder(resp.Body) 64 var files []*AllocFileInfo 65 if err := decoder.Decode(&files); err != nil { 66 return nil, nil, err 67 } 68 return files, nil, nil 69 } 70 71 // Stat is used to stat a file at a given path of an allocation directory 72 func (a *AllocFS) Stat(alloc *Allocation, path string, q *QueryOptions) (*AllocFileInfo, *QueryMeta, error) { 73 node, _, err := a.client.Nodes().Info(alloc.NodeID, &QueryOptions{}) 74 if err != nil { 75 return nil, nil, err 76 } 77 78 if node.HTTPAddr == "" { 79 return nil, nil, fmt.Errorf("http addr of the node where alloc %q is running is not advertised", alloc.ID) 80 } 81 u := &url.URL{ 82 Scheme: "http", 83 Host: node.HTTPAddr, 84 Path: fmt.Sprintf("/v1/client/fs/stat/%s", alloc.ID), 85 } 86 v := url.Values{} 87 v.Set("path", path) 88 u.RawQuery = v.Encode() 89 req := &http.Request{ 90 Method: "GET", 91 URL: u, 92 } 93 c := http.Client{} 94 resp, err := c.Do(req) 95 if err != nil { 96 return nil, nil, err 97 } 98 if resp.StatusCode != 200 { 99 return nil, nil, a.getErrorMsg(resp) 100 } 101 decoder := json.NewDecoder(resp.Body) 102 var file *AllocFileInfo 103 if err := decoder.Decode(&file); err != nil { 104 return nil, nil, err 105 } 106 return file, nil, nil 107 } 108 109 // ReadAt is used to read bytes at a given offset until limit at the given path 110 // in an allocation directory 111 func (a *AllocFS) ReadAt(alloc *Allocation, path string, offset int64, limit int64, q *QueryOptions) (io.Reader, *QueryMeta, error) { 112 node, _, err := a.client.Nodes().Info(alloc.NodeID, &QueryOptions{}) 113 if err != nil { 114 return nil, nil, err 115 } 116 117 if node.HTTPAddr == "" { 118 return nil, nil, fmt.Errorf("http addr of the node where alloc %q is running is not advertised", alloc.ID) 119 } 120 u := &url.URL{ 121 Scheme: "http", 122 Host: node.HTTPAddr, 123 Path: fmt.Sprintf("/v1/client/fs/readat/%s", alloc.ID), 124 } 125 v := url.Values{} 126 v.Set("path", path) 127 v.Set("offset", strconv.FormatInt(offset, 10)) 128 v.Set("limit", strconv.FormatInt(limit, 10)) 129 u.RawQuery = v.Encode() 130 req := &http.Request{ 131 Method: "GET", 132 URL: u, 133 } 134 c := http.Client{} 135 resp, err := c.Do(req) 136 if err != nil { 137 return nil, nil, err 138 } 139 return resp.Body, nil, nil 140 } 141 142 // Cat is used to read contents of a file at the given path in an allocation 143 // directory 144 func (a *AllocFS) Cat(alloc *Allocation, path string, q *QueryOptions) (io.Reader, *QueryMeta, error) { 145 node, _, err := a.client.Nodes().Info(alloc.NodeID, &QueryOptions{}) 146 if err != nil { 147 return nil, nil, err 148 } 149 150 if node.HTTPAddr == "" { 151 return nil, nil, fmt.Errorf("http addr of the node where alloc %q is running is not advertised", alloc.ID) 152 } 153 u := &url.URL{ 154 Scheme: "http", 155 Host: node.HTTPAddr, 156 Path: fmt.Sprintf("/v1/client/fs/cat/%s", alloc.ID), 157 } 158 v := url.Values{} 159 v.Set("path", path) 160 u.RawQuery = v.Encode() 161 req := &http.Request{ 162 Method: "GET", 163 URL: u, 164 } 165 c := http.Client{} 166 resp, err := c.Do(req) 167 if err != nil { 168 return nil, nil, err 169 } 170 return resp.Body, nil, nil 171 } 172 173 func (a *AllocFS) getErrorMsg(resp *http.Response) error { 174 if errMsg, err := ioutil.ReadAll(resp.Body); err == nil { 175 return fmt.Errorf(string(errMsg)) 176 } else { 177 return err 178 } 179 }