client.go 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995
  1. // Copyright 2015 go-dockerclient authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. // Package docker provides a client for the Docker remote API.
  5. //
  6. // See https://goo.gl/G3plxW for more details on the remote API.
  7. package docker
  8. import (
  9. "bufio"
  10. "bytes"
  11. "crypto/tls"
  12. "crypto/x509"
  13. "encoding/json"
  14. "errors"
  15. "fmt"
  16. "io"
  17. "io/ioutil"
  18. "net"
  19. "net/http"
  20. "net/http/httputil"
  21. "net/url"
  22. "os"
  23. "path/filepath"
  24. "reflect"
  25. "runtime"
  26. "strconv"
  27. "strings"
  28. "sync/atomic"
  29. "time"
  30. "github.com/fsouza/go-dockerclient/external/github.com/docker/docker/opts"
  31. "github.com/fsouza/go-dockerclient/external/github.com/docker/docker/pkg/homedir"
  32. "github.com/fsouza/go-dockerclient/external/github.com/docker/docker/pkg/stdcopy"
  33. "github.com/fsouza/go-dockerclient/external/github.com/hashicorp/go-cleanhttp"
  34. )
  35. const userAgent = "go-dockerclient"
  36. var (
  37. // ErrInvalidEndpoint is returned when the endpoint is not a valid HTTP URL.
  38. ErrInvalidEndpoint = errors.New("invalid endpoint")
  39. // ErrConnectionRefused is returned when the client cannot connect to the given endpoint.
  40. ErrConnectionRefused = errors.New("cannot connect to Docker endpoint")
  41. // ErrInactivityTimeout is returned when a streamable call has been inactive for some time.
  42. ErrInactivityTimeout = errors.New("inactivity time exceeded timeout")
  43. apiVersion112, _ = NewAPIVersion("1.12")
  44. apiVersion119, _ = NewAPIVersion("1.19")
  45. )
  46. // APIVersion is an internal representation of a version of the Remote API.
  47. type APIVersion []int
  48. // NewAPIVersion returns an instance of APIVersion for the given string.
  49. //
  50. // The given string must be in the form <major>.<minor>.<patch>, where <major>,
  51. // <minor> and <patch> are integer numbers.
  52. func NewAPIVersion(input string) (APIVersion, error) {
  53. if !strings.Contains(input, ".") {
  54. return nil, fmt.Errorf("Unable to parse version %q", input)
  55. }
  56. raw := strings.Split(input, "-")
  57. arr := strings.Split(raw[0], ".")
  58. ret := make(APIVersion, len(arr))
  59. var err error
  60. for i, val := range arr {
  61. ret[i], err = strconv.Atoi(val)
  62. if err != nil {
  63. return nil, fmt.Errorf("Unable to parse version %q: %q is not an integer", input, val)
  64. }
  65. }
  66. return ret, nil
  67. }
  68. func (version APIVersion) String() string {
  69. var str string
  70. for i, val := range version {
  71. str += strconv.Itoa(val)
  72. if i < len(version)-1 {
  73. str += "."
  74. }
  75. }
  76. return str
  77. }
  78. // LessThan is a function for comparing APIVersion structs
  79. func (version APIVersion) LessThan(other APIVersion) bool {
  80. return version.compare(other) < 0
  81. }
  82. // LessThanOrEqualTo is a function for comparing APIVersion structs
  83. func (version APIVersion) LessThanOrEqualTo(other APIVersion) bool {
  84. return version.compare(other) <= 0
  85. }
  86. // GreaterThan is a function for comparing APIVersion structs
  87. func (version APIVersion) GreaterThan(other APIVersion) bool {
  88. return version.compare(other) > 0
  89. }
  90. // GreaterThanOrEqualTo is a function for comparing APIVersion structs
  91. func (version APIVersion) GreaterThanOrEqualTo(other APIVersion) bool {
  92. return version.compare(other) >= 0
  93. }
  94. func (version APIVersion) compare(other APIVersion) int {
  95. for i, v := range version {
  96. if i <= len(other)-1 {
  97. otherVersion := other[i]
  98. if v < otherVersion {
  99. return -1
  100. } else if v > otherVersion {
  101. return 1
  102. }
  103. }
  104. }
  105. if len(version) > len(other) {
  106. return 1
  107. }
  108. if len(version) < len(other) {
  109. return -1
  110. }
  111. return 0
  112. }
  113. // Client is the basic type of this package. It provides methods for
  114. // interaction with the API.
  115. type Client struct {
  116. SkipServerVersionCheck bool
  117. HTTPClient *http.Client
  118. TLSConfig *tls.Config
  119. Dialer *net.Dialer
  120. endpoint string
  121. endpointURL *url.URL
  122. eventMonitor *eventMonitoringState
  123. requestedAPIVersion APIVersion
  124. serverAPIVersion APIVersion
  125. expectedAPIVersion APIVersion
  126. unixHTTPClient *http.Client
  127. }
  128. // NewClient returns a Client instance ready for communication with the given
  129. // server endpoint. It will use the latest remote API version available in the
  130. // server.
  131. func NewClient(endpoint string) (*Client, error) {
  132. client, err := NewVersionedClient(endpoint, "")
  133. if err != nil {
  134. return nil, err
  135. }
  136. client.SkipServerVersionCheck = true
  137. return client, nil
  138. }
  139. // NewTLSClient returns a Client instance ready for TLS communications with the givens
  140. // server endpoint, key and certificates . It will use the latest remote API version
  141. // available in the server.
  142. func NewTLSClient(endpoint string, cert, key, ca string) (*Client, error) {
  143. client, err := NewVersionedTLSClient(endpoint, cert, key, ca, "")
  144. if err != nil {
  145. return nil, err
  146. }
  147. client.SkipServerVersionCheck = true
  148. return client, nil
  149. }
  150. // NewTLSClientFromBytes returns a Client instance ready for TLS communications with the givens
  151. // server endpoint, key and certificates (passed inline to the function as opposed to being
  152. // read from a local file). It will use the latest remote API version available in the server.
  153. func NewTLSClientFromBytes(endpoint string, certPEMBlock, keyPEMBlock, caPEMCert []byte) (*Client, error) {
  154. client, err := NewVersionedTLSClientFromBytes(endpoint, certPEMBlock, keyPEMBlock, caPEMCert, "")
  155. if err != nil {
  156. return nil, err
  157. }
  158. client.SkipServerVersionCheck = true
  159. return client, nil
  160. }
  161. // NewVersionedClient returns a Client instance ready for communication with
  162. // the given server endpoint, using a specific remote API version.
  163. func NewVersionedClient(endpoint string, apiVersionString string) (*Client, error) {
  164. u, err := parseEndpoint(endpoint, false)
  165. if err != nil {
  166. return nil, err
  167. }
  168. var requestedAPIVersion APIVersion
  169. if strings.Contains(apiVersionString, ".") {
  170. requestedAPIVersion, err = NewAPIVersion(apiVersionString)
  171. if err != nil {
  172. return nil, err
  173. }
  174. }
  175. return &Client{
  176. HTTPClient: cleanhttp.DefaultClient(),
  177. Dialer: &net.Dialer{},
  178. endpoint: endpoint,
  179. endpointURL: u,
  180. eventMonitor: new(eventMonitoringState),
  181. requestedAPIVersion: requestedAPIVersion,
  182. }, nil
  183. }
  184. // NewVersionnedTLSClient has been DEPRECATED, please use NewVersionedTLSClient.
  185. func NewVersionnedTLSClient(endpoint string, cert, key, ca, apiVersionString string) (*Client, error) {
  186. return NewVersionedTLSClient(endpoint, cert, key, ca, apiVersionString)
  187. }
  188. // NewVersionedTLSClient returns a Client instance ready for TLS communications with the givens
  189. // server endpoint, key and certificates, using a specific remote API version.
  190. func NewVersionedTLSClient(endpoint string, cert, key, ca, apiVersionString string) (*Client, error) {
  191. certPEMBlock, err := ioutil.ReadFile(cert)
  192. if err != nil {
  193. return nil, err
  194. }
  195. keyPEMBlock, err := ioutil.ReadFile(key)
  196. if err != nil {
  197. return nil, err
  198. }
  199. caPEMCert, err := ioutil.ReadFile(ca)
  200. if err != nil {
  201. return nil, err
  202. }
  203. return NewVersionedTLSClientFromBytes(endpoint, certPEMBlock, keyPEMBlock, caPEMCert, apiVersionString)
  204. }
  205. // NewClientFromEnv returns a Client instance ready for communication created from
  206. // Docker's default logic for the environment variables DOCKER_HOST, DOCKER_TLS_VERIFY, and DOCKER_CERT_PATH.
  207. //
  208. // See https://github.com/docker/docker/blob/1f963af697e8df3a78217f6fdbf67b8123a7db94/docker/docker.go#L68.
  209. // See https://github.com/docker/compose/blob/81707ef1ad94403789166d2fe042c8a718a4c748/compose/cli/docker_client.py#L7.
  210. func NewClientFromEnv() (*Client, error) {
  211. client, err := NewVersionedClientFromEnv("")
  212. if err != nil {
  213. return nil, err
  214. }
  215. client.SkipServerVersionCheck = true
  216. return client, nil
  217. }
  218. // NewVersionedClientFromEnv returns a Client instance ready for TLS communications created from
  219. // Docker's default logic for the environment variables DOCKER_HOST, DOCKER_TLS_VERIFY, and DOCKER_CERT_PATH,
  220. // and using a specific remote API version.
  221. //
  222. // See https://github.com/docker/docker/blob/1f963af697e8df3a78217f6fdbf67b8123a7db94/docker/docker.go#L68.
  223. // See https://github.com/docker/compose/blob/81707ef1ad94403789166d2fe042c8a718a4c748/compose/cli/docker_client.py#L7.
  224. func NewVersionedClientFromEnv(apiVersionString string) (*Client, error) {
  225. dockerEnv, err := getDockerEnv()
  226. if err != nil {
  227. return nil, err
  228. }
  229. dockerHost := dockerEnv.dockerHost
  230. if dockerEnv.dockerTLSVerify {
  231. parts := strings.SplitN(dockerEnv.dockerHost, "://", 2)
  232. if len(parts) != 2 {
  233. return nil, fmt.Errorf("could not split %s into two parts by ://", dockerHost)
  234. }
  235. cert := filepath.Join(dockerEnv.dockerCertPath, "cert.pem")
  236. key := filepath.Join(dockerEnv.dockerCertPath, "key.pem")
  237. ca := filepath.Join(dockerEnv.dockerCertPath, "ca.pem")
  238. return NewVersionedTLSClient(dockerEnv.dockerHost, cert, key, ca, apiVersionString)
  239. }
  240. return NewVersionedClient(dockerEnv.dockerHost, apiVersionString)
  241. }
  242. // NewVersionedTLSClientFromBytes returns a Client instance ready for TLS communications with the givens
  243. // server endpoint, key and certificates (passed inline to the function as opposed to being
  244. // read from a local file), using a specific remote API version.
  245. func NewVersionedTLSClientFromBytes(endpoint string, certPEMBlock, keyPEMBlock, caPEMCert []byte, apiVersionString string) (*Client, error) {
  246. u, err := parseEndpoint(endpoint, true)
  247. if err != nil {
  248. return nil, err
  249. }
  250. var requestedAPIVersion APIVersion
  251. if strings.Contains(apiVersionString, ".") {
  252. requestedAPIVersion, err = NewAPIVersion(apiVersionString)
  253. if err != nil {
  254. return nil, err
  255. }
  256. }
  257. if certPEMBlock == nil || keyPEMBlock == nil {
  258. return nil, errors.New("Both cert and key are required")
  259. }
  260. tlsCert, err := tls.X509KeyPair(certPEMBlock, keyPEMBlock)
  261. if err != nil {
  262. return nil, err
  263. }
  264. tlsConfig := &tls.Config{Certificates: []tls.Certificate{tlsCert}}
  265. if caPEMCert == nil {
  266. tlsConfig.InsecureSkipVerify = true
  267. } else {
  268. caPool := x509.NewCertPool()
  269. if !caPool.AppendCertsFromPEM(caPEMCert) {
  270. return nil, errors.New("Could not add RootCA pem")
  271. }
  272. tlsConfig.RootCAs = caPool
  273. }
  274. tr := cleanhttp.DefaultTransport()
  275. tr.TLSClientConfig = tlsConfig
  276. if err != nil {
  277. return nil, err
  278. }
  279. return &Client{
  280. HTTPClient: &http.Client{Transport: tr},
  281. TLSConfig: tlsConfig,
  282. Dialer: &net.Dialer{},
  283. endpoint: endpoint,
  284. endpointURL: u,
  285. eventMonitor: new(eventMonitoringState),
  286. requestedAPIVersion: requestedAPIVersion,
  287. }, nil
  288. }
  289. func (c *Client) checkAPIVersion() error {
  290. serverAPIVersionString, err := c.getServerAPIVersionString()
  291. if err != nil {
  292. return err
  293. }
  294. c.serverAPIVersion, err = NewAPIVersion(serverAPIVersionString)
  295. if err != nil {
  296. return err
  297. }
  298. if c.requestedAPIVersion == nil {
  299. c.expectedAPIVersion = c.serverAPIVersion
  300. } else {
  301. c.expectedAPIVersion = c.requestedAPIVersion
  302. }
  303. return nil
  304. }
  305. // Endpoint returns the current endpoint. It's useful for getting the endpoint
  306. // when using functions that get this data from the environment (like
  307. // NewClientFromEnv.
  308. func (c *Client) Endpoint() string {
  309. return c.endpoint
  310. }
  311. // Ping pings the docker server
  312. //
  313. // See https://goo.gl/kQCfJj for more details.
  314. func (c *Client) Ping() error {
  315. path := "/_ping"
  316. resp, err := c.do("GET", path, doOptions{})
  317. if err != nil {
  318. return err
  319. }
  320. if resp.StatusCode != http.StatusOK {
  321. return newError(resp)
  322. }
  323. resp.Body.Close()
  324. return nil
  325. }
  326. func (c *Client) getServerAPIVersionString() (version string, err error) {
  327. resp, err := c.do("GET", "/version", doOptions{})
  328. if err != nil {
  329. return "", err
  330. }
  331. defer resp.Body.Close()
  332. if resp.StatusCode != http.StatusOK {
  333. return "", fmt.Errorf("Received unexpected status %d while trying to retrieve the server version", resp.StatusCode)
  334. }
  335. var versionResponse map[string]interface{}
  336. if err := json.NewDecoder(resp.Body).Decode(&versionResponse); err != nil {
  337. return "", err
  338. }
  339. if version, ok := (versionResponse["ApiVersion"]).(string); ok {
  340. return version, nil
  341. }
  342. return "", nil
  343. }
  344. type doOptions struct {
  345. data interface{}
  346. forceJSON bool
  347. headers map[string]string
  348. }
  349. func (c *Client) do(method, path string, doOptions doOptions) (*http.Response, error) {
  350. var params io.Reader
  351. if doOptions.data != nil || doOptions.forceJSON {
  352. buf, err := json.Marshal(doOptions.data)
  353. if err != nil {
  354. return nil, err
  355. }
  356. params = bytes.NewBuffer(buf)
  357. }
  358. if path != "/version" && !c.SkipServerVersionCheck && c.expectedAPIVersion == nil {
  359. err := c.checkAPIVersion()
  360. if err != nil {
  361. return nil, err
  362. }
  363. }
  364. httpClient := c.HTTPClient
  365. protocol := c.endpointURL.Scheme
  366. var u string
  367. if protocol == "unix" {
  368. httpClient = c.unixClient()
  369. u = c.getFakeUnixURL(path)
  370. } else {
  371. u = c.getURL(path)
  372. }
  373. req, err := http.NewRequest(method, u, params)
  374. if err != nil {
  375. return nil, err
  376. }
  377. req.Header.Set("User-Agent", userAgent)
  378. if doOptions.data != nil {
  379. req.Header.Set("Content-Type", "application/json")
  380. } else if method == "POST" {
  381. req.Header.Set("Content-Type", "plain/text")
  382. }
  383. for k, v := range doOptions.headers {
  384. req.Header.Set(k, v)
  385. }
  386. resp, err := httpClient.Do(req)
  387. if err != nil {
  388. if strings.Contains(err.Error(), "connection refused") {
  389. return nil, ErrConnectionRefused
  390. }
  391. return nil, err
  392. }
  393. if resp.StatusCode < 200 || resp.StatusCode >= 400 {
  394. return nil, newError(resp)
  395. }
  396. return resp, nil
  397. }
  398. type streamOptions struct {
  399. setRawTerminal bool
  400. rawJSONStream bool
  401. useJSONDecoder bool
  402. headers map[string]string
  403. in io.Reader
  404. stdout io.Writer
  405. stderr io.Writer
  406. // timeout is the initial connection timeout
  407. timeout time.Duration
  408. // Timeout with no data is received, it's reset every time new data
  409. // arrives
  410. inactivityTimeout time.Duration
  411. }
  412. func (c *Client) stream(method, path string, streamOptions streamOptions) error {
  413. if (method == "POST" || method == "PUT") && streamOptions.in == nil {
  414. streamOptions.in = bytes.NewReader(nil)
  415. }
  416. if path != "/version" && !c.SkipServerVersionCheck && c.expectedAPIVersion == nil {
  417. err := c.checkAPIVersion()
  418. if err != nil {
  419. return err
  420. }
  421. }
  422. req, err := http.NewRequest(method, c.getURL(path), streamOptions.in)
  423. if err != nil {
  424. return err
  425. }
  426. req.Header.Set("User-Agent", userAgent)
  427. if method == "POST" {
  428. req.Header.Set("Content-Type", "plain/text")
  429. }
  430. for key, val := range streamOptions.headers {
  431. req.Header.Set(key, val)
  432. }
  433. var resp *http.Response
  434. protocol := c.endpointURL.Scheme
  435. address := c.endpointURL.Path
  436. if streamOptions.stdout == nil {
  437. streamOptions.stdout = ioutil.Discard
  438. }
  439. if streamOptions.stderr == nil {
  440. streamOptions.stderr = ioutil.Discard
  441. }
  442. cancelRequest := cancelable(c.HTTPClient, req)
  443. if protocol == "unix" {
  444. dial, err := c.Dialer.Dial(protocol, address)
  445. if err != nil {
  446. return err
  447. }
  448. cancelRequest = func() { dial.Close() }
  449. defer dial.Close()
  450. breader := bufio.NewReader(dial)
  451. err = req.Write(dial)
  452. if err != nil {
  453. return err
  454. }
  455. // ReadResponse may hang if server does not replay
  456. if streamOptions.timeout > 0 {
  457. dial.SetDeadline(time.Now().Add(streamOptions.timeout))
  458. }
  459. if resp, err = http.ReadResponse(breader, req); err != nil {
  460. // Cancel timeout for future I/O operations
  461. if streamOptions.timeout > 0 {
  462. dial.SetDeadline(time.Time{})
  463. }
  464. if strings.Contains(err.Error(), "connection refused") {
  465. return ErrConnectionRefused
  466. }
  467. return err
  468. }
  469. } else {
  470. if resp, err = c.HTTPClient.Do(req); err != nil {
  471. if strings.Contains(err.Error(), "connection refused") {
  472. return ErrConnectionRefused
  473. }
  474. return err
  475. }
  476. }
  477. defer resp.Body.Close()
  478. if resp.StatusCode < 200 || resp.StatusCode >= 400 {
  479. return newError(resp)
  480. }
  481. var canceled uint32
  482. if streamOptions.inactivityTimeout > 0 {
  483. ch := handleInactivityTimeout(&streamOptions, cancelRequest, &canceled)
  484. defer close(ch)
  485. }
  486. err = handleStreamResponse(resp, &streamOptions)
  487. if err != nil {
  488. if atomic.LoadUint32(&canceled) != 0 {
  489. return ErrInactivityTimeout
  490. }
  491. return err
  492. }
  493. return nil
  494. }
  495. func handleStreamResponse(resp *http.Response, streamOptions *streamOptions) error {
  496. var err error
  497. if !streamOptions.useJSONDecoder && resp.Header.Get("Content-Type") != "application/json" {
  498. if streamOptions.setRawTerminal {
  499. _, err = io.Copy(streamOptions.stdout, resp.Body)
  500. } else {
  501. _, err = stdcopy.StdCopy(streamOptions.stdout, streamOptions.stderr, resp.Body)
  502. }
  503. return err
  504. }
  505. // if we want to get raw json stream, just copy it back to output
  506. // without decoding it
  507. if streamOptions.rawJSONStream {
  508. _, err = io.Copy(streamOptions.stdout, resp.Body)
  509. return err
  510. }
  511. dec := json.NewDecoder(resp.Body)
  512. for {
  513. var m jsonMessage
  514. if err := dec.Decode(&m); err == io.EOF {
  515. break
  516. } else if err != nil {
  517. return err
  518. }
  519. if m.Stream != "" {
  520. fmt.Fprint(streamOptions.stdout, m.Stream)
  521. } else if m.Progress != "" {
  522. fmt.Fprintf(streamOptions.stdout, "%s %s\r", m.Status, m.Progress)
  523. } else if m.Error != "" {
  524. return errors.New(m.Error)
  525. }
  526. if m.Status != "" {
  527. fmt.Fprintln(streamOptions.stdout, m.Status)
  528. }
  529. }
  530. return nil
  531. }
  532. type proxyWriter struct {
  533. io.Writer
  534. calls uint64
  535. }
  536. func (p *proxyWriter) callCount() uint64 {
  537. return atomic.LoadUint64(&p.calls)
  538. }
  539. func (p *proxyWriter) Write(data []byte) (int, error) {
  540. atomic.AddUint64(&p.calls, 1)
  541. return p.Writer.Write(data)
  542. }
  543. func handleInactivityTimeout(options *streamOptions, cancelRequest func(), canceled *uint32) chan<- struct{} {
  544. done := make(chan struct{})
  545. proxyStdout := &proxyWriter{Writer: options.stdout}
  546. proxyStderr := &proxyWriter{Writer: options.stderr}
  547. options.stdout = proxyStdout
  548. options.stderr = proxyStderr
  549. go func() {
  550. var lastCallCount uint64
  551. for {
  552. select {
  553. case <-time.After(options.inactivityTimeout):
  554. case <-done:
  555. return
  556. }
  557. curCallCount := proxyStdout.callCount() + proxyStderr.callCount()
  558. if curCallCount == lastCallCount {
  559. atomic.AddUint32(canceled, 1)
  560. cancelRequest()
  561. return
  562. }
  563. lastCallCount = curCallCount
  564. }
  565. }()
  566. return done
  567. }
  568. type hijackOptions struct {
  569. success chan struct{}
  570. setRawTerminal bool
  571. in io.Reader
  572. stdout io.Writer
  573. stderr io.Writer
  574. data interface{}
  575. }
  576. // CloseWaiter is an interface with methods for closing the underlying resource
  577. // and then waiting for it to finish processing.
  578. type CloseWaiter interface {
  579. io.Closer
  580. Wait() error
  581. }
  582. type waiterFunc func() error
  583. func (w waiterFunc) Wait() error { return w() }
  584. type closerFunc func() error
  585. func (c closerFunc) Close() error { return c() }
  586. func (c *Client) hijack(method, path string, hijackOptions hijackOptions) (CloseWaiter, error) {
  587. if path != "/version" && !c.SkipServerVersionCheck && c.expectedAPIVersion == nil {
  588. err := c.checkAPIVersion()
  589. if err != nil {
  590. return nil, err
  591. }
  592. }
  593. var params io.Reader
  594. if hijackOptions.data != nil {
  595. buf, err := json.Marshal(hijackOptions.data)
  596. if err != nil {
  597. return nil, err
  598. }
  599. params = bytes.NewBuffer(buf)
  600. }
  601. req, err := http.NewRequest(method, c.getURL(path), params)
  602. if err != nil {
  603. return nil, err
  604. }
  605. req.Header.Set("Content-Type", "application/json")
  606. req.Header.Set("Connection", "Upgrade")
  607. req.Header.Set("Upgrade", "tcp")
  608. protocol := c.endpointURL.Scheme
  609. address := c.endpointURL.Path
  610. if protocol != "unix" {
  611. protocol = "tcp"
  612. address = c.endpointURL.Host
  613. }
  614. var dial net.Conn
  615. if c.TLSConfig != nil && protocol != "unix" {
  616. dial, err = tlsDialWithDialer(c.Dialer, protocol, address, c.TLSConfig)
  617. if err != nil {
  618. return nil, err
  619. }
  620. } else {
  621. dial, err = c.Dialer.Dial(protocol, address)
  622. if err != nil {
  623. return nil, err
  624. }
  625. }
  626. errs := make(chan error)
  627. quit := make(chan struct{})
  628. go func() {
  629. clientconn := httputil.NewClientConn(dial, nil)
  630. defer clientconn.Close()
  631. clientconn.Do(req)
  632. if hijackOptions.success != nil {
  633. hijackOptions.success <- struct{}{}
  634. <-hijackOptions.success
  635. }
  636. rwc, br := clientconn.Hijack()
  637. defer rwc.Close()
  638. errChanOut := make(chan error, 1)
  639. errChanIn := make(chan error, 1)
  640. if hijackOptions.stdout == nil && hijackOptions.stderr == nil {
  641. close(errChanOut)
  642. } else {
  643. // Only copy if hijackOptions.stdout and/or hijackOptions.stderr is actually set.
  644. // Otherwise, if the only stream you care about is stdin, your attach session
  645. // will "hang" until the container terminates, even though you're not reading
  646. // stdout/stderr
  647. if hijackOptions.stdout == nil {
  648. hijackOptions.stdout = ioutil.Discard
  649. }
  650. if hijackOptions.stderr == nil {
  651. hijackOptions.stderr = ioutil.Discard
  652. }
  653. go func() {
  654. defer func() {
  655. if hijackOptions.in != nil {
  656. if closer, ok := hijackOptions.in.(io.Closer); ok {
  657. closer.Close()
  658. }
  659. errChanIn <- nil
  660. }
  661. }()
  662. var err error
  663. if hijackOptions.setRawTerminal {
  664. _, err = io.Copy(hijackOptions.stdout, br)
  665. } else {
  666. _, err = stdcopy.StdCopy(hijackOptions.stdout, hijackOptions.stderr, br)
  667. }
  668. errChanOut <- err
  669. }()
  670. }
  671. go func() {
  672. var err error
  673. if hijackOptions.in != nil {
  674. _, err = io.Copy(rwc, hijackOptions.in)
  675. }
  676. errChanIn <- err
  677. rwc.(interface {
  678. CloseWrite() error
  679. }).CloseWrite()
  680. }()
  681. var errIn error
  682. select {
  683. case errIn = <-errChanIn:
  684. case <-quit:
  685. return
  686. }
  687. var errOut error
  688. select {
  689. case errOut = <-errChanOut:
  690. case <-quit:
  691. return
  692. }
  693. if errIn != nil {
  694. errs <- errIn
  695. } else {
  696. errs <- errOut
  697. }
  698. }()
  699. return struct {
  700. closerFunc
  701. waiterFunc
  702. }{
  703. closerFunc(func() error { close(quit); return nil }),
  704. waiterFunc(func() error { return <-errs }),
  705. }, nil
  706. }
  707. func (c *Client) getURL(path string) string {
  708. urlStr := strings.TrimRight(c.endpointURL.String(), "/")
  709. if c.endpointURL.Scheme == "unix" {
  710. urlStr = ""
  711. }
  712. if c.requestedAPIVersion != nil {
  713. return fmt.Sprintf("%s/v%s%s", urlStr, c.requestedAPIVersion, path)
  714. }
  715. return fmt.Sprintf("%s%s", urlStr, path)
  716. }
  717. // getFakeUnixURL returns the URL needed to make an HTTP request over a UNIX
  718. // domain socket to the given path.
  719. func (c *Client) getFakeUnixURL(path string) string {
  720. u := *c.endpointURL // Copy.
  721. // Override URL so that net/http will not complain.
  722. u.Scheme = "http"
  723. u.Host = "unix.sock" // Doesn't matter what this is - it's not used.
  724. u.Path = ""
  725. urlStr := strings.TrimRight(u.String(), "/")
  726. if c.requestedAPIVersion != nil {
  727. return fmt.Sprintf("%s/v%s%s", urlStr, c.requestedAPIVersion, path)
  728. }
  729. return fmt.Sprintf("%s%s", urlStr, path)
  730. }
  731. func (c *Client) unixClient() *http.Client {
  732. if c.unixHTTPClient != nil {
  733. return c.unixHTTPClient
  734. }
  735. socketPath := c.endpointURL.Path
  736. tr := &http.Transport{
  737. Dial: func(network, addr string) (net.Conn, error) {
  738. return c.Dialer.Dial("unix", socketPath)
  739. },
  740. }
  741. cleanhttp.SetTransportFinalizer(tr)
  742. c.unixHTTPClient = &http.Client{Transport: tr}
  743. return c.unixHTTPClient
  744. }
  745. type jsonMessage struct {
  746. Status string `json:"status,omitempty"`
  747. Progress string `json:"progress,omitempty"`
  748. Error string `json:"error,omitempty"`
  749. Stream string `json:"stream,omitempty"`
  750. }
  751. func queryString(opts interface{}) string {
  752. if opts == nil {
  753. return ""
  754. }
  755. value := reflect.ValueOf(opts)
  756. if value.Kind() == reflect.Ptr {
  757. value = value.Elem()
  758. }
  759. if value.Kind() != reflect.Struct {
  760. return ""
  761. }
  762. items := url.Values(map[string][]string{})
  763. for i := 0; i < value.NumField(); i++ {
  764. field := value.Type().Field(i)
  765. if field.PkgPath != "" {
  766. continue
  767. }
  768. key := field.Tag.Get("qs")
  769. if key == "" {
  770. key = strings.ToLower(field.Name)
  771. } else if key == "-" {
  772. continue
  773. }
  774. addQueryStringValue(items, key, value.Field(i))
  775. }
  776. return items.Encode()
  777. }
  778. func addQueryStringValue(items url.Values, key string, v reflect.Value) {
  779. switch v.Kind() {
  780. case reflect.Bool:
  781. if v.Bool() {
  782. items.Add(key, "1")
  783. }
  784. case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
  785. if v.Int() > 0 {
  786. items.Add(key, strconv.FormatInt(v.Int(), 10))
  787. }
  788. case reflect.Float32, reflect.Float64:
  789. if v.Float() > 0 {
  790. items.Add(key, strconv.FormatFloat(v.Float(), 'f', -1, 64))
  791. }
  792. case reflect.String:
  793. if v.String() != "" {
  794. items.Add(key, v.String())
  795. }
  796. case reflect.Ptr:
  797. if !v.IsNil() {
  798. if b, err := json.Marshal(v.Interface()); err == nil {
  799. items.Add(key, string(b))
  800. }
  801. }
  802. case reflect.Map:
  803. if len(v.MapKeys()) > 0 {
  804. if b, err := json.Marshal(v.Interface()); err == nil {
  805. items.Add(key, string(b))
  806. }
  807. }
  808. case reflect.Array, reflect.Slice:
  809. vLen := v.Len()
  810. if vLen > 0 {
  811. for i := 0; i < vLen; i++ {
  812. addQueryStringValue(items, key, v.Index(i))
  813. }
  814. }
  815. }
  816. }
  817. // Error represents failures in the API. It represents a failure from the API.
  818. type Error struct {
  819. Status int
  820. Message string
  821. }
  822. func newError(resp *http.Response) *Error {
  823. defer resp.Body.Close()
  824. data, err := ioutil.ReadAll(resp.Body)
  825. if err != nil {
  826. return &Error{Status: resp.StatusCode, Message: fmt.Sprintf("cannot read body, err: %v", err)}
  827. }
  828. return &Error{Status: resp.StatusCode, Message: string(data)}
  829. }
  830. func (e *Error) Error() string {
  831. return fmt.Sprintf("API error (%d): %s", e.Status, e.Message)
  832. }
  833. func parseEndpoint(endpoint string, tls bool) (*url.URL, error) {
  834. if endpoint != "" && !strings.Contains(endpoint, "://") {
  835. endpoint = "tcp://" + endpoint
  836. }
  837. u, err := url.Parse(endpoint)
  838. if err != nil {
  839. return nil, ErrInvalidEndpoint
  840. }
  841. if tls {
  842. u.Scheme = "https"
  843. }
  844. switch u.Scheme {
  845. case "unix":
  846. return u, nil
  847. case "http", "https", "tcp":
  848. _, port, err := net.SplitHostPort(u.Host)
  849. if err != nil {
  850. if e, ok := err.(*net.AddrError); ok {
  851. if e.Err == "missing port in address" {
  852. return u, nil
  853. }
  854. }
  855. return nil, ErrInvalidEndpoint
  856. }
  857. number, err := strconv.ParseInt(port, 10, 64)
  858. if err == nil && number > 0 && number < 65536 {
  859. if u.Scheme == "tcp" {
  860. if tls {
  861. u.Scheme = "https"
  862. } else {
  863. u.Scheme = "http"
  864. }
  865. }
  866. return u, nil
  867. }
  868. return nil, ErrInvalidEndpoint
  869. default:
  870. return nil, ErrInvalidEndpoint
  871. }
  872. }
  873. type dockerEnv struct {
  874. dockerHost string
  875. dockerTLSVerify bool
  876. dockerCertPath string
  877. }
  878. func getDockerEnv() (*dockerEnv, error) {
  879. dockerHost := os.Getenv("DOCKER_HOST")
  880. var err error
  881. if dockerHost == "" {
  882. dockerHost, err = DefaultDockerHost()
  883. if err != nil {
  884. return nil, err
  885. }
  886. }
  887. dockerTLSVerify := os.Getenv("DOCKER_TLS_VERIFY") != ""
  888. var dockerCertPath string
  889. if dockerTLSVerify {
  890. dockerCertPath = os.Getenv("DOCKER_CERT_PATH")
  891. if dockerCertPath == "" {
  892. home := homedir.Get()
  893. if home == "" {
  894. return nil, errors.New("environment variable HOME must be set if DOCKER_CERT_PATH is not set")
  895. }
  896. dockerCertPath = filepath.Join(home, ".docker")
  897. dockerCertPath, err = filepath.Abs(dockerCertPath)
  898. if err != nil {
  899. return nil, err
  900. }
  901. }
  902. }
  903. return &dockerEnv{
  904. dockerHost: dockerHost,
  905. dockerTLSVerify: dockerTLSVerify,
  906. dockerCertPath: dockerCertPath,
  907. }, nil
  908. }
  909. // DefaultDockerHost returns the default docker socket for the current OS
  910. func DefaultDockerHost() (string, error) {
  911. var defaultHost string
  912. if runtime.GOOS == "windows" {
  913. // If we do not have a host, default to TCP socket on Windows
  914. defaultHost = fmt.Sprintf("tcp://%s:%d", opts.DefaultHTTPHost, opts.DefaultHTTPPort)
  915. } else {
  916. // If we do not have a host, default to unix socket
  917. defaultHost = fmt.Sprintf("unix://%s", opts.DefaultUnixSocket)
  918. }
  919. return opts.ValidateHost(defaultHost)
  920. }