github.com/rentongzhang/docker@v1.8.2-rc1/pkg/plugins/client.go (about) 1 package plugins 2 3 import ( 4 "bytes" 5 "encoding/json" 6 "fmt" 7 "io/ioutil" 8 "net/http" 9 "strings" 10 "time" 11 12 "github.com/Sirupsen/logrus" 13 "github.com/docker/docker/pkg/sockets" 14 "github.com/docker/docker/pkg/tlsconfig" 15 ) 16 17 const ( 18 versionMimetype = "application/vnd.docker.plugins.v1+json" 19 defaultTimeOut = 30 20 ) 21 22 func NewClient(addr string, tlsConfig tlsconfig.Options) (*Client, error) { 23 tr := &http.Transport{} 24 25 c, err := tlsconfig.Client(tlsConfig) 26 if err != nil { 27 return nil, err 28 } 29 tr.TLSClientConfig = c 30 31 protoAndAddr := strings.Split(addr, "://") 32 sockets.ConfigureTCPTransport(tr, protoAndAddr[0], protoAndAddr[1]) 33 return &Client{&http.Client{Transport: tr}, protoAndAddr[1]}, nil 34 } 35 36 type Client struct { 37 http *http.Client 38 addr string 39 } 40 41 func (c *Client) Call(serviceMethod string, args interface{}, ret interface{}) error { 42 return c.callWithRetry(serviceMethod, args, ret, true) 43 } 44 45 func (c *Client) callWithRetry(serviceMethod string, args interface{}, ret interface{}, retry bool) error { 46 var buf bytes.Buffer 47 if err := json.NewEncoder(&buf).Encode(args); err != nil { 48 return err 49 } 50 51 req, err := http.NewRequest("POST", "/"+serviceMethod, &buf) 52 if err != nil { 53 return err 54 } 55 req.Header.Add("Accept", versionMimetype) 56 req.URL.Scheme = "http" 57 req.URL.Host = c.addr 58 59 var retries int 60 start := time.Now() 61 62 for { 63 resp, err := c.http.Do(req) 64 if err != nil { 65 if !retry { 66 return err 67 } 68 69 timeOff := backoff(retries) 70 if abort(start, timeOff) { 71 return err 72 } 73 retries++ 74 logrus.Warnf("Unable to connect to plugin: %s, retrying in %v", c.addr, timeOff) 75 time.Sleep(timeOff) 76 continue 77 } 78 79 defer resp.Body.Close() 80 if resp.StatusCode != http.StatusOK { 81 remoteErr, err := ioutil.ReadAll(resp.Body) 82 if err != nil { 83 return fmt.Errorf("Plugin Error: %s", err) 84 } 85 return fmt.Errorf("Plugin Error: %s", remoteErr) 86 } 87 88 return json.NewDecoder(resp.Body).Decode(&ret) 89 } 90 } 91 92 func backoff(retries int) time.Duration { 93 b, max := 1, defaultTimeOut 94 for b < max && retries > 0 { 95 b *= 2 96 retries-- 97 } 98 if b > max { 99 b = max 100 } 101 return time.Duration(b) * time.Second 102 } 103 104 func abort(start time.Time, timeOff time.Duration) bool { 105 return timeOff+time.Since(start) >= time.Duration(defaultTimeOut)*time.Second 106 }