Merge branch 'patch-1' of https://github.com/mr-c/arvados into mr-c-patch-1
[arvados.git] / sdk / go / arvados / keep_service.go
index 9797440205cf3d8396d14ec389e380b2260486b2..da1710374e1e69ca4bfe6c2f77c8b990a1f7dc4e 100644 (file)
@@ -6,28 +6,33 @@ package arvados
 
 import (
        "bufio"
+       "context"
        "fmt"
+       "io/ioutil"
        "net/http"
        "strconv"
        "strings"
+       "time"
 )
 
 // KeepService is an arvados#keepService record
 type KeepService struct {
-       UUID           string `json:"uuid"`
-       ServiceHost    string `json:"service_host"`
-       ServicePort    int    `json:"service_port"`
-       ServiceSSLFlag bool   `json:"service_ssl_flag"`
-       ServiceType    string `json:"service_type"`
-       ReadOnly       bool   `json:"read_only"`
+       UUID           string    `json:"uuid"`
+       ServiceHost    string    `json:"service_host"`
+       ServicePort    int       `json:"service_port"`
+       ServiceSSLFlag bool      `json:"service_ssl_flag"`
+       ServiceType    string    `json:"service_type"`
+       ReadOnly       bool      `json:"read_only"`
+       CreatedAt      time.Time `json:"created_at"`
+       ModifiedAt     time.Time `json:"modified_at"`
 }
 
 type KeepMount struct {
-       UUID           string   `json:"uuid"`
-       DeviceID       string   `json:"device_id"`
-       ReadOnly       bool     `json:"read_only"`
-       Replication    int      `json:"replication"`
-       StorageClasses []string `json:"storage_classes"`
+       UUID           string          `json:"uuid"`
+       DeviceID       string          `json:"device_id"`
+       ReadOnly       bool            `json:"read_only"`
+       Replication    int             `json:"replication"`
+       StorageClasses map[string]bool `json:"storage_classes"`
 }
 
 // KeepServiceList is an arvados#keepServiceList record
@@ -99,21 +104,57 @@ func (s *KeepService) Mounts(c *Client) ([]KeepMount, error) {
        return mounts, nil
 }
 
+// Touch updates the timestamp on the given block.
+func (s *KeepService) Touch(ctx context.Context, c *Client, blk string) error {
+       req, err := http.NewRequest("TOUCH", s.url(blk), nil)
+       if err != nil {
+               return err
+       }
+       resp, err := c.Do(req.WithContext(ctx))
+       if err != nil {
+               return err
+       }
+       defer resp.Body.Close()
+       if resp.StatusCode != http.StatusOK {
+               body, _ := ioutil.ReadAll(resp.Body)
+               return fmt.Errorf("%s %s: %s", resp.Proto, resp.Status, body)
+       }
+       return nil
+}
+
+// Untrash moves/copies the given block out of trash.
+func (s *KeepService) Untrash(ctx context.Context, c *Client, blk string) error {
+       req, err := http.NewRequest("PUT", s.url("untrash/"+blk), nil)
+       if err != nil {
+               return err
+       }
+       resp, err := c.Do(req.WithContext(ctx))
+       if err != nil {
+               return err
+       }
+       defer resp.Body.Close()
+       if resp.StatusCode != http.StatusOK {
+               body, _ := ioutil.ReadAll(resp.Body)
+               return fmt.Errorf("%s %s: %s", resp.Proto, resp.Status, body)
+       }
+       return nil
+}
+
 // Index returns an unsorted list of blocks at the given mount point.
-func (s *KeepService) IndexMount(c *Client, mountUUID string, prefix string) ([]KeepServiceIndexEntry, error) {
-       return s.index(c, s.url("mounts/"+mountUUID+"/blocks?prefix="+prefix))
+func (s *KeepService) IndexMount(ctx context.Context, c *Client, mountUUID string, prefix string) ([]KeepServiceIndexEntry, error) {
+       return s.index(ctx, c, s.url("mounts/"+mountUUID+"/blocks?prefix="+prefix))
 }
 
 // Index returns an unsorted list of blocks that can be retrieved from
 // this server.
-func (s *KeepService) Index(c *Client, prefix string) ([]KeepServiceIndexEntry, error) {
-       return s.index(c, s.url("index/"+prefix))
+func (s *KeepService) Index(ctx context.Context, c *Client, prefix string) ([]KeepServiceIndexEntry, error) {
+       return s.index(ctx, c, s.url("index/"+prefix))
 }
 
-func (s *KeepService) index(c *Client, url string) ([]KeepServiceIndexEntry, error) {
-       req, err := http.NewRequest("GET", url, nil)
+func (s *KeepService) index(ctx context.Context, c *Client, url string) ([]KeepServiceIndexEntry, error) {
+       req, err := http.NewRequestWithContext(ctx, "GET", url, nil)
        if err != nil {
-               return nil, fmt.Errorf("NewRequest(%v): %v", url, err)
+               return nil, fmt.Errorf("NewRequestWithContext(%v): %v", url, err)
        }
        resp, err := c.Do(req)
        if err != nil {
@@ -127,6 +168,13 @@ func (s *KeepService) index(c *Client, url string) ([]KeepServiceIndexEntry, err
        scanner := bufio.NewScanner(resp.Body)
        sawEOF := false
        for scanner.Scan() {
+               if scanner.Err() != nil {
+                       // If we encounter a read error (timeout,
+                       // connection failure), stop now and return it
+                       // below, so it doesn't get masked by the
+                       // ensuing "badly formatted response" error.
+                       break
+               }
                if sawEOF {
                        return nil, fmt.Errorf("Index response contained non-terminal blank line")
                }