image.go 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642
  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
  5. import (
  6. "bytes"
  7. "encoding/base64"
  8. "encoding/json"
  9. "errors"
  10. "fmt"
  11. "io"
  12. "net/http"
  13. "net/url"
  14. "os"
  15. "time"
  16. )
  17. // APIImages represent an image returned in the ListImages call.
  18. type APIImages struct {
  19. ID string `json:"Id" yaml:"Id"`
  20. RepoTags []string `json:"RepoTags,omitempty" yaml:"RepoTags,omitempty"`
  21. Created int64 `json:"Created,omitempty" yaml:"Created,omitempty"`
  22. Size int64 `json:"Size,omitempty" yaml:"Size,omitempty"`
  23. VirtualSize int64 `json:"VirtualSize,omitempty" yaml:"VirtualSize,omitempty"`
  24. ParentID string `json:"ParentId,omitempty" yaml:"ParentId,omitempty"`
  25. RepoDigests []string `json:"RepoDigests,omitempty" yaml:"RepoDigests,omitempty"`
  26. Labels map[string]string `json:"Labels,omitempty" yaml:"Labels,omitempty"`
  27. }
  28. // RootFS represents the underlying layers used by an image
  29. type RootFS struct {
  30. Type string `json:"Type,omitempty" yaml:"Type,omitempty"`
  31. Layers []string `json:"Layers,omitempty" yaml:"Layers,omitempty"`
  32. }
  33. // Image is the type representing a docker image and its various properties
  34. type Image struct {
  35. ID string `json:"Id" yaml:"Id"`
  36. RepoTags []string `json:"RepoTags,omitempty" yaml:"RepoTags,omitempty"`
  37. Parent string `json:"Parent,omitempty" yaml:"Parent,omitempty"`
  38. Comment string `json:"Comment,omitempty" yaml:"Comment,omitempty"`
  39. Created time.Time `json:"Created,omitempty" yaml:"Created,omitempty"`
  40. Container string `json:"Container,omitempty" yaml:"Container,omitempty"`
  41. ContainerConfig Config `json:"ContainerConfig,omitempty" yaml:"ContainerConfig,omitempty"`
  42. DockerVersion string `json:"DockerVersion,omitempty" yaml:"DockerVersion,omitempty"`
  43. Author string `json:"Author,omitempty" yaml:"Author,omitempty"`
  44. Config *Config `json:"Config,omitempty" yaml:"Config,omitempty"`
  45. Architecture string `json:"Architecture,omitempty" yaml:"Architecture,omitempty"`
  46. Size int64 `json:"Size,omitempty" yaml:"Size,omitempty"`
  47. VirtualSize int64 `json:"VirtualSize,omitempty" yaml:"VirtualSize,omitempty"`
  48. RepoDigests []string `json:"RepoDigests,omitempty" yaml:"RepoDigests,omitempty"`
  49. RootFS *RootFS `json:"RootFS,omitempty" yaml:"RootFS,omitempty"`
  50. }
  51. // ImagePre012 serves the same purpose as the Image type except that it is for
  52. // earlier versions of the Docker API (pre-012 to be specific)
  53. type ImagePre012 struct {
  54. ID string `json:"id"`
  55. Parent string `json:"parent,omitempty"`
  56. Comment string `json:"comment,omitempty"`
  57. Created time.Time `json:"created"`
  58. Container string `json:"container,omitempty"`
  59. ContainerConfig Config `json:"container_config,omitempty"`
  60. DockerVersion string `json:"docker_version,omitempty"`
  61. Author string `json:"author,omitempty"`
  62. Config *Config `json:"config,omitempty"`
  63. Architecture string `json:"architecture,omitempty"`
  64. Size int64 `json:"size,omitempty"`
  65. }
  66. var (
  67. // ErrNoSuchImage is the error returned when the image does not exist.
  68. ErrNoSuchImage = errors.New("no such image")
  69. // ErrMissingRepo is the error returned when the remote repository is
  70. // missing.
  71. ErrMissingRepo = errors.New("missing remote repository e.g. 'github.com/user/repo'")
  72. // ErrMissingOutputStream is the error returned when no output stream
  73. // is provided to some calls, like BuildImage.
  74. ErrMissingOutputStream = errors.New("missing output stream")
  75. // ErrMultipleContexts is the error returned when both a ContextDir and
  76. // InputStream are provided in BuildImageOptions
  77. ErrMultipleContexts = errors.New("image build may not be provided BOTH context dir and input stream")
  78. // ErrMustSpecifyNames is the error rreturned when the Names field on
  79. // ExportImagesOptions is nil or empty
  80. ErrMustSpecifyNames = errors.New("must specify at least one name to export")
  81. )
  82. // ListImagesOptions specify parameters to the ListImages function.
  83. //
  84. // See https://goo.gl/xBe1u3 for more details.
  85. type ListImagesOptions struct {
  86. All bool
  87. Filters map[string][]string
  88. Digests bool
  89. Filter string
  90. }
  91. // ListImages returns the list of available images in the server.
  92. //
  93. // See https://goo.gl/xBe1u3 for more details.
  94. func (c *Client) ListImages(opts ListImagesOptions) ([]APIImages, error) {
  95. path := "/images/json?" + queryString(opts)
  96. resp, err := c.do("GET", path, doOptions{})
  97. if err != nil {
  98. return nil, err
  99. }
  100. defer resp.Body.Close()
  101. var images []APIImages
  102. if err := json.NewDecoder(resp.Body).Decode(&images); err != nil {
  103. return nil, err
  104. }
  105. return images, nil
  106. }
  107. // ImageHistory represent a layer in an image's history returned by the
  108. // ImageHistory call.
  109. type ImageHistory struct {
  110. ID string `json:"Id" yaml:"Id"`
  111. Tags []string `json:"Tags,omitempty" yaml:"Tags,omitempty"`
  112. Created int64 `json:"Created,omitempty" yaml:"Created,omitempty"`
  113. CreatedBy string `json:"CreatedBy,omitempty" yaml:"CreatedBy,omitempty"`
  114. Size int64 `json:"Size,omitempty" yaml:"Size,omitempty"`
  115. }
  116. // ImageHistory returns the history of the image by its name or ID.
  117. //
  118. // See https://goo.gl/8bnTId for more details.
  119. func (c *Client) ImageHistory(name string) ([]ImageHistory, error) {
  120. resp, err := c.do("GET", "/images/"+name+"/history", doOptions{})
  121. if err != nil {
  122. if e, ok := err.(*Error); ok && e.Status == http.StatusNotFound {
  123. return nil, ErrNoSuchImage
  124. }
  125. return nil, err
  126. }
  127. defer resp.Body.Close()
  128. var history []ImageHistory
  129. if err := json.NewDecoder(resp.Body).Decode(&history); err != nil {
  130. return nil, err
  131. }
  132. return history, nil
  133. }
  134. // RemoveImage removes an image by its name or ID.
  135. //
  136. // See https://goo.gl/V3ZWnK for more details.
  137. func (c *Client) RemoveImage(name string) error {
  138. resp, err := c.do("DELETE", "/images/"+name, doOptions{})
  139. if err != nil {
  140. if e, ok := err.(*Error); ok && e.Status == http.StatusNotFound {
  141. return ErrNoSuchImage
  142. }
  143. return err
  144. }
  145. resp.Body.Close()
  146. return nil
  147. }
  148. // RemoveImageOptions present the set of options available for removing an image
  149. // from a registry.
  150. //
  151. // See https://goo.gl/V3ZWnK for more details.
  152. type RemoveImageOptions struct {
  153. Force bool `qs:"force"`
  154. NoPrune bool `qs:"noprune"`
  155. }
  156. // RemoveImageExtended removes an image by its name or ID.
  157. // Extra params can be passed, see RemoveImageOptions
  158. //
  159. // See https://goo.gl/V3ZWnK for more details.
  160. func (c *Client) RemoveImageExtended(name string, opts RemoveImageOptions) error {
  161. uri := fmt.Sprintf("/images/%s?%s", name, queryString(&opts))
  162. resp, err := c.do("DELETE", uri, doOptions{})
  163. if err != nil {
  164. if e, ok := err.(*Error); ok && e.Status == http.StatusNotFound {
  165. return ErrNoSuchImage
  166. }
  167. return err
  168. }
  169. resp.Body.Close()
  170. return nil
  171. }
  172. // InspectImage returns an image by its name or ID.
  173. //
  174. // See https://goo.gl/jHPcg6 for more details.
  175. func (c *Client) InspectImage(name string) (*Image, error) {
  176. resp, err := c.do("GET", "/images/"+name+"/json", doOptions{})
  177. if err != nil {
  178. if e, ok := err.(*Error); ok && e.Status == http.StatusNotFound {
  179. return nil, ErrNoSuchImage
  180. }
  181. return nil, err
  182. }
  183. defer resp.Body.Close()
  184. var image Image
  185. // if the caller elected to skip checking the server's version, assume it's the latest
  186. if c.SkipServerVersionCheck || c.expectedAPIVersion.GreaterThanOrEqualTo(apiVersion112) {
  187. if err := json.NewDecoder(resp.Body).Decode(&image); err != nil {
  188. return nil, err
  189. }
  190. } else {
  191. var imagePre012 ImagePre012
  192. if err := json.NewDecoder(resp.Body).Decode(&imagePre012); err != nil {
  193. return nil, err
  194. }
  195. image.ID = imagePre012.ID
  196. image.Parent = imagePre012.Parent
  197. image.Comment = imagePre012.Comment
  198. image.Created = imagePre012.Created
  199. image.Container = imagePre012.Container
  200. image.ContainerConfig = imagePre012.ContainerConfig
  201. image.DockerVersion = imagePre012.DockerVersion
  202. image.Author = imagePre012.Author
  203. image.Config = imagePre012.Config
  204. image.Architecture = imagePre012.Architecture
  205. image.Size = imagePre012.Size
  206. }
  207. return &image, nil
  208. }
  209. // PushImageOptions represents options to use in the PushImage method.
  210. //
  211. // See https://goo.gl/zPtZaT for more details.
  212. type PushImageOptions struct {
  213. // Name of the image
  214. Name string
  215. // Tag of the image
  216. Tag string
  217. // Registry server to push the image
  218. Registry string
  219. OutputStream io.Writer `qs:"-"`
  220. RawJSONStream bool `qs:"-"`
  221. InactivityTimeout time.Duration `qs:"-"`
  222. }
  223. // PushImage pushes an image to a remote registry, logging progress to w.
  224. //
  225. // An empty instance of AuthConfiguration may be used for unauthenticated
  226. // pushes.
  227. //
  228. // See https://goo.gl/zPtZaT for more details.
  229. func (c *Client) PushImage(opts PushImageOptions, auth AuthConfiguration) error {
  230. if opts.Name == "" {
  231. return ErrNoSuchImage
  232. }
  233. headers, err := headersWithAuth(auth)
  234. if err != nil {
  235. return err
  236. }
  237. name := opts.Name
  238. opts.Name = ""
  239. path := "/images/" + name + "/push?" + queryString(&opts)
  240. return c.stream("POST", path, streamOptions{
  241. setRawTerminal: true,
  242. rawJSONStream: opts.RawJSONStream,
  243. headers: headers,
  244. stdout: opts.OutputStream,
  245. inactivityTimeout: opts.InactivityTimeout,
  246. })
  247. }
  248. // PullImageOptions present the set of options available for pulling an image
  249. // from a registry.
  250. //
  251. // See https://goo.gl/iJkZjD for more details.
  252. type PullImageOptions struct {
  253. Repository string `qs:"fromImage"`
  254. Registry string
  255. Tag string
  256. OutputStream io.Writer `qs:"-"`
  257. RawJSONStream bool `qs:"-"`
  258. InactivityTimeout time.Duration `qs:"-"`
  259. }
  260. // PullImage pulls an image from a remote registry, logging progress to
  261. // opts.OutputStream.
  262. //
  263. // See https://goo.gl/iJkZjD for more details.
  264. func (c *Client) PullImage(opts PullImageOptions, auth AuthConfiguration) error {
  265. if opts.Repository == "" {
  266. return ErrNoSuchImage
  267. }
  268. headers, err := headersWithAuth(auth)
  269. if err != nil {
  270. return err
  271. }
  272. return c.createImage(queryString(&opts), headers, nil, opts.OutputStream, opts.RawJSONStream, opts.InactivityTimeout)
  273. }
  274. func (c *Client) createImage(qs string, headers map[string]string, in io.Reader, w io.Writer, rawJSONStream bool, timeout time.Duration) error {
  275. path := "/images/create?" + qs
  276. return c.stream("POST", path, streamOptions{
  277. setRawTerminal: true,
  278. headers: headers,
  279. in: in,
  280. stdout: w,
  281. rawJSONStream: rawJSONStream,
  282. inactivityTimeout: timeout,
  283. })
  284. }
  285. // LoadImageOptions represents the options for LoadImage Docker API Call
  286. //
  287. // See https://goo.gl/JyClMX for more details.
  288. type LoadImageOptions struct {
  289. InputStream io.Reader
  290. }
  291. // LoadImage imports a tarball docker image
  292. //
  293. // See https://goo.gl/JyClMX for more details.
  294. func (c *Client) LoadImage(opts LoadImageOptions) error {
  295. return c.stream("POST", "/images/load", streamOptions{
  296. setRawTerminal: true,
  297. in: opts.InputStream,
  298. })
  299. }
  300. // ExportImageOptions represent the options for ExportImage Docker API call.
  301. //
  302. // See https://goo.gl/le7vK8 for more details.
  303. type ExportImageOptions struct {
  304. Name string
  305. OutputStream io.Writer
  306. InactivityTimeout time.Duration `qs:"-"`
  307. }
  308. // ExportImage exports an image (as a tar file) into the stream.
  309. //
  310. // See https://goo.gl/le7vK8 for more details.
  311. func (c *Client) ExportImage(opts ExportImageOptions) error {
  312. return c.stream("GET", fmt.Sprintf("/images/%s/get", opts.Name), streamOptions{
  313. setRawTerminal: true,
  314. stdout: opts.OutputStream,
  315. inactivityTimeout: opts.InactivityTimeout,
  316. })
  317. }
  318. // ExportImagesOptions represent the options for ExportImages Docker API call
  319. //
  320. // See https://goo.gl/huC7HA for more details.
  321. type ExportImagesOptions struct {
  322. Names []string
  323. OutputStream io.Writer `qs:"-"`
  324. InactivityTimeout time.Duration `qs:"-"`
  325. }
  326. // ExportImages exports one or more images (as a tar file) into the stream
  327. //
  328. // See https://goo.gl/huC7HA for more details.
  329. func (c *Client) ExportImages(opts ExportImagesOptions) error {
  330. if opts.Names == nil || len(opts.Names) == 0 {
  331. return ErrMustSpecifyNames
  332. }
  333. return c.stream("GET", "/images/get?"+queryString(&opts), streamOptions{
  334. setRawTerminal: true,
  335. stdout: opts.OutputStream,
  336. inactivityTimeout: opts.InactivityTimeout,
  337. })
  338. }
  339. // ImportImageOptions present the set of informations available for importing
  340. // an image from a source file or the stdin.
  341. //
  342. // See https://goo.gl/iJkZjD for more details.
  343. type ImportImageOptions struct {
  344. Repository string `qs:"repo"`
  345. Source string `qs:"fromSrc"`
  346. Tag string `qs:"tag"`
  347. InputStream io.Reader `qs:"-"`
  348. OutputStream io.Writer `qs:"-"`
  349. RawJSONStream bool `qs:"-"`
  350. InactivityTimeout time.Duration `qs:"-"`
  351. }
  352. // ImportImage imports an image from a url, a file or stdin
  353. //
  354. // See https://goo.gl/iJkZjD for more details.
  355. func (c *Client) ImportImage(opts ImportImageOptions) error {
  356. if opts.Repository == "" {
  357. return ErrNoSuchImage
  358. }
  359. if opts.Source != "-" {
  360. opts.InputStream = nil
  361. }
  362. if opts.Source != "-" && !isURL(opts.Source) {
  363. f, err := os.Open(opts.Source)
  364. if err != nil {
  365. return err
  366. }
  367. opts.InputStream = f
  368. opts.Source = "-"
  369. }
  370. return c.createImage(queryString(&opts), nil, opts.InputStream, opts.OutputStream, opts.RawJSONStream, opts.InactivityTimeout)
  371. }
  372. // BuildImageOptions present the set of informations available for building an
  373. // image from a tarfile with a Dockerfile in it.
  374. //
  375. // For more details about the Docker building process, see
  376. // http://goo.gl/tlPXPu.
  377. type BuildImageOptions struct {
  378. Name string `qs:"t"`
  379. Dockerfile string `qs:"dockerfile"`
  380. NoCache bool `qs:"nocache"`
  381. SuppressOutput bool `qs:"q"`
  382. Pull bool `qs:"pull"`
  383. RmTmpContainer bool `qs:"rm"`
  384. ForceRmTmpContainer bool `qs:"forcerm"`
  385. Memory int64 `qs:"memory"`
  386. Memswap int64 `qs:"memswap"`
  387. CPUShares int64 `qs:"cpushares"`
  388. CPUQuota int64 `qs:"cpuquota"`
  389. CPUPeriod int64 `qs:"cpuperiod"`
  390. CPUSetCPUs string `qs:"cpusetcpus"`
  391. InputStream io.Reader `qs:"-"`
  392. OutputStream io.Writer `qs:"-"`
  393. RawJSONStream bool `qs:"-"`
  394. Remote string `qs:"remote"`
  395. Auth AuthConfiguration `qs:"-"` // for older docker X-Registry-Auth header
  396. AuthConfigs AuthConfigurations `qs:"-"` // for newer docker X-Registry-Config header
  397. ContextDir string `qs:"-"`
  398. Ulimits []ULimit `qs:"-"`
  399. BuildArgs []BuildArg `qs:"-"`
  400. InactivityTimeout time.Duration `qs:"-"`
  401. }
  402. // BuildArg represents arguments that can be passed to the image when building
  403. // it from a Dockerfile.
  404. //
  405. // For more details about the Docker building process, see
  406. // http://goo.gl/tlPXPu.
  407. type BuildArg struct {
  408. Name string `json:"Name,omitempty" yaml:"Name,omitempty"`
  409. Value string `json:"Value,omitempty" yaml:"Value,omitempty"`
  410. }
  411. // BuildImage builds an image from a tarball's url or a Dockerfile in the input
  412. // stream.
  413. //
  414. // See https://goo.gl/xySxCe for more details.
  415. func (c *Client) BuildImage(opts BuildImageOptions) error {
  416. if opts.OutputStream == nil {
  417. return ErrMissingOutputStream
  418. }
  419. headers, err := headersWithAuth(opts.Auth, c.versionedAuthConfigs(opts.AuthConfigs))
  420. if err != nil {
  421. return err
  422. }
  423. if opts.Remote != "" && opts.Name == "" {
  424. opts.Name = opts.Remote
  425. }
  426. if opts.InputStream != nil || opts.ContextDir != "" {
  427. headers["Content-Type"] = "application/tar"
  428. } else if opts.Remote == "" {
  429. return ErrMissingRepo
  430. }
  431. if opts.ContextDir != "" {
  432. if opts.InputStream != nil {
  433. return ErrMultipleContexts
  434. }
  435. var err error
  436. if opts.InputStream, err = createTarStream(opts.ContextDir, opts.Dockerfile); err != nil {
  437. return err
  438. }
  439. }
  440. qs := queryString(&opts)
  441. if len(opts.Ulimits) > 0 {
  442. if b, err := json.Marshal(opts.Ulimits); err == nil {
  443. item := url.Values(map[string][]string{})
  444. item.Add("ulimits", string(b))
  445. qs = fmt.Sprintf("%s&%s", qs, item.Encode())
  446. }
  447. }
  448. if len(opts.BuildArgs) > 0 {
  449. v := make(map[string]string)
  450. for _, arg := range opts.BuildArgs {
  451. v[arg.Name] = arg.Value
  452. }
  453. if b, err := json.Marshal(v); err == nil {
  454. item := url.Values(map[string][]string{})
  455. item.Add("buildargs", string(b))
  456. qs = fmt.Sprintf("%s&%s", qs, item.Encode())
  457. }
  458. }
  459. return c.stream("POST", fmt.Sprintf("/build?%s", qs), streamOptions{
  460. setRawTerminal: true,
  461. rawJSONStream: opts.RawJSONStream,
  462. headers: headers,
  463. in: opts.InputStream,
  464. stdout: opts.OutputStream,
  465. inactivityTimeout: opts.InactivityTimeout,
  466. })
  467. }
  468. func (c *Client) versionedAuthConfigs(authConfigs AuthConfigurations) interface{} {
  469. if c.serverAPIVersion == nil {
  470. c.checkAPIVersion()
  471. }
  472. if c.serverAPIVersion != nil && c.serverAPIVersion.GreaterThanOrEqualTo(apiVersion119) {
  473. return AuthConfigurations119(authConfigs.Configs)
  474. }
  475. return authConfigs
  476. }
  477. // TagImageOptions present the set of options to tag an image.
  478. //
  479. // See https://goo.gl/98ZzkU for more details.
  480. type TagImageOptions struct {
  481. Repo string
  482. Tag string
  483. Force bool
  484. }
  485. // TagImage adds a tag to the image identified by the given name.
  486. //
  487. // See https://goo.gl/98ZzkU for more details.
  488. func (c *Client) TagImage(name string, opts TagImageOptions) error {
  489. if name == "" {
  490. return ErrNoSuchImage
  491. }
  492. resp, err := c.do("POST", fmt.Sprintf("/images/"+name+"/tag?%s",
  493. queryString(&opts)), doOptions{})
  494. if err != nil {
  495. return err
  496. }
  497. defer resp.Body.Close()
  498. if resp.StatusCode == http.StatusNotFound {
  499. return ErrNoSuchImage
  500. }
  501. return err
  502. }
  503. func isURL(u string) bool {
  504. p, err := url.Parse(u)
  505. if err != nil {
  506. return false
  507. }
  508. return p.Scheme == "http" || p.Scheme == "https"
  509. }
  510. func headersWithAuth(auths ...interface{}) (map[string]string, error) {
  511. var headers = make(map[string]string)
  512. for _, auth := range auths {
  513. switch auth.(type) {
  514. case AuthConfiguration:
  515. var buf bytes.Buffer
  516. if err := json.NewEncoder(&buf).Encode(auth); err != nil {
  517. return nil, err
  518. }
  519. headers["X-Registry-Auth"] = base64.URLEncoding.EncodeToString(buf.Bytes())
  520. case AuthConfigurations, AuthConfigurations119:
  521. var buf bytes.Buffer
  522. if err := json.NewEncoder(&buf).Encode(auth); err != nil {
  523. return nil, err
  524. }
  525. headers["X-Registry-Config"] = base64.URLEncoding.EncodeToString(buf.Bytes())
  526. }
  527. }
  528. return headers, nil
  529. }
  530. // APIImageSearch reflect the result of a search on the Docker Hub.
  531. //
  532. // See https://goo.gl/AYjyrF for more details.
  533. type APIImageSearch struct {
  534. Description string `json:"description,omitempty" yaml:"description,omitempty"`
  535. IsOfficial bool `json:"is_official,omitempty" yaml:"is_official,omitempty"`
  536. IsAutomated bool `json:"is_automated,omitempty" yaml:"is_automated,omitempty"`
  537. Name string `json:"name,omitempty" yaml:"name,omitempty"`
  538. StarCount int `json:"star_count,omitempty" yaml:"star_count,omitempty"`
  539. }
  540. // SearchImages search the docker hub with a specific given term.
  541. //
  542. // See https://goo.gl/AYjyrF for more details.
  543. func (c *Client) SearchImages(term string) ([]APIImageSearch, error) {
  544. resp, err := c.do("GET", "/images/search?term="+term, doOptions{})
  545. if err != nil {
  546. return nil, err
  547. }
  548. defer resp.Body.Close()
  549. var searchResult []APIImageSearch
  550. if err := json.NewDecoder(resp.Body).Decode(&searchResult); err != nil {
  551. return nil, err
  552. }
  553. return searchResult, nil
  554. }
  555. // SearchImagesEx search the docker hub with a specific given term and authentication.
  556. //
  557. // See https://goo.gl/AYjyrF for more details.
  558. func (c *Client) SearchImagesEx(term string, auth AuthConfiguration) ([]APIImageSearch, error) {
  559. headers, err := headersWithAuth(auth)
  560. if err != nil {
  561. return nil, err
  562. }
  563. resp, err := c.do("GET", "/images/search?term="+term, doOptions{
  564. headers: headers,
  565. })
  566. if err != nil {
  567. return nil, err
  568. }
  569. defer resp.Body.Close()
  570. var searchResult []APIImageSearch
  571. if err := json.NewDecoder(resp.Body).Decode(&searchResult); err != nil {
  572. return nil, err
  573. }
  574. return searchResult, nil
  575. }