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