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